2011年3月2日水曜日

Natural Tiny Shell(NT-Shell)のポーティング事例。LPCXpressoとTOPPERS/ASPで小規模組み込みシステムの開発をもっと便利に!

はじめに

前回の記事でVT100仮想端末を小規模組み込みシステムで実現するためのライブラリを公開しました。
中には「これが何の役に立つのだろう?」と疑問に思われた方も少なくないでしょう。

この手のツールは実際の開発作業が進むにつれて利便性を再認識することが少なくありません。
(逆に言うと実際に開発作業で相当に困らないと不便な事に気付かない事が多いのです。)

今回はLPCXpresso上でTOPPERS/ASPを動作させるシステムを実際に開発するシステムと見立てて、Natural Tiny Shell(NT-Shell)をポーティングして活用した時のメリットについて御紹介します。


TOPPERS/ASPでNatural Tiny Shell(NT-Shell)を使う

今回はRTOS上にシェルを実装することでシステム開発をもっと便利にしてみましょう。
題して「LPCXpressoとTOPPERS/ASPで小規模組み込みシステムの開発をもっと便利に!」です。
小規模組み込みシステムでありがちな「この程度の規模だからいいや。」と諦めている方におすすめです。
きちんと動作するデバッグ用シェルがあるだけでシステムが見違えるように良くなったように感じます。
デバッグも楽しくなって作業効率が向上すること間違いなし!
是非皆さんも挑戦してみませんか?

エコーバックを行わないようにする

受信した文字列をエコーバックする設定を取り除く。

TOPPERS/ASPでは受信した文字列をエコーバックすることができるようになっています。
Natural Tiny Shell(NT-Shell)を使用する時、エコーバックは都合が悪いので設定を外します。
これはシリアルインターフェースドライバで行うことができます。

syssvc/serial.c の serial_opn_por 関数でIOCTL_ECHOの指定を取り除きます。
serial.cの240行目付近です。


/*
 *  変数の初期化
 *  エコーバックさせたい時にはIOCTL_ECHOを追加すると良い。
 */
p_spcb->ioctl = (IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV);


なぜ受信した文字列をそのまま返してはいけないかという話です。

システムに接続されたシリアル端末が送信してくるコードの中には制御コードが含まれる事があります。
今回のシェルを設計実装した目的の1つは「制御コードをうまく処理してシリアル端末ユーザに便利な機能を提供しよう」です。
受信したコードをそのまま送信した結果、シリアル端末上で制御コードが解釈されてしまっては従来と何も変わらない事になってしまいます。
これを避ける為にエコーバックをしないようにします。

例えば、「おっ。上方向キーだな。じゃあ、過去のコマンドを表示してあげよう。」といった具合です。

システム

今回のシステムは以下のようになっています。
実際に開発するシステムに見立てていると考えてみて下さい。


システムと開発用ホストは2つのUSBで接続されています。

1つはLPCXpresso用でこれはLPCXpresso上のデバッガに接続されています。
実際に開発するシステムによってはここは他のデバッガに置き換わる事もあるでしょう。

もう1つは開発対象システムのUARTをUSBで入出力するための変換器との接続です。
今回は秋月電子通商で販売されているFT2232Dを使った変換器を使用しました。

実際の接続した状態は以下のようになっています。


内部タスクの構成

今回の内部タスク構成を以下のようにしました。
  • task_ledblink: LEDを一定間隔でトグルするLED点滅タスク
  • task_ntshll: Natural Tiny Shellをフロントエンドとするシェルタスク

LED点滅タスクを作る

LED点滅タスクは一定時間間隔で動作しLEDの状態をトグルさせるタスクです。
点滅の間隔は100[ms]ですが、データキューから値を受け取って変化させることができるようにしてあります。
外部からデータキュー経由で点滅の速度(正確にいうとタスクの動作間隔)を変化させることができるようにしてあります。


void task_ledblink(intptr_t exinf)
{
    syslog(LOG_NOTICE, "task_ledblink: Started.");

    int ledspd = 100;
    while(1)
    {
        uint_t value;
        while (prcv_dtq(DTQ_LEDSPD, (intptr_t *)&value) == E_OK) {
            if (value > 0) {
                ledspd = value;
                // syslog(LOG_NOTICE, "new value is %d.", value);
            }
        }
        LPC_GPIO0->FIOPIN ^= ACTLED;
        tslp_tsk(ledspd);
    }
}


シェルタスクを作る

次にNatural Tiny Shell(NT-Shell)を組み込んだシェルタスクを立てます。
シェルタスクはUARTに対する入出力を管理しながら、ユーザの要求をシステムに伝達する役目を果たします。


void task_ntshell(intptr_t exinf)
{
    syslog(LOG_NOTICE, "task_ntshell: Started.");
    serial_opn_por(SIO_PORTID);

    ntshell_execute(&parser,
            &editor, &history,
            func_read, func_write, func_cb);
}


ntshell_executeは処理を戻さない関数です。
UARTからの入出力関数を受け取って処理を行ないます。

今回の例ではfunc_readは以下のようになっています。


int func_read(void *buf, int cnt)
{
    return serial_rea_dat(SIO_PORTID, buf, cnt);
}


同様にfunc_writeは以下のようになっています。


int func_write(const void *buf, int cnt)
{
    return serial_wri_dat(SIO_PORTID, buf, cnt);
}


ユーザが操作を決定するとコールバック関数(上記ではfunc_cb)が呼ばれるようになっています。
ユーザが入力を完了後、エンターキーを押した時の入力文字列が渡されるようになっています。

ここでユーザの要求に応じて処理を行えば良い事になります。


int func_cb(const unsigned char *text)
{
    // TODO 入力されたコマンドに応じて処理を行う。
}


ちなみに、この関数内部の実行スレッドはシェルタスクのスレッドです。
今回のアプリケーションでは以下のように実装してみました。
ntop_compareはNatural Tiny Shellに含まれるユティリティ関数で、文字列の比較を行うものです。


int func_cb(const unsigned char *text)
{
    static int ledspd = 100;
    if (ntopt_compare(text, "INTERVAL UP") == 0) {
        if (ledspd < 500) {
            ledspd++;
            snd_dtq(DTQ_LEDSPD, (intptr_t)ledspd);
        }
    } else if (ntopt_compare(text, "INTERVAL DOWN") == 0) {
        if (ledspd > 1) {
            ledspd--;
            snd_dtq(DTQ_LEDSPD, (intptr_t)ledspd);
        }
    } else if ((ntopt_compare(text, "HELP") == 0)
            || (ntopt_compare(text, "?") == 0)) {
        text_puts("\r\nINTERVAL UP   : Task interval time increase.");
        text_puts("\r\nINTERVAL DOWN : Task interval time decrease.");
    } else {
        if (ntopt_get_count(text) > 0) {
            text_puts("\r\nUnknown command found. (HELP: display help.)");
        }
    }

    return 0;
}


実際に使ってみる

実際に使用している様子を動画で御紹介します。


リソース

今回は3千円で楽しめるARMマイコンとRTOSの世界 (TOPPERS/ASP on LPCXpresso LPC1768)のプロジェクトに小規模組み込みシステムデバッグ用シェル - Natural Tiny Shell (NT-Shell)を追加する形で作業しました。
プロジェクトはここからダウンロードできます。

2011/03/08追記。
公開当初のサンプルプロジェクトが使用しているNT-Shellにはバックスペース処理にバグがありました。
修正したライブラリに差し替えました

まとめ

ターゲットに対して対話型で操作要求ができるとちょっとした確認をする時に非常に便利です。
今回はLPCXpresso(Cortex-M3搭載)でRTOS(TOPPERS/ASP)を動作させるという比較的小さな組み込みシステムでの応用例を示しました。

システム内部の値を外部から変更することは当然デバッガなどでも可能です。
しかし、ちょっとしたパラメータを変更したい場合や複数のパラメータを同時に変更したい時には不便です。

対話型のシェルインターフェースがあれば、開発ホスト並の利便性を確保することも可能になります。

補足

念の為補足しておくと、LEDの点灯間隔を変化させるという行為が主眼ではありません。
おそらく点灯間隔を変えるための実装にはもっと相応しいものがあるでしょう。

今回はあくまでシステム内部の挙動をシェルを介して変化させるというところに視点をおいてあります。
今回の実装では点灯間隔が狭くなるにつれてプロセッサの使用率も相当上がります。
システムがどの程度の負荷を許容するのかを外部でパラメータを変更させながら見ることもできるでしょう。

1 件のコメント:

  1. 北京の技術者です。NT-Shellをいつも開発の有力なツールとして使っています。どうもありがとう。今は会社のプロジェクトでNT-ShellをToppers/ASPに組み込んでみたいと思います。更新を期待しています。

    返信削除