MbedFileServerを公開しました。

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.