exStickGEでHTTPサーバを建ててLチカしてみた

技術紹介

前回はexStickGE上のMicroBlazeで動作するLinuxにEthernetを追加しました.
ネットワークにつながったので今回はHTTPサーバを建ててみたいと思います.
ついでにLEDのLチカを追加します.(ついでと言う割には作業量は結構増えます)

ビルド

HTTPサーバは軽量なlighttpdを使用します.
~/Project以下にserverprjディレクトリを作成し主にその中で作業する予定です.
MicroBlazeのクロスコンパイルはこのディレクトリ以下のソフトウェアを使用します.

/tools/Xilinx/Vitis/2020.1/gnu/microblaze/linux_toolchain/lin64_le/microblazeel-v11.0-bs-cmp-re-mh-div-xilinx-linux

サーバのビルドの下準備

lighttpdをビルドするのに必要な以下のライブラリをビルドしてインストールします.

  • zlibc
  • pcre
  • fastcgi (Lチカするときに使用する)
zlibc
# zlibc
cd ~/Project/serverprj
wget http://www.zlib.net/zlib-1.2.11.tar.gz
tar -xvf zlib-1.2.11.tar.gz 
cd zlib-1.2.11/
# コンパイラを指定してconfigureを叩く
# 追加でインストールディレクトリも指定しておく
CC=microblazeel-xilinx-linux-gnu-gcc ./configure --prefix=/tools/Xilinx/Vitis/2020.1/gnu/microblaze/linux_toolchain/lin64_le/microblazeel-v11.0-bs-cmp-re-mh-div-xilinx-linux/usr
make
sudo make install
pcre
# pcre
cd ~/Project/serverprj
wget https://ftp.pcre.org/pub/pcre/pcre-8.44.zip
unzip pcre-8.44.zip
cd pcre-8.44
mkdir build
# zlibc同様コンパイラとインストールディレクトリを指定する
./configure --host=microblazeel-xilinx-linux-gnu --prefix=/home/dev/Project/serverprj/pcre-8.44/build
make
make install
fastcgi
cd ~/Project/serverprj
wget https://github.com/FastCGI-Archives/FastCGI.com/raw/master/original_snapshot/fcgi-2.4.1-SNAP-0910052249.tar.gz
tar -xvf fcgi-2.4.1-SNAP-0910052249.tar.gz fcgi-2.4.1-SNAP-0910052249/
cd fcgi-2.4.1-SNAP-0910052249/
# config.subで引数のhostに応じたコンパイラ名を
# 出してくれるらしいがMicroBlazeは対応していないので誤魔化す
cat << EOF > config.sub
echo "microblazeel-xilinx-linux-gnu"
EOF

mkdir dest
./configure --host=microblazeel-xilinx-linux-gnu --prefix=/home/dev/Project/serverprj/fcgi-2.4.1-SNAP-0910052249/dest
make
make install
sudo cp -r dest/* /tools/Xilinx/Vitis/2020.1/gnu/microblaze/linux_toolchain/lin64_le/microblazeel-v11.0-bs-cmp-re-mh-div-xilinx-linux/usr/

lighttpdのビルド

最低限のライブラリをビルドしたのでlighttpdをビルドします.

cd ~/Project/serverprj
wget https://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.59.tar.gz
tar -xvf lighttpd-1.4.59.tar.gz
cd lighttpd-1.4.59
mkdir dest
PCRECONFIG=/home/dev/Project/serverprj/pcre-8.44/build/bin/pcre-config PCRE_LIB=/home/dev/Project/serverprj/pcre-8.44/build/lib/libpcre.a ./configure --host=microblazeel-xilinx-linux-gnu --disable-ipv6 --prefix=/home/dev/Project/serverprj/lighttpd-1.4.59/dest
make
make install
コンフィグファイルの生成

lighttpdのサンプルコンフィグファイルがdoc/config以下に保存されているので
serverprjディレクトリにコピーして事前に編集しておきます.

cp -r ~/Project/serverprj/lighttpd-1.4.59/doc/config ~/Project/serverprj/

libhttpd.confを編集し93行目をコメントアウト

#server.use-ipv6 = "enable"

modules.confを編集し146行目をアンコメント

include "conf.d/fastcgi.conf"

conf.d/fastcgi.confを編集し8行目以下を編集

server.modules += ( "mod_fastcgi" )
fastcgi.server = (
    ".fcgi" => ((
        "socket" => "/tmp/gpioctl.socket",
    ))
)

Lチカプロジェクトの生成

cd ~/Project/serverprj
mkdir lchika
cd lchika

lchikaディレクトリ内に”lchika.c”として以下のファイルを作成します.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <fcgi_config.h>
#include <fcgi_stdio.h>

int list[] = {509, 510, 511};

int init_gpio()
{
	int fd, i;
	char s[64];

	if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0)
	{
		printf("export open error\n");
		return -1;
	}

	for (i = 0; i < sizeof(list) / sizeof(list[0]); i++)
	{
		sprintf(s, "%d", list[i]);
		write(fd, s, strlen(s));
	}
	close(fd);

	for (i = 0; i < sizeof(list) / sizeof(list[0]); i++)
	{
		sprintf(s, "/sys/class/gpio/gpio%d/direction", list[i]);
		if ((fd = open(s, O_WRONLY)) < 0)
		{
			printf("direction open error\n");
			return -1;
		}
		write(fd, "out", 4);
		close(fd);
	}
	return 0;
}

int finalize_gpio()
{
	int fd, i;
	char s[64];

	if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0)
	{
		printf("export open error\n");
		return -1;
	}

	for (i = 0; i < sizeof(list) / sizeof(list[0]); i++)
	{
		sprintf(s, "%d", list[i]);
		write(fd, s, strlen(s));
	}
	close(fd);
}

void set_gpio(int gpio, int val)
{
	int fd, i;
	char s[64];

	sprintf(s, "/sys/class/gpio/gpio%d/value", gpio);
	if ((fd = open(s, O_WRONLY)) < 0)
	{
		printf("value open error\n");
		return;
	}
	sprintf(s, "%d", val);
	write(fd, s, strlen(s));
	close(fd);
}

int main()
{
	char *ptr, *str = NULL;
	int len = 0, frn;
	int ope_led, ope_val;

	if (init_gpio() < 0)
	{
		return -1;
	}
	while (FCGI_Accept() >= 0)
	{

		FCGI_printf("Content-type: text/plain\r\n"
					"\r\n"
					"Set GPIO LED!\n");

		if ((ptr = getenv("QUERY_STRING")) != NULL && (len = strlen(ptr)) > 0)
		{
			str = strdup(ptr);
		}
		if (str)
		{
			ope_led = ope_val = -1;
			char *head, *eq_p;
			head = strtok(str, "&");
			while (head)
			{
				eq_p = strchr(head, '=');
				if (eq_p)
				{
					*eq_p = 0;
					if (strcmp(head, "led") == 0)
					{
						if (sscanf(eq_p + 1, "%d", &ope_led) == 0)
						{
							ope_led = -1;
							FCGI_printf("LED can't convert\n");
						};
					}
					else if (strcmp(head, "val") == 0)
					{
						if (sscanf(eq_p + 1, "%d", &ope_val) == 0)
						{
							ope_val = -1;
							FCGI_printf("Value can't convert\n");
						};
					}
					*eq_p = '=';
				}
				head = strtok(NULL, "&");
			}
			FCGI_printf("LED %d VAL %d\n", ope_led, ope_val);
			FCGI_printf("\n");
			free(str);
			if (0 <= ope_led && ope_led <= 2 && (ope_val == 0 || ope_val == 1))
			{
				set_gpio(list[ope_led], ope_val);
			}
		}
	}
	finalize_gpio();

	return 0;
}

コンパイルします.

microblazeel-xilinx-linux-gnu-gcc -o gpioctl.fcgi lchika.c -lfcgi

実際に動かしてみる

ここまでで必要なライブラリ及びソフトウェアが揃ったので実際に動かしていきます.
シリアル通信モジュールを接続し,前回同様にJTAGで動かします.

cd ~/Project/linuxprj/sw
petalinux-boot --jtag --fpga
petalinux-boot --jtag --kernel

ユーザ名及びパスワードはrootでログインします.

インストール

ここからは地道にビルドしたソフトウェアをコピーしてきます.

#開発用サーバからscpでコピーするためのユーザ情報変数
R_USER=dev
R_IP=192.168.0.10

scp -r ${R_USER}@${R_IP}:/home/dev/Project/serverprj/lighttpd-1.4.59/dest/* /usr/
scp -r ${R_USER}@${R_IP}:/home/dev/Project/serverprj/pcre-8.44/build/lib/libpcre.so* /usr/lib
scp -r ${R_USER}@${R_IP}:/home/dev/Project/serverprj/fcgi-2.4.1-SNAP-0910052249/dest/* /usr/

mkdir /etc/lighttpd
scp -r ${R_USER}@${R_IP}:/home/dev/Project/serverprj/config/* /etc/lighttpd/


mkdir /srv

groupadd lighttpd
useradd -g lighttpd -d /srv/www -s /sbin/nologin lighttpd

mkdir /var/log/lighttpd

chown lighttpd:lighttpd /var/log/lighttpd

mkdir /srv/www/htdocs

scp -r ${R_USER}@${R_IP}:/home/dev/Project/serverprj/lchika/gpioctl.fcgi /srv/www/htdocs

cat << EOF > /srv/www/htdocs/index.html
<html>
        <head>
                <title>Linux on Microblaze</title>
        </head>
        <body>
                <h1>Hello World!</h1>
        </body>
</html>
EOF

chown -R lighttpd:lighttpd /srv/www/htdocs


cgi-fcgi -connect /tmp/gpioctl.socket /srv/www/htdocs/gpioctl.fcgi
chmod a+w /tmp/gpioctl.socket

lighttpd -f /etc/lighttpd/lighttpd.conf -m /usr/lib

アクセス

ipコマンドでIPアドレスを調べます.今回は192.168.0.215でした.

root@sw:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0a:35:00:22:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.215/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@sw:~#

http://192.168.0.215/にアクセスしてみましょう.

次はLEDを操作します.
http://192.168.0.215/gpioctl.fcgiがアドレスでパラメータを用いて制御します.
ledが0~2で上の図の509~511に対応します.
valは0か1で0=消灯,1=点灯に対応します.
例えば以下のURLであればシルクでLED4の緑色が点灯します.
http://192.168.0.215/gpioctl.fcgi?led=1&val=1

全部点灯させてみました.
http://192.168.0.215/gpioctl.fcgi?led=0&val=1
http://192.168.0.215/gpioctl.fcgi?led=2&val=1

まとめ

Ubuntu上でMicroblaze用のソフトウェアをコンパイルし実機上で動作を確認できました.

現状はシンプルに起動したあとソフトウェアを追加する形をとっています.
実際に運用する場合にはすべてまとめた状態にするべきですが,
リセットすれば初期化されるのでこれはこれで便利だと思っています.

HTTPによる制御が可能になったのでブラウザ経由で
FPGAがかんたんに操作できます.
是非試してみてください.

コメント

  1. […] Sierra Wireless社のLegatoフレームワークにもlighttpdを使用したサンプルアプリケーションが存在します.しかし今回はWP7605を通常のLinuxマシンのように使用する前提で別途lighttpdをビルドしサーバとして運用することにします.以前MicroBlazeで使用したのを参考にビルドしていきます. […]

タイトルとURLをコピーしました