mbed/LPCXpressoで動作するファイルサーバの安定版ができたので公開します。
MbedFileServer
http://mbed.org/users/nyatla/code/MbedFileServer/
このプログラムは、SDカードとmbedLocalFileSystemにあるファイルを公開するシンプルなWebサーバです。 libMiMicライブラリを使用したHTTPDのデモプログラムです。
アプリケーションの仕様や導入方法はmbedのwikiに書いてあるので、コアライブラリのMiMicSDKのお話を幾つか。
MiMicSDK
MiMicSDKはLPCXpresso/mbedをメインに、マイコンにマイクロWebサービスを実装する為のライブラリです。mbedにはlibMiMicの名前で登録されています。
http://mbed.org/users/nyatla/code/libMiMic/
TCP/IPスタック
MiMicSDKのTCP/IPスタックは、mbed標準のものではなく自前のMiMicIPスタックを使っています。MiMicIPはRTTが少ない事が特徴の常時接続タイプのマルチスレッドTCP/IPスタックです。uIPを基礎に、ACK送信タイミング、再送制御、タスクスイッチタイミングなどを魔改造したライブラリです。有線ならば概ね10ms以下の遅延/合計8Mbps程度の通信が可能で、独自のブロッキングソケットAPIを持ちます。
HTTPD
MiMicSDKのHTTPDは、mbed標準のものではなく、自前のMiMicHttpdを使っています。MiMicHttpdは、HTTP/1.1,持続性接続,マルチセッション, chunkedに対応しています。また、HTTP構文パーサが逐次解析/一括解析の両方に対応しているので、長大なHTTPリクエストを省メモリで解析することが出来ます。
HTTPDの実装は、クラスのコールバックハンドラを実装する形です。コールバックハンドラにはHTTPコネクションが引き渡され、アプリケーションはそれを使用してHTTPデータの送受信を実行します。コールバックハンドラはマルチスレッドで実行されているので、メモリが許す限り、複数の接続を同時に処理することが出来ます。
HTTPDは必要に応じて排他的に接続を処理することも出来ます。例えばMCUのリソースにアクセスする場合にロックをかけることが出来ます。
以下のコードは実際のhttpdの実装です。30行程度で実用的なWebサーバを構築することが出来ます。
#include "mimic.h" class MiMicRemoteMcu:public MiMic::Httpd { private: ModUrl modurl; //basic URL parser public: MiMicRemoteMcu():Httpd(80) { } virtual void onRequest(HttpdConnection& i_connection) { char url[32]; int method; //call ModUrl module. if(this->modurl.execute(i_connection,url,32,&method)){ //send 200 OK and requested URL i_connection.sendHeader(200,"text/html",NULL); i_connection.sendBodyF("Your Request path is %s.",url); return; } return; } }; int main() { NetConfig cfg; //create network configulation Net net(cfg); //create a net instance. MiMicRemoteMcu httpd; //create a httpd instance. httpd.loop(); //start httpd loop. return 0; }
HTTPD-modules
MiMicHttpdにはモジュールを組み込むことで機能を拡張することが出来ます。モジュールは、URLのパスのプレフィクスをテストして、自分宛のリクエストを処理します。モジュールの追加・取り外しは数行の修正で可能です。現在はファイルシステムのマウントモジュール、オンチップコンフィギュレーション操作モジュール、MiMicVMの実行モジュール、ROM上のファイルイメージのマウントモジュールがあります。以下のコードはMiMicRemoteMCUのHttpハンドラです。シンプルな実装で複雑なアプリケーションが実装できます。
#include "mbed.h" #include "SDFileSystem.h" #include "mimic.h" #include "fsdata.h" LocalFileSystem2 lf("local"); SDFileSystem sd(p5, p6, p7, p8,"sd"); class MiMicRemoteMcu:public MiMic::Httpd { private: ModRomFiles modromfs; //ROM file module ModMiMicSetting mimicsetting; //mimic setting API ModRemoteMcu remotemcu; // remotemcu API ModLocalFileSystem modlocal; //basic URL parser ModLocalFileSystem modsd; //basic URL parser public: MiMicRemoteMcu():Httpd(80) { this->modromfs.setParam("rom",RMCU_FSDATA,20); this->mimicsetting.setParam("setup"); this->remotemcu.setParam("mvm"); this->modlocal.setParam("local"); this->modsd.setParam("sd"); } virtual void onRequest(HttpdConnection& i_connection) { //try to ModRomFS module. if(this->modromfs.execute(i_connection)){ return; } //try to ModMiMicSetting module. if(this->mimicsetting.execute(i_connection)){ return; } //try to ModRemoteMcu module. if(this->remotemcu.execute(i_connection)){ return; } //try to ModLocalFileSystem if(this->modlocal.execute(i_connection)){ return; } //try to ModLocalFileSystem(SD) if(this->modsd.execute(i_connection)){ return; } //Otherwise, Send the redirect response to /rom/index.html i_connection.sendHeader(301, "text/html", "Status: 302:Moved Temporarily\r\n" "Location: /rom/index.html\r\n"); return; } }; int main() { NetConfig cfg; //create network configulation with onchip-setting. //try to override setting by local file. if(!cfg.loadFromFile("/local/mimic.cfg")){ wait_ms(1000);//wait for SD card initialization. cfg.loadFromFile("/sd/mimic.cfg"); } Net net(cfg); //create a net instance MiMicRemoteMcu httpd; //create a httpd instance. httpd.loop(); //start httpd loop. return 0; }
MiMicSDKの使用メモリ
MiMicSDKのコアシステムは512バイトのスタックで動作するように設計されています。mbedクラスは2KB程度のスタックで動作します。HTTPハンドラに入った時点でのスタック消費量は約40バイトです。ヒープメモリについては、MiMicSDKはヒープメモリを消費しません。mbedクラスは若干のヒープメモリを消費することがあります。
MiMicSDKの消費するメモリは、約16Kバイトのシステムメモリ(スタック+静的メモリ+ヒープメモリ)と、16KBのイーサネット処理メモリです。イーサネット処理は最低で8KBまで圧縮できます。システムメモリはHTTPハンドラのスタックサイズに依存しますが、スタックサイズ2KB×4スレッドの場合、約16Kバイト以下のメモリで動作します。
参考: MiMicのメモリマップ
NySDFileSystem
SDFileSystemのバグを修正し、スタック消費量を抑制したライブラリです。
http://mbed.org/users/nyatla/code/NySDFileSystem/
MiMicSDKはmbedOfficialのSDFileSystemも使用できますが、NySDFileSystemの使用を推奨しています。mbedOfficialのSDFileSystemを使用した場合、SDカード未挿入時にハングアップします。
プラットフォーム検出
MiMicSDKは実行時にプラットフォームを認識する機能があります。方式は2種類あり、これを利用してmbedとLPCXpressoを判別します。一つの方法はLANペリフェラルを認識する方法、二つ目はMCUに接続されているデバッガを認識する方法です。
LANペリフェラルの認識は単純です。順番にLANペリフェラルを初期化し、成功したペリフェラルのドライバ起動し、使用します。これにより、MiMicSDKはLANペリフェラルの違いを吸収します。
デバッガを認識する方法はやや複雑です。LPCXpressoとmbedでMCUの初期化手順が若干違うので、その差異をCoreDebugRegisterの値から検出します。これにより、MiMicSDKはmbedが持つセミホスティングAPIを抑制します。
トリッキーな方法なのでお勧めは出来ませんが、今のところうまく認識しているようです。
検証プログラムはこちら
http://mbed.org/users/nyatla/code/PlatformSelectSample/
PlatformInfoクラスが検出コードです。リセットのスティッキービットの値とトレースビットの値の組み合わせから判定します。取得前に割込み有効な200msのウエイトを入れるのがポイントです。
MiMicSDKのLocalFileSystem2クラスは、mbedであることが判定した場合のみセミホスティングAPIを使用することで、LPCXpressoがmbed固有コードでハングアップする事態を回避しています。
コンフィギュレーションの保存
MiMicSDKはネットワークコンフィギュレーションをオンチップのプログラムFlashに保存しています。これにより、LPCXpresso,mbedの両方で、更新可能なコンフィギュレーションシステムを実現しています。
プログラム領域のコンフィギュレーションには、「初回値」0xffffffffが書き込まれており、初回のコンフィギュレーション更新時にこの値を0xefffffffにクリアして、プログラムフラッシュの最終ページに同じ構造のコンフィギュレーションを書き込みます。起動時に初回値が0xfffffffでなければ最終ページのコンフィギュレーションを参照することで、オンチップフラッシュを利用したコンフィギュレーションの保持が可能になります。
mbedの場合はさらに、初回値が0xffffffffの時にmbedのMACアドレスで設定値を上書きする処理が追加されます。
またなんか思い出したら書きます。ご質問はTwitterの@nyatlaまで。
Comments are closed, but trackbacks and pingbacks are open.