特集 : 作ってみよう,MyガジェットPart4

対象製品: Armadillo-9
先頭 Part 3

(株)アットマークテクノ
荘司靖
SHOJI Yasushi
森島史仁
MORISHIMA Fumito

この文書は技術評論社「Software Design」2005年12月号に掲載されたものです。

最後に,これまで作ってきたシステムを組み合わせて,CD試聴機を完成させる手順を解説します.また後半では,より製品レベルのガジェットに近づけるためのさまざまなテクニックを解説します.

はじめに

画像の描画,ユーザからのインプット(タッチパネル+バーコードリーダ),音楽の再生などそれぞれの機能が実現したので,これらを組み合わせてCD試聴システムを構築します(写真1).


●写真1 

最近の組み込み開発

最近では組み込み機器にも,高機能と開発期間の短縮(Time to market)という相反するものが要求されていまので,まず機能が実現できるのかどうかをはっきりさせるための(proof of concept),プログラミングが重要になっています.機能の実現が可能になった時点で,どこまで作り込むかという問題になります.

組み込み機器だからといって,シェルスクリプトのような安易な方法がすべて悪いというわけではありません.数がそれほど見込めない機器の場合,C やアセンブリでガリガリ書いていては到底要求されているコストに見合わないものになってしまいます.Linuxのような高機能OSを採用することも,1つには部品の再利用を促すこと目ができるからであり,組み込みだからと言ってTCP/IPのスタックから自前で毎回作っていては,作れるものも作れなくなってしまいます.

組み込み機器で一番大事なのは,人間の手を介することなく動き続けることができるという点です.言い替えれば,エラー処理をシステム停止に及ぶような致命的な障害とすることなく,処理ができるかどうかです.

高機能になればなるほど動作するパターンは多く,複雑なものになっていきます.最近のように高機能になった組み込み機器では,完全な検証は難しくなっています.

増え続ける機能により複雑化した組み込み機器ですが,設計の段階で複雑性を減らす努力も必要です.

最近の機器には,多くの人が使い切れないほどの機能やインターフェースが付いていることが多いですが,逆に最近Appleが発表したある機器のリモコンは,ボタン数が従来のリモコンに比べて圧倒的に少ないのを売りにしていました.

組み込み機器の話題から外れますが,Linux のデスクトップ環境であるGnome も,シンプルさを重視したインターフェースを目指して開発が進められています.

CD 試聴システムの作成

さて,CD視聴システムの作成に戻りましょう.機能的に足りないのは,ジャケット画像をサーバから取得する部分と,タッチパネルのイベントからプレーヤを操作する部分です.

作成するプログラム名は,SoundStationと名付けました.

ジャケット画像の取得

画像データをサーバから取得する方法ですが,HTTP プロトコルで取得します.あらかじめサーバとなるコンピュータ上でWebサーバを立ち上げておいてください.

● Curl ライブラリのインストール

HTTP プロトコルを利用するにあたり,Curl(http://curl.haxx.se/)のライブラリを使用します.Curl自体はURLによるファイル転送を行うためのコマンドラインツールを提供しています.HTTPだけではなく,HTTPS,FTP,FTPS,TFTP,etc…といった多彩なプロトコルが利用可能です.

ARM用のバイナリパッケージからクロス開発環境にインストールするという簡単な方法もありますが,デフォルトのCurl ライブラリでは,libssl,libidn,zlib といったライブラリも必要なため,サイズが大きくなります.

そこで,今回はソースファイルから必要最小限の機能を持ったライブラリを作成してインストールします(ARM用バイナリパッケージからインストールする方法はコラムで紹介します).

Curl のサイトからソースファイルをダウンロードして展開し,ARM用のライブラリを作成するようにコンフィギュレーションします.コンフィギュレーションの設定ですが,今回はHTTP アクセスだけなので,ほとんどの機能を無効にしています.コンフィギュレーションに成功したら,ビルドとインストールを実行します(図1).

これで,libcurl がクロス開発環境にセットアップされました.

●図1 Curl ライブラリのインストール


$ wget http://curl.haxx.se/download/curl-7.15.0.tar.gz
...
$ tar zxvf curl-7.15.0.tar.gz
...
$ ls
curl-7.15.0 curl-7.15.0.tar.gz
$ cd curl-7.15.0
$ ./configure --prefix=/usr/arm-linux/ \
--host=arm-linux \
--build=i686-pc-linux-gnu \
--enable-shared=no \
--without-ssl \
--without-zlib \
--without-libidn \
--without-gnutls \
--without-ca-bandle \
--disable-ldap \
--disable-ftp \
--disable-gopher \
--disable-file \
--disable-dict \
--disable-telnet \
--disable-tftp \
--disable-manual \
--disable-ipv6 \
--disable-verbose \
--disable-crypto-auth \
--disable-cookies \
--disable-sspi \
--disable-ares \
CC=arm-linux-gcc
$ make
...
$ su
Password:
# make install
...
# ls /usr/arm-linux/lib/libcurl*
/usr/arm-linux/lib/libcurl.a /usr/arm-linux/lib/libcurl.la
#

ソースコード1 ~サーバからJPEG 画像をダウンロード

リスト1は,Curlライブラリを使用してサーバからJPEG画像をダウンロードする部分のソースコードです.Curlライブラリには,Easyと呼ばれる同期インターフェースとMultiと呼ばれる非同期インターフェースがありますが,今回は簡単に利用できるEasyを使っています.

●リスト1 サーバからJPEG 画像をダウンロードするソースコード(ソースコード


FILE* fp;
CURL* handle;
CURLcode return_code;
char url[1024];
 

/**
 * 取得したデータを書き込むためのファイルを準備
 */
fp = fopen(SAVE_FNAME, "wb");
if(fp == NULL){
    perror("fopen() ");
    return -1;
}

/**
 * ファイルが置かれているURLの文字列を作成(http://[server_name]/[barcode].jpeg)
 **/
fprintf(url, "%s/%s.jpeg", PICTURE_SERVER, barcode);
printf("URL : %s\n", url);

(1)

/**
 * URLと書込みストリームを指定して,JPEGファイルの取得処理を実行
 */
handle = curl_easy_init();
if(handle == NULL){
    fprintf(stderr, "curl_easy_init() failed\n");
    return -1;
}

curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp);

return_code = curl_easy_perform(handle);
if(return_code != CURLE_OK){
    curl_easy_strerror(return_code);
    return -1;
}

curl_easy_cleanup(handle);
(2)

●リスト1-(1)

取得したデータを保存するためのファイルを,書き込みモードでオープンする処理と,ファイルが置いてあるURLの文字列を作成しています.

●リスト1-(2)

curl_easy_init()で,Curlライブラリの初期化関数を呼び出した後,URL の指定と,取得したデータを書込みむストリームの指定をcurl_easy_setopt( )で,URLとデータを書き込むストリームを指定します.次に,curl_easy_perform()を呼び出し,実際のファイル取得処理を行った後,curl_easy_cleanup( )を呼び出して,リソースを開放しています.

このように,Curlライブラリを使用するときは,setopt()で設定を行い,perform()で実際に問い合わせを行うという処理の流れになります.

alsaplayer の操作

SoundStationでは,以下の操作を行えるようにしました.

・再生
・一時停止

・早送り再生(2 倍速)
・巻き戻し再生(2 倍速)
・次の曲へ
・前の曲へ
・ボリュームアップ
・ボリュームダウン

画面イメージを図2に掲載しておきます.

●画面イメージ

ソースコード2 ~ alsaplayer へのイベント通知

リスト2 は,操作イベントが発生したときに,alsaplayerにイベントを通知する部分のソースコードです.

●リスト2 alsaplayer にイベントを通知するソースコード(ソースコード



/***********************************************************************
 * summary : alsaplayer をfork して操作を要求する
 * return : 成功0, 失敗-1
 **********************************************************************/
int send_message_to_player(
    const char* command, /* 実行するコマンド名*/
    const char* parameter /* コマンド別のパラメータ*/
)
{
    pid_t pid;
    int status;
    char buffer[PATH_MAX];

    pid = fork();
    switch(pid){
    case -1:
        perror("fork failed");
        return -1;
    case 0:
        execlp("alsaplayer", "alsaplayer", "--quiet",
            "--session-name", SESSION, "-E",
            command, parameter, NULL);
    }
    while (waitpid(pid, &status, 0) < 0) {
        if (errno != EINTR){
            perror("waitpid failed");
            return -1;
        }
    }

    return 0;
}
(1)

/***********************************************************************
 * summary : 発生したイベントを判別して,プレーヤーを操作する
 * return : 成功0, 失敗-1
 **********************************************************************/
int manage_player(
    int event /* 発生したイベントの種別*/
)
{
    int ret = -1;
    char param[PATH_MAX];
    static double volume = 1.0; /* default */

    switch(event){
    case SS_VOLUME_UP: /* 音量アップ(0.0 ~ 1.0) */
        volume += (volume < 1.0)? 0.1 : 0;
        sprintf(param, "%3.1f", volume);
        ret = send_message_to_player(AP_VOLUME_CMD, param);
        break;

    case SS_VOLUME_DOWN: /* 音量ダウン(0.0 ~ 1.0) */
        volume -= (volume > 0.0)? 0.1 : 0;
        sprintf(param, "%3.1f", volume);
        ret = send_message_to_player(AP_VOLUME_CMD, param);
        break;

    case SS_SKIP_NEXT: /* 次の曲へ*/
        ret = send_message_to_player(AP_SKIP_NEXT_CMD, NULL);
        break;

    case SS_SKIP_PREV: /* 前の曲へ*/
        ret = send_message_to_player(AP_SKIP_PREV_CMD, NULL);
        break;

    case SS_FAST_FORWARD: /* 2倍速再生*/
        ret = send_message_to_player(AP_FAST_FORWARD_CMD, "2.0");
        break;

    case SS_REWIND: /* 2倍速逆再生*/
        ret = send_message_to_player(AP_REWIND_CMD, "-2.0");
        break;

    case SS_PLAY_SOUND: /* 再生*/
        ret = send_message_to_player(AP_PLAY_CMD, NULL);
        break;

    case SS_PAUSE_SOUND: /* 一時停止*/
        ret = send_message_to_player(AP_PAUSE_CMD, NULL);
        break;
    default:
        break;
    }

    return ret;
}
(2)

●リスト2-(1)

send_message_to_player( )では,fork した後,command とparameter を引数に追加して,alsaplayer をexecしています.

commandの中身は,“play”“stop”“pause”などのalsaplayer が受け付ける操作名で,paramter は“speed”などのように,値を指定する必要がある操作の場合に使われます.値を指定する必要がない操作のときはNULLです.

●リスト2-(2)

manage_player( )はタッチパネルで発生したイベントを受け取り,alsaplayerを操作するための関数です.イベント種別ごとにalsaplayerに渡す操作名を設定して,send_message_to_playerを呼び出します.

また,“speed”と“volume”の操作では値を指定する必要があるため,値の計算や指定も行っています.

ビルドと実行

前章との変更点をメインプログラムとMakefileのパッチにしたので,これをAtmark Dist内のプロジェクトディレクトリに当てて,make するとSound Stationの完成です(図3).

イメージファイルをフラッシュメモリに書き込んで実行させてみてください.

●図3 プログラムのビルド


$ wget http://download.atmark-techno.com/misc/softwaredesign/chapter5/soundstation_dist.patch
$ patch -p1 < ./soundstation_final.patch
$ make

プロダクト化する

メニューに追加する

全コンポーネントが動き,SoundStationのプログラムも無事動き,全コンポーネントが動作したので,あとは製品として仕上げていくだけになりました.Atmark Distは各ベンダディレクトリの下にプロダクト(製品)のディレクトリを配置することで,メニューから簡単にイメージを作成してくれるようになっています.

そこで,SoundStationをAtmark Dist内でプロダクト化し,今後のメンテナンスを行いやすくしていきましょう.プロダクト化するのはとても簡単です.ベンダディレクトリの下にディレクトリを配置し,Makefile やデフォルトのコンフィギュレーション情報を配置するだけで,ビルドシステムが自動的にメニューに追加してくれます.

まず最初にArmadillo-9 をそのままSoundStationという名前でコピーします(図4).

●図4 Armadillo-9 をSoundStation という名前でコピー



$ cd atmark-dist/vendors/AtmarkTechno/
$ cp -a Armadillo-9 SoundStation
$ cd ~/atmark-dist
$

さらに,make menuconfigを実行してみます.


$ make menuconfig

「Vendor/Product Selection --->」を選択し「AtmarkTechno Products」のリストの中にSoundStationが存在することを確認してください.

今はArmadillo-9のディレクトリをコピーしただけですので,SoundStationを選択しても,できあがるimage ファイルはArmadillo-9 とまったく同じものになります.

●デバイスノードの追加

ユーザランドのイメージファイル内にデバイスファイルを追加するために,SoundStation/ext2_devtable.txtを編集します.イメージファイルを作成するコマンドgetext2fsは,このファイルを参照してイメージ内にデバイスファイルを作成します.

たとえば,タッチパネルのイベントを読み込むためのデバイスファイル/dev/input/event0を追加するには,ext2_devtable.txtに以下の行を追加します.


/dev/input/event c 660 0 0 13 128   0 1 1

このファイルのフォーマットは,atmark-dist/user/mtd-utils/device_table.txtに記載されています.

自動起動rc

SoundStationを自動的に起動するためのrcスクリプトを追加します.他のrcスクリプトを真似て,リスト3のようにします.

●リスト3 rc スクリプト


#!/bin/sh
. /etc/init.d/functions
PATH=/bin:/sbin:/usr/bin:/usr/sbin
echo "Starting SoundStation:"
soundstation &
check_status

このスクリプトを,SoundStation/etc/init.d にsoundstationとしてファイルを保存します.

次にMakefile を修正して,/etc/rc.d ディレクトリ内にシンボリックリンクが作成されるようにします(リスト4).

●リスト4 Makefile の修正


$(ROMFSINST) -s /etc/init.d/checkroot /etc/rc.d/S05checkroot
$(ROMFSINST) -s /etc/init.d/syslogd /etc/rc.d/S10syslogd
$(ROMFSINST) -s /etc/init.d/klogd /etc/rc.d/S20klogd
$(ROMFSINST) -s /etc/init.d/firewall /etc/rc.d/S30firewall
$(ROMFSINST) -s /etc/init.d/networking /etc/rc.d/S40networking
$(ROMFSINST) -s /etc/init.d/thttpd /etc/rc.d/S50thttpd
$(ROMFSINST) -s /etc/init.d/inetd /etc/rc.d/S60inetd
[追加]
$(ROMFSINST) -s /etc/init.d/soundstation /etc/rc.d/S99soundstation

SoundStation/Makefile としてセーブした後,イメージを作成しなおしてください.作成したイメージをフラッシュメモリに書き込めば完成です.これで電源を入れると目的のプログラムが動作し,組み込みシステムらしくなりました.

より製品に近いガジェットにするために

動作するものはできましたが,いろいろと問題点が残っています.ここでは,組み込みシステムにありがちな以下の3点の問題点に取り組みます.

・IP アドレスの変更など,些細な設定変更を簡単 に行えない
・保守はネットワークから行うしかないが,IP ア ドレスがわからなくなる
・電源を入れてから,利用可能になるまでに時間 がかかる

設定の保存

IP アドレスをDHCP で取得する場合には問題になりませんが,何らかの理由でDHCP が使えない場合には,端末ごとにIPアドレスを設定する必要があります.もちろん,設定ファイルを直接変更し,それぞれのイメージファイルを生成することも可能ですが,たかだかIPアドレスの設定のためにイメージファイルを書き換えなければならないのであれば,運用上問題になります.

組み込み機器であれば,固体固有の情報が必要になるケースが多くあります.しかし,ファイルシステムを書き込み可能にしてしまうと,電源を切る際にサーバやデスクトップのようにシャットダウンの手順を踏み, ファイルシステムをアンマウントする必要が出てしまいます.組み込み機器では,電源が突然切られてもシステムが壊れては いけません.電源を突然切ったら二度と動かなくなるテレビや冷蔵庫なんて欲しくありません.

そこで,flatfsdと呼ばれるツールを使って,これを実現する方法をご紹介します.flatfsdはあるディレクトリにあるファイルをシリアライズして,フラッシュメモリに書き出したり,シリアライズされているデータをフラッシュメモリから読み出してファイルを復元してくれます.

● flatfsd の利用

データを保持する領域は/dev/flash/configを使います.ここにはオンボードフラッシュメモリの領域が割り当てられています.

データを書き出す先は/etc/config を使います./etc以下はromfsになっているため,このディレクトリにはramfsをmountする必要があります.

また,何らかの理由によりフラッシュメモリのconfig 領域が壊れてしまった場合には,/etc/default にあるファイルをコピーしますので,このディレクトリにはデフォルト状態に必要なファイルを入れておく必要があります.

さて,dist上でこれらの作業を行いましょう.まずは,アプリケーションのメニューを表示してflatfsdを選択します(図5).

●図5 メニューからflatfsd を選択


-> Filesystem Applications
   -> [*] flatfsd

次に,ユーザランドイメージ内に/etc/config/etc/default ディレクトリを作成するため,Makefile のROMFS_DIRS を修正します(リスト5).

●リスト5 Makefile を修正(SoundStation/etc/Makefile)


ROMFS_DIRS =    root bin lib mnt tmp proc \
        etc etc/rc.d etc/dhcpc etc/terminfo etc/network \
        etc/network/if-down.d etc/network/if-post-down.d \
        etc/network/if-up.d etc/network/if-pre-up.d \
        dev dev/flash \
        usr usr/lib \
        var var/log var/run \
        home home/ftp home/ftp/etc home/ftp/bin \
        home/ftp/lib home/ftp/pub \
        home/www-data home/www-data/cgi-bin \
        home/guest \
        [追加]
        etc/config \
        etc/default

プロジェクト内にetc/defualt ディレクトリを作成して,保存するファイルを追加します(図6).

●図6 default ディレクトリに保存するファイルを追加


$ mkdir etc/default
$ cp etc/network/interfaces etc/default

今回はネットワークの設定ファイルを保存対象とします.

ネットワーク設定の起動スクリプトを修正して,/etc/config/interfacesファイルを参照するように書き換えます(リスト6).

●リスト6 ネットワーク設定の起動スクリプトを修正(SoundStation/etc/init.d/networking)


#!/bin/sh

. /etc/init.d/functions

PATH=/bin:/sbin:/usr/bin:/usr/sbin

echo -n "Configuring network interfaces: "
[変更箇所]
ifup -a -i /etc/config/interfaces

check_status

次に,flatfsd 用の起動スクリプトを作成し,SoundStation/etc/init.d にflatfsd として追加します(リスト7).

●リスト7 flatfsd 用の起動スクリプトを作成(SoundStation/etc/init.d/flatfsd)


#!/bin/sh

. /etc/init.d/functions

PATH=/bin:/sbin:/usr/bin:/usr/sbin

echo "Populating /etc/config: "
flatfsd -r

echo "Starting flatfsd: "
flatfsd &
check_status

flatfsd -rで/dev/flash/configの内容を/etc/configに復旧した後,flatfsdプロセスを常駐させています.

また,前の説明と同じように,Makefile に/etc/rc.d/S30flatfsdへのシンボリックリンクを作成する記述を追加します.

重要な点は,flatfsdがnetworkingより先に実行されるようにすることです.これは,flatfsd -rが実行されるまで,/etc/config/interfacesが作成されず,networking スクリプトが設定ファイルを見つけることができないからです.

最後に, 起動スクリプトの修正です./etc/configにramfsをmountする処理を追加します(リスト8).

●リスト8 /etc/config にramfs をmount する処理を追加(SoundStation/etc/init.d/rc)


echo >> /etc/issue
echo >> /etc/issue.net

[追加2行]
echo "Mounting /etc/config:"
mount -t ramfs none /etc/config

echo "Running local start scripts."

作業を終えたらユーザランドのイメージファイルをビルドして,netflashでイメージを更新してください.

さっそくArmadillo-9でファイルの編集内容が保存されるか試してみます,まず,/etc/config/interfacesを編集してIPアドレスを192.168.0.40に変更します(リスト9).

●リスト9 /etc/config/interfaces を編集


# /etc/network/interfaces -- configuration file
for ifup(8), ifdown(8)
auto lo eth0
iface lo inet loopback
[変更箇所]
    iface eth0 inet static
    address 192.168.0.40
    netmask 255.255.255.0
    gateway 192.168.0.1

flatfsdはUSR1シグナルを受信すると設定を保存するので, プロセスにシグナルを投げて/etc/config ディレクトリ以下をフラッシュメモリに保存します.その後Armadillo-9を再起動し,起動後にIPアドレスが変更されたことを確認します(図7).

●図7 IPアドレスが変更されたことを確認


# killall -USR1 flatfsd
flatfsd: Wrote 280 bytes to flash in 4 seconds
# reboot
...
(再起動)
...
armadillo9 login: root
Password:
# ifconfig
eth0    Link encap:Ethernet HWaddr 01:23:45:67:89:ab
    inet addr:192.168.0.40 Bcast:192.168.10.255 Mask:255.255.255.0
...
#

IP アドレスが変わっているのがわかります.もちろん,/etc/config/interfacesファイルは変更されたままです.

/etc/defaultディレクトリの内容で/etc/configの内容を初期化したい場合は,-w オプションを付け てflatfsdコマンドを実行します(図8).

●図8 /etc/default ディレクトリの内容で/etc/config の内容を初期化


# flatfsd -w
flatfsd: Nonexistent or bad flatfs (119), creating new one...
flatfsd: Wrote 212 bytes to flash in 4 seconds
flatfsd: Created 2 configuration files (145 bytes)
#

他にも設定を保持したいファイルがあれば,同様の手順で行うことができます. ただし,/dev/flash/configに割り当てられているフラッシュメモリのサイズは64K バイトなので,これを超えないように注意する必要があります.

MTDのマップを編集して割り当てられているフラッシュメモリのサイズを変更するには,linux-2.6.x/drivers/mtd/map/armadillo9.cを編集する必要があります.

ネットワークからの保守

ネットワークからしかログインできないのはやむを得ないとしても,IP アドレスがわからなくなると保守もできなくなるのでは,実用的ではありません.この問題と解決するために,機器のネットワーク設定を調べるdiscover というツールを使用します.

discoverツールは,ブロードキャストパケットを使用して機器のネットワーク設定を調べます.機器側には,discoverdというプロセスを常駐させる必要があります.このツールを使えば,Ethernetのセグメント内(ルータを挟まない)の機器が検索可能です.

●機器側にdiscoverd を導入

Armadillo-9に機器側のプログラムdiscoverdを導入します.このツールは,もともとArmadillo-J という製品向けに作られているため,パッチを当てて少々プログラムを変更する必要があります(図9).

●図9 discoverd にパッチを当てる


$ wget http://download.atmark-techno.com/misc/softwaredesign/chapter5/discover_a9.patch
$ patch -p1 < ./discoverd_a9.patch
$

discoverdではネットワークの設定の変更も行えますが,その保存に1つ前に説明したflatfsdを使用しているので,flatfsdも動作するようにしておく必要があります(前述した手順を行っていれば大丈夫です).

アプリケーションのメニューを表示してdiscoverdを選択します(図10).

●図10 メニューからdiscoverd を選択


-> Network Applications
   -> [*] discoverd

次に起動スクリプトを作成して,起動時にdiscoverdが実行されるようにします(リスト10).

●リスト10 起動スクリプトを作成(SoundStation/etc/rc.d/S90discoverd)


#!/bin/sh

. /etc/init.d/functions

PATH=/bin:/sbin:/usr/bin:/usr/sbin

echo "Starting discoverd: "
discoverd &
check_status

ここでも,前の説明と同様Makefileに/etc/rc.d/S40discoverdへのシンボリックリンクを作成する記述を追加します.シンボリックリンク名を,flatfsdより後に起動されるように付けている点に注意してください.

また,discoverdがネットワーク設定を行うので,今までのネットワーク設定のための起動スクリプトが起動時に実行されないようにコメントアウトしたほうが無難です.

今までどおりにイメージを作成してフラッシュメモリを書き換えます.

●開発用PC にdiscover ツールを導入

次に開発用PCにdiscoverツールをインストールします.http://download.atmark-techno.com/misc/softwaredesign/chapter5/iptools/からdiscoverをダウンロードして適当な場所に保存してください.もしうまく動かないときはソースからコンパイルすると良いでしょう.

●実行

では実際に動作させてみます.Armadillo-9 を起動した後,ダウンロードしたdiscover ツールを開発用PCで実行します(図11).

●図11 discover ツールを開発用PC で実行


$ ./discover
sending find packet
packet received
01:23:45:67:89:ab|DHCP no |IP 192.168.0.40 |MASK 255.255.255.0 |GW 0.0.0.0
$

応答の先頭に表示されているのがMACアドレスです.ネットワーク上にdiscoverdが動作している機器が複数ある場合,その分のネットワーク情報が表示されるので,MACアドレスで固体を識別します.

また,ipconfigというツールを使うと,機器のネットワーク設定を変更することもできます.ここでは,IPアドレスを192.168.10.50/24に,デフォルトゲートウェイに192.168.0.1 を設定してみます(図12).

これで,ネットワークからの保守が可能になりました.

●図12 ipconfig でネットワーク設定を変更


$ ./ipconfig 01:1:23:45:67:89:ab 192.168.0.50 255.255.255.0 192.168.0.1
sending find packet
packet received
01:23:45:67:89:ab|DHCP no |IP 192.168.0.50 |MASK 255.255.255.0 |GW 192.168.0.1
$

起動時間の短縮

ユーザにとって機器というのは,電源を入れるとすぐに使えるものだという認識があります.OSのブート時間なんてものは考慮されないので,電源を入れてからできる限り早く使用できる状態にする必要があります.

起動時間の短縮のためにできることは,簡単にできて効果が高いものから,時間がかかるくせに効果が低いものまでさまざまですが,ここでは以下の3点を実行してみます.

(1)必要のないデバイスドライバを組みこまない
(2)できるだけ小さいイメージにしてフラッシュROMに格納する
(3)起動スクリプト内の不必要な処理をやめ,不要なプロセスを起動しない

(1)必要のないデバイスドライバを外す

カーネルのコンフィギュレーションを行い,必要のないドライバを外します(図13).カーネルのサイズが小さくなり,また初期化処理が呼ばれないことで起動時間が短くなります.

●図13 必要のないドライバを外す


General setup --->
   [ ] Stsctl support
   [*] Configure standard kernel features (for small systems) --->
      [ ] Load all symbols for debugging/kksymoops
      [ ] BUG() support
      [ ] Enable full-sized data structures for core
      [ ] Enable futex support
      [ ] Optimize for size
      [ ] Use full shmem filesystem
   Loadable module support --->
      [ ] Enable loadable module support
   System Type --->
      [ ] Armadillo-9 PC/104 bus (ISA) support
   Device Drivers --->
      ATA/ATAPI/MFM/RLL support --->
         < > ATA/ATAPI/MFM/RLL support
      SCSI device support --->
         [ ] legacy /proc/scsi/ suppor
         < > SCSI disk support
   Networking support --->
      Wireless LAN (non-hamradio) --->
         [ ] Wireless LAN drivers (non-hamradio) & Wireless Extensions
   Input device support --->
      < > Mouse interface
      < > Joystick interface
      [ ] Keyboards --->
      [ ] Mouse --->
      [ ] Joystick --->
      Hardware I/O ports --->
         < > Serial I/O support
   Character devices --->
      [ ] Virtual terminal
      < > EP93xx GPIO support
   I2C support --->
      < > I2C device interface
      Other I2C Chip support --->
         < > Armadillo-9 Real Time Clock
   USB support --->
      [ ] USB device filesystem
      USB Serial Converter support --->
         < > USB Serial Converter support
File system --->
   [ ] Ext3 journalling file system support
      CD-ROM/DVD Filesystems --->
      [ ] ISO 9660 CDROM file system support
   DOS/FAT/NT Filesystems --->
      [ ] MSDOS fs support
      [ ] VFAT (Windows-95) fs support
   Pseudo filesystems --->
      [ ] sysfs file system support
   Network filesystems --->
      [ ] NFS file system support
      [ ] SMB file system support (to mount
          Windows shares etc.)

(2)できるだけ小さいイメージにしてフラッシュメモリに格納する

起動時に展開する処理が少なくなるために,起動が早くなります.Armadillo-9 では,フラッシュメモリのうちカーネル用に約1.44M バイト,ユーザランド用に約6.44M バイトが割り当てられていますが,本当はそれぞれ非圧縮でこのサイズに収まると理想的です.

不要なドライバを外すことでカーネルを小さくしたので,ここでは必要のないアプリケーションを外してユーザランドイメージを小さくします(図14).

●図14 不要なアプリケーションを外す


-> Core Applications
   -> [ ] hwclock
-> Filesystem Applications
   -> [ ] e2fsck
   -> [ ] mks2fs
   -> [ ] fsck
-> Network Applications
   -> [ ] ftpd
   -> [ ] iptables
   -> [ ] msntp
   -> [ ] thttpd
-> Miscellaneous Applications
   -> [ ] zmodem utils
-> BusyBox
   -> [ ] dpkg
   -> [ ] dpkg: deb
   -> [ ] fdisk
   -> [ ] fsck_minix
   -> [ ] hdparm
   -> [ ] insmod
   -> [ ] insmod: lsmod
   -> [ ] insmod: modprobe
   -> [ ] insmod: rmmod
   -> [ ] insmod: 2.1 ? 2.4 kernel modules
   -> [ ] insmod: Model version checks
   -> [ ] mount: support NFS mounts
   -> [ ] tftp

まだまだbusybox 内に必要のないアプリケーションがありますが,それほどサイズを小さくする効果はないので,この辺にしておきます.

(3)起動スクリプト内の不必要な処理をやめる

必要のない処理をすべて削除して,必要なプログラムだけを起動するようにした新しい起動スクリプトを作成しました.ずいぶんとシンプルです(リスト11).

●リスト11 起動スクリプトを作成(SoundStation/etc/init.d/rc)


#!/bin/sh

PATH=/bin:/sbin:/usr/bin:/usr/sbin
TZ=JST-9

mount -t proc proc /proc
mount -t ramfs none /etc/config

flatfsd -r
flatfsd &
inetd
discoverd &
soundstation &

ビルドして出来上がったカーネルイメージ,ユーザランドイメージのサイズが,デフォルトのイメージより小さくなっています.

カーネル/ユーザランド領域ともにフラッシュメモリを更新し,起動時間を計測してみます.実際に計測した結果,今まで20秒以上かかっていた起動時間が5秒程度まで短縮しました.

これ以上短くする場合は,initプログラムを書き換えたり,デバイスドライバやブートローダを変更するといった手段が残されています.また,どうしても起動時間がかかってしまう場合は,起動の進捗を表示するなどして,利用者のストレスを軽減する策を考えることも必要となります.

まとめ

これでガジェットが完成しました.駆け足の説明になってしまいましたが,組み込み機器の開発の様子がわかってもらえたと思います.

いくつかの周辺機器を必要としましたが,タッチパネルやバーコードリーダが準備できない場合でも,タッチパネルの代わりにジョイスティックを使ったり,バーコードリーダの代わりにシリアルコンソールからCDのタイトルを入力するといったように,少々変更することでシステム構築を体験できるかと思います.

今回の説明では,曲名を表示する機能を盛り込むとこまでいけませんでしたが,グラフィックライブラリを使用すれば割と簡単に実現できると思います.この機能の追加は,読者のみなさんへの宿題とさせていただきます.ぜひオリジナルのガジェット作りに挑戦してみてください.

コラム:バイナリーパッケージからクロス開発用ライブラリをインストールする方法

クロス開発環境にライブラリを導入する方法ですが、もちろんソースファイルからコンパイルを行っても良いのですが、ARM用のバイナリパッケージをダウンロードしてクロス開発環境に追加する方法がより簡単です。筆者の開発環境がDebianなので、Debianでの方法を記載しますが他の環境でも特に難しい事はないと思います。

まず、Debianのパッケージサイト(http://www.debian.org/distrib/packages)で必要なライブラリのバイナリ・パッケージを検索して、目的のパッケージのページへ移動します。ページ内に各CPUアーキテクチャが表になっているので、ターゲットのアーキテクチャ用のパッケージをダウンロードします。

ダウンロードに成功したらdpkg-cross という、パッケージをクロス開発用に変換するコマンドを使用してクロス開発用のパッケージを作成します。作成されたパッケージのファイル名にはcross という文字が入るので、容易に判別できると思います。

最後に作成したパッケージをインストールします。ここではlibssl0.9.7 を例に説明します。

●作成したパッケージをインストール

$ wget http://ftp.jp.debian.org/debian/pool/main/o/openssl/libssl0.9.7_0.9.7e-3_arm.deb
...
$ ls
libssl0.9.7_0.9.7e-3_arm.deb
$ dpkg-cross -b -aarm libssl0.9.7_0.9.7e-3_arm.deb
Building libssl0.9.7-arm-cross_0.9.7e-3_all.deb
$ ls
libssl0.9.7-arm-cross_0.9.7e-3_all.deb  libssl0.9.7_0.9.7e-3_arm.deb
$ su
Password:
# dpkg -i libssl0.9.7-arm-cross_0.9.7e-3_all.deb
Selecting previously deselected package libssl0.9.7-arm-cross.
(Reading database ... 13060 files and directories currently installed.)
Unpacking libssl0.9.7-arm-cross (from libssl0.9.7-arm-cross_0.9.7e-3_all.deb) ...
Setting up libssl0.9.7-arm-cross (0.9.7e-3) ...
#

通常はこれでインストールでますが、ライブラリの中にはpkg-configパッケージを必要とするものがあり、この場合は依存関係が解決できずにインストールに失敗します。

pkg-config は、ライブラリやアプリケーションをコンパイルするときに必要とされるコンパイルオプションを出力するための補助的なツールです。パッケージと一緒にインストールされる .pc ファイルを参照して、必要なオプションの出力を行っています。

このため開発PC用のpkg-configをインストールして、ARM用クロスパッケージの.pc ファイルが置かれる、/usr/arm-linux/lib/pkgconfigをPKG_CONFIG_PATH環境変数に指定すれば、クロス環境向けにpkg-configが使えるようになり、クロス用をインストール必要はありません。ダミーのクロス用pkg-configパッケージをインストールして、この依存関係さえ解決すれば十分です。以下に、ダミーパッケージをインストールする手順を記載します。

●ダミーパッケージをインストール

# apt-get install equivs
# apt-get install pkg-config
# exit
$ wget http://download.atmark-techno.com/misc/softwaredesign/chapter6/mkXdummy
$ chmod 755 mkXdummy
$ ./mkXdummy pkg-config
...
$ ls pkg-config*
pkg-config-arm-cross_1.0_all.deb
# su -
Password:
# dpkg -i pkg-config-arm-cross_1.0_all.deb

先頭 Part 3

Creative Commons License
この作品は、クリエイティブ・コモンズ・ライセンスの下でライセンスされています。