古賀 信哉のWindows CE Blog
Visual Studio 2005 以降の Visual C++ は、OpenMP 2.0 をサポートしています。OpenMP は、共有メモリ型の並列処理を記述するための仕組みで、C/C++ と Fortran に対する仕様が、OpenMP Architecture Review Board (OpenMP ARB) によって策定・公開されています。OpenMP の詳細は、OpenMP ARB の Web サイト、および、Visual Studio のリファレンスをご覧ください:
Open MP
http://openmp.org/
OpenMP C and C++ Application Program Interface
http://msdn.microsoft.com/en-us/library/8y6825×5(v=vs.90).aspx
なお、OpenMP 仕様の最新版は、2011年の 3.1 ですが、Visual C++ がサポートしているのは 2.0 です。
さて、この OpenMP 2.0 は、Windows Embedded Compact 7 (WEC 7) で対応が追加されました。OpenMP のカタログ項目は、Platform Builder の Catalog Items View に表示されるツリーの、以下の位置にあります:
Core OS
Windows Embedded Compact
Application and Services Development
C Libraries and Runtimes
★ OpenMP Runtime
対応する Sysgen 変数は、SYSGEN_OPENMP です。これについては、リファレンスの次のページに書かれています:
C Libraries and Runtimes Catalog Items and Sysgen Variables (Windows Embedded Compact 7)
http://msdn.microsoft.com/en-us/library/gg155191.aspx
ただし、デスクトップ版の Windows(Windows7 など)とは異なり、WEC 7 の OpenMP 対応では、C/C++ コンパイラの pragma に制限があり、以下のものは使えません。
omp dynamic
omp threadprivate
これについては、リファレンスの次のページをご覧ください:
C/C++ Libraries for Windows Embedded Compact (Windows Embedded Compact 7)
http://msdn.microsoft.com/en-us/library/ee479345.aspx
さらに、WEC 7 の場合は、SMP 対応のボード、つまり、カーネルがマルチコアに対応していなければ、OpenMP を使用できないということが、先ほど述べたカタログ項目のリファレンスのページに書かれています。
マルチコアのプロセッサを搭載した WEC 7 対応のボードをお持ちの方は、試してみると面白いかも知れませんね。Visula C++ で OpenMP を使う場合は、以下のリファレンスページが参考になるでしょう:
OpenMP in Visual C++
http://msdn.microsoft.com/en-us/library/tt15eb9t(v=vs.90).aspx
2012/02/29
koga
Windows Embedded Compact 7 (WEC 7) で追加になった機能の中に、USB Audio のクラスドライバがあります。このドライバを組み込めば、オーディオ出力のハードウェアがないデバイスでも、USB Audio アダプタを使って音声出力できます。今回は、実際に動作確認してみた結果を紹介します。
■USB Audio アダプタ
今回動作確認に使ったのは、エアリア社製の「響音4」という製品です:
http://www.area-powers.jp/product/usb_product/product/kyo-on/u1sounds4.html
家電量販店の店頭で購入しましたが、¥2,000未満の価格で、お手頃です。購入して、Windows 7 の PC に接続してみたところ、パッケージの箱の説明どおり、付属ドライバのインストール無しで、動作しました。つまり、USB Audio の規格に合致しているので、Windows 7 の標準ドライバで動作します。Windpows 7 のデバイスマネージャでデバイス情報を見たところ、USB の Vendor ID が 0D8C ですから、台湾の C-Media Electronics 社のチップセットを使っているようです:
http://www.cmedia.com.tw/ProductsIndex.aspx
■USB Audio クラスドライバ
WEC 7 の USB Audio クラスドライバは、リファレンスに簡単な説明が載っています。
http://msdn.microsoft.com/en-us/library/gg158818.aspx (USB Host Driver Catalog Items and Sysgen Variables)
上のページを見ると、SYSGEN_USB_AUDIO という Sysgen 変数が定義されると組み込まれ、出力と入力をサポートしているようです。このドライバのソースコードは、WEC 7 のソースツリーで、以下の場所にあります。
%_WINCEROOT%/public/COMMON/oak/drivers/wavedev/wavedev2/usb/
このソースを見ると、wavemain.cpp にある Waveform Audio Driver の関数実装のうち、WAV_IOControl() において、入力デバイスに対するメッセージ(WIDM_*)の応答動作も実装されており、出力と入力をどちらもサポートしていることが分かります。Waveform Audio Driver については、リファレンスをご覧ください:
http://msdn.microsoft.com/en-us/library/ee485907.aspx (Waveform Audio Driver Reference)
■USB Audio 機能の組み込み
USB Audio クラスドライバを OS イメージに組み込むには、Platform Builder のカタログ項目ビュー(Catalog Items View)で、次のカタログ項目を選択して下さい:
<OS Design 名>
Core OS
Device Drivers
USB
USB Host
USB Class Drivers
★ USB Audio Class Driver
USB ポート(USB ホストのポート)を搭載した WEC 7 デバイスであれば、これにより、音声出力できるようになります。USB Audio クラスドライバのレジストリ設定ファイル(usbaudio.reg)を見ると分かりますが、Audio クラスを宣言する全ての USB デバイスに対して、このドライバを USB Host Client Driver として登録する設定になっており、USB Audio デバイスの Vendor ID や Product ID を意識する必要は、ありません。
弊社が BSP を提供している CPU ボードである、アットマークテクノ社の Armadillo-440 で試してみたところ、冒頭で紹介した USB Audio アダプタ(エアリア社の響音4)を使って、ヘッドフォンに音声出力できました。エクスプローラのディレクトリアイコンをダブルクリック(ダブルタップ)した際などに、効果音が出力されます。Armadillo-400 シリーズ用 BSP の、公開している評価版では、Armadillo-440 液晶モデルの音声出力インタフェースをサポートしていませんが、USB Audio アダプタと組み合わせれば、WEC 7 の USB Audio クラスドライバを使って音声出力できるというわけです。
さらに、DirectShow と Windows Music Player、および、MP3 と WMA のコーデックを OS イメージへ組み込むことにより、MP3 や WMA の音楽ファイルを再生できることも確認できました。
以上、WEC 7 で追加された USB Audio クラスドライバの紹介です。興味のある方は、ぜひ試してみて下さい。
2012/02/12
koga
前回のエントリでは、ファイルシステム用の永続記憶域を使った部分アップデートの方法を紹介しました。今回は、ROM イメージを複数に分割する方式の部分アップデートについて紹介します。
最初に断っておきますが、この方法は、WinCE/WEC の OS Design のコンフィグレーションでは対応できません。カーネル移植レイヤ(OAL)とブートローダのカスタマイズが必要です。
■複数の ROM イメージ(Multiple Region)
ROM イメージを複数に分割する仕組みは、もともと、WinCE/WEC のカーネルと Platform Builder 内蔵の ROM イメージ生成コマンド(makeimg.exe, romimage.exe)に組み込まれています。ただし、それを有効にするためには、OAL とブートローダが、複数に分割された ROM イメージに対応する必要があるのです。この対応は、必須ではないため、全ての BSP が対応しているわけではありません。対応していない BSP の場合は、OAL とブートローダの実装にカスタマイズを加えなければいけない、というわけです。
複数に分割された ROM イメージに対応した OAL とブートローダは、それぞれ、次の機能を持ちます。
・OAL
ブートローダが Flash メモリなどから RAM にロードした(XIP の場合は、NOR Flash 上の)、複数に分割された ROM イメージのリストを、カーネルに伝える。この通知は、OAL の初期化時に(つまり、OEMInit() の中で)OEMRomChain を構築することで行う。
・ブートローダ
Flash メモリなどから、複数に分割された ROM イメージを RAM へロードする(XIP の場合は、ロードしない)。また、ROM イメージをホスト(開発用 PC)から転送された時は、分割された ROM イメージを各々認識し、それらを、Flash メモリなどに書き込む。
ここで、「分割された ROM イメージ」というのは、ROM イメージファイルを単純に分割したものでは、ありません。「分割された ROM イメージ」の一つ一つは、それぞれが ROM イメージのヘッダを持っていて、個別の ROM イメージとなっています。これらを、region と呼びます。どのように region を構成するのかは、config.bib で設定します。makeimg.exe は、config.bib で複数の region が設定されていれば、それに従って、region ごとに ROM イメージファイル(.bin)を生成するのです。
複数の region を WinCE/WEC カーネルに認識させるために、OAL は、初期化時に region のリストを構築します。このリストが、上で述べた OEMRomChain です。OEMRomChain は、ROMChain_t 構造体のリストで、カーネルのスタートアップルーチンによって、スタートアップルーチンが所属する ROM イメージを指すように初期化されます。つまり、デフォルトでは、region が一つだけとなります。その後、スタートアップルーチンが OAL の OEMInit() を呼び出し、OEMInit() が、OEMRomChain に複数の region を登録する(OEMRomChain を初期化し直す)というわけです。
より正確には、OEMInit() が OEMRomChain をどう構築するかは、OAL における OEMInit() の実装次第です。カーネルのスタートアップルーチンは、OEMInit() を呼び出した後、OEMRomChain の内容をチェックして、自身が所属する region が登録されていない場合には、自身が所属する region を OEMRomChain の末尾に連結します。
ROMChain_t 構造体の説明は、WinCE 6.0/WEC 7 のリファレンスの、次のページをご覧ください:
OEMRomChain
http://msdn.microsoft.com/en-US/library/ee479246(v=WinEmbedded.60).aspx
http://msdn.microsoft.com/en-US/library/ee479246.aspx
■Region ごとの部分アップデート
複数の ROM イメージ(Multiple Region)を使うと、部分アップデートする対象(アプリケーションなど)を収録した ROM イメージと、OS 本体を収録した ROM イメージを分けることができます。そして、ブートローダが対応していれば、アップデートしたい ROM イメージ(region)だけをブートローダへ転送し、書き換えることができます。これが、ROM イメージファイルを複数に分割する方式の部分アップデートです。
この方法の利点は、次の通りです:
・永続記憶域上にルートファイルシステムを構築する必要がないため、より耐障害性が高い。
・OS イメージ中の全てのファイルを、アップデートすることが可能。
ここで、「OS イメージ中の全てのファイルをアップデート可能」というのは、ROM イメージの Region 間で shadowing が作用することによるものです。つまり、二つの region に同じファイルが収録されている場合、上述した OEMRomChain のリストにおいて、より先頭に近い方の region 内のファイルが優先され、その後ろにある region 内のファイルが隠されるのです。
OEMRomChain の region 間での shadowin は、前回紹介した、ルートファイルシステム上のファイルによる ROM イメージ内のファイルの shadowing の仕組みと、本質的には同じものです。どちらも、FSD Manager と、カーネルのローダーによって実現されています。前回、カーネルのローダーが、OpenExecutable() から OpenFileFromFilesys() と OpenFileFromROM() を呼び出し、先に呼び出す OpenFileFromFilesys() で executable ファイル(.exe または .dll)が見つかれば、そちらを優先する、と説明しました。実は、OEMRomChain に複数の region が登録されている場合、OpenFileFromROM() は、OEMRomChain のリスト(つまり、region のリスト)を先頭から順に辿り、最初に見つかったファイルをオープンします。従って、よりリストの先頭に近い region 内のファイルが優先される、というわけです。
たとえば、OS 本体を収録した region(※この region に、カーネルのスタートアップルーチンが含まれます)と部分アップデートする対象を収録した region の二つがある場合について考えましょう。OEMRomChain のリストを構築する際、OS 本体を収録した region がリストの末尾要素となり、部分アップデートする対象を収録した region がリストの先頭要素となるようにすれば、両者に同じファイルが存在する場合、部分アップデート対象を収録した region 内のファイルが優先されます。このため、OS 本体を収録した region に収録したデバイスドライバなどをアップデートする際に、その region を書き換える代わりに、部分アップデート用の region の ROM イメージにアップデートしたいファイルを追加して、部分アップデート用の region だけを書き換える、という方策が可能です。
OS 本体を収録した region のサイズが、部分アップデートする対象を収録した region のサイズよりも、ずっと大きければ、小さい方の region(つまり、部分アップデートする対象を収録した region)の方を書き換える方が、より小さなコストで済みます。
部分アップデート用に、複数の ROM イメージ、つまり region の分割を行う方策としては、region を二つに分ける以外に、次のように、四つの region を設定する方策も考えられます(どちらかといえば、極端な例ですが):
- NK: OS 本体を収録
- EXT: デバイス固有(BSP 固有)のデバイスドライバやアプリケーションなどを収録
- UNK: NK region 内のファイルの更新版を収録する(※出荷時は空)
- UEXT: EXT region 内のファイルの更新版を収録する(※出荷時は空)
このように region を設定すれば、OS 本体(WinCE/WEC のカーネル及び、標準のデバイスドライバやアプリケーション、API の DLL など)と、デバイス(あなたが開発する製品)固有のドライバやアプリケーションを、それぞれ独立してアップデートできます。OS 本体用の ROM イメージと、デバイス固有の ROM イメージは、全体的なアップデートが必要となれば、各々の region(NK, EXT)を書き換えればよいですし、特定のファイルだけをアップデートしたい場合は、各々の部分アップデート用の region(UNK, UEXT)を書き換えればよい、というわけです。
WinCE/WEC は、月例アップデートが公開されます。もし、出荷後に重要な修正がリリースされた場合は、その修正を、出荷済みの製品の OS に反映しなければならないこともあるでしょう。そのような場合に、上の例のような region 分割を設定しておくと、OS 本体の ROM イメージを全て書き換えなくても、修正が加わった .dll や .exe を収録した、部分アップデートの ROM イメージを作り(そのイメージサイズは、OS 本体の ROM イメージに比べて、非常に小さいでしょう)、対応する region を書き換えることでアップデートできます。なお、部分アップデートを繰り返す場合、部分アップデートの ROM イメージには、最新のアップデート対象の .exe や .dll に加えて、以前の部分アップデートの際に収録した .exe や .dll も収録しなければならないことに注意して下さい。そうしなければ、部分アップデートした際に、以前の部分アップデートの内容が消えてしまうからです。
ところで、もし、部分アップデートを繰り返した結果、アップデート対象のファイルが累積して、部分アップデートの ROM イメージが大きくなった場合は、古い部分アップデート内容を破棄して、全体をアップデートする必要が生じる場合も、あると思います。つまり、上の例で言うと、UNK または UEXT region に収録するファイルが増えた場合は、それらの region を空にして、代わりに、NK または EXT region を作り直し、そちらを書き換える必要が生じるでしょう。もちろん、どのように region を分割し、部分アップデートを行うかということは、ケースバイケースですよね。
■Region 分割の手順
ここまでで、ROM イメージを複数に分割する方式の部分アップデートについて、その仕組みと、部分アップデートの方策について説明しました。残りは、実際の手順です。
複数の region に分割した ROM イメージを作成する手順の例は、WinCE 6.0 のリファレンスに載っています。現時点では、WEC 7 のリファレンスには対応するページが見当たりません。
How to Create a Run-Time Image with Multiple XIP Regions
http://msdn.microsoft.com/en-US/library/ee482739.aspx
このページでは、CEPC の場合の手順が載っていますが、他のボード(デバイス)の場合も、基本的には同じです。必要な作業を簡単にまとめると、次の通りです:
・config.bib ファイルの MEMORY セクションの記述を書き換える。その際、環境変数 IMGMULTIBIN に対する条件分岐を書き加えて、複数 region 対応するかどうかを、環境変数(IMGMULTIBIN)の設定有無で切り換えできるようにすると便利。
複数 region 対応用の MEMORY セクションには、NK の他に定義する region を、RAMIMAGE 型の memory region として設定する。また、それらの region の連結内容を記録するための CHAIN region を、RESERVED の memory region として設定する。
http://msdn.microsoft.com/en-US/library/ee482800.aspx (Modifying the Binary Image Builder Files)
・platform.bib ファイルの MODULES または FILES セクションに、NK 以外の region に収録するファイルを記述する。
BSP 固有のデバイスドライバやアプリケーションなどを、NK 以外の region に収録する場合は、環境変数 IMGMULTIBIN に対する条件分岐を書き加えて、複数 region 対応の場合のみ、当該 region(「Region ごとの部分アップデート」で示した例で言えば、EXT region)を指定する。
http://msdn.microsoft.com/en-US/library/ee482800.aspx (Modifying the Binary Image Builder Files)
・OS イメージをビルドする。
・ビルドしてできた .bin ファイルのうち、chain.bib を、Platform Builder から WinCE/WEC デバイスへ転送するファイルとして設定する。
デバイスへ転送するファイルは、Platform Builder のプロパティダイアログで設定できる。Platform Builder の「プロジェクト」 > 「プロパティ」メニューで、プロジェクトのプロパティダイアログを開き、左側にあるツリービューから、「構成プロパティ」 > 「全般」を選択して表示される画面の、「デバッガ用のターゲットファイル名」というラベルのドロップダウンリストで、転送したい .bin ファイルを選択する。
http://msdn.microsoft.com/en-US/library/ee482967.aspx (Building the Run-Time Image and Opening a Workspace with Multiple XIP Regions)
以上が、複数の region に分割した ROM イメージを作成して、WinCE/WEC デバイスのブートローダへ転送するために、Platform Builder で行う手順です。なお、上の最後のページ(“Building the Run-Time Image and Opening a Workspace with Multiple XIP Regions”)の説明では、複数に分割した ROM イメージを全て転送する場合、xip.bin を指定すると書かれていますが、これは、うまくいきません。xip.bin ではなく、CAHIN region の内容を収録した chain.bin を指定して下さい。
xip.bin は、全ての region の内容を一つに連結したファイルなのですが、WinCE 6.0 付属のブートローダのライブラリ(blcommon)の実装は、この構造に対応していないように思われます。xip.bin が、残りの .bin ファイルの内容を単純に連結した内容になっており、その結果、blcommon ライブラリでは、先頭の region しか認識されないのです。blcommon ライブラリのソースを読むと、ROM イメージのヘッダに記すマジックナンバーの値として、xip.bin 専用の値が定義されていたような形跡があるのですが、その値(X000FF)が設定されている場合、blcommon ライブラリは、エラーメッセージを出力して停止するように実装されています。
■OAL とブートローダのカスタマイズ
さて、今回の最初の方で、複数に分割した ROM イメージに対応するには、OAL とブートローダのカスタマイズが必要だと述べました。複数に分割した ROM イメージに対応している OAL とブートローダが、それぞれ、どのような働きをするのかについても、ごく簡単に説明しました。OAL とブートローダに対するカスタマイズの内容について、最後に、もう少しだけ補足します。
・OAL のカスタマイズ
OEMInit() 中で、OEMRomChain を構築しなければならないことは、既に述べました。このことは、次のページに書かれています。
Booting an Image with Multiple XIP Regions
http://msdn.microsoft.com/en-US/library/ee483010.aspx
しかし、このページの説明だけでは、あっさりし過ぎていて、具体的にどうすればよいのか、分かりません。OEMRomChain を構築する例は、x86 用の BSP 共通ソースをご覧になるのが良いでしょう。このソースは、次の場所にあります:
%_WINCEROOT%/PLATFORM/COMMON/src/x86/COMMON/startup/oeminit.c
oeminit.c の中にある、x86InitRomChain() が、OEMRomChain を構築する関数です。なお、x86InitRomChain() では、OEMRomChain という名前の変数の値を設定していますが、実は、OEMRomChain はマクロで、その実体は、OEMGLOBAL 構造体のメンバ pROMChain なのです。
OEMGLOBAL
http://msdn.microsoft.com/en-us/library/ee478176(v=WinEmbedded.60).aspx
http://msdn.microsoft.com/en-us/library/ee478176.aspx
OEMRomChain を定義したヘッダファイルは、次の場所にあります:
%_WINCEROOT%/PUBLIC/COMMON/OAK/INC/bcoemglobal.h
OEMRomChain を構築する処理では、region の連結内容を記録した CHAIN region と、各 regionの ROM イメージヘッダ内容をアクセスする必要がありますが、それらは、以下のヘッダファイルで定義されています:
%_WINCEROOT%/PUBLIC/COMMON/OAK/INC/romldr.h
%_WINCEROOT%/PUBLIC/COMMON/OAK/INC/pehdr.h
CHAIN region の構造については、次のページでも説明されています:
XIP Chain
http://msdn.microsoft.com/en-us/library/ee482877.aspx
・ブートローダのカスタマイズ
ブートローダのカスタマイズについては、次のページをご覧ください。
Adding Support for Multiple-BIN Image Notification
http://msdn.microsoft.com/en-US/library/ee479207.aspx
OEMMultiBINNotify
http://msdn.microsoft.com/en-US/library/ee478943(v=WinEmbedded.60).aspx
http://msdn.microsoft.com/en-US/library/ee478943.aspx
OEMMultiBINNotify() を実装すると共に、CHAIN region の内容および他の region をホストから受け取って Flash メモリなどに書き込む動作、および、region が一つだけ転送された場合(部分アップデートの場合)に、それを正しい場所へ書き込む機能を実装しなければいけません。さらに、ブート動作では、Flash メモリなどに書き込んだ、CHAIN region と他の全ての region を RAM へロードする処理(XIP の場合は、ロードしない)を実装する必要があります。
2012/01/13
koga
WinCE 6.0/WEC 7 では、通常、OS 全体を ROM イメージファイル(nk.bin)に格納し、Flash メモリなどに書き込んで使います。Flash メモリに書き込んだ ROM イメージファイルは、電源投入後に、ブートローダによって RAM にロードされ、ブートローダがカーネルのスタートアップルーチンへ制御を移すことにより、WinCE/WEC が起動する、というわけです(NOR Flash の場合には、XIP; Execute-In-Place 用の ROM イメージファイルを Flash メモリへ書き込むことにより、イメージファイルを RAM にロードせず、Flash メモリから直接カーネルを実行することも可能です)。
ここで、OS 全体を ROM イメージファイルに格納するということは、デバイスドライバやアプリケーションを修正した場合、その修正を反映するには、ROM イメージファイルを作り直して上書きしなければならない、ということを意味します。ROM イメージファイルのサイズは、コンフィグレーション次第で変わりますが、数十MB、場合によっては 64MB を超えることもあります。PC ならばともかく、一般の組み込み機器では、アップデートのたびに ROM イメージファイル全体を書き換えなければならないというのは、大きなコストだと言えるでしょう。
ROM イメージファイル全体を書き変えずに、アップデートしたいアプリケーション(.exe)やデバイスドライバ(.dll)だけを置き換えることは、できないのでしょうか?それは可能です。アップデートしたいものだけを置き換える、つまり部分アップデートには、二通り、ないしは三通りの方法があります。WinCE 6.0/WEC 7 を動かすデバイスのハードウェア構成の違いや、デバイスのメンテナンス方策、および、カーネル移植レイヤとブートローダのカスタマイズが可能かどうかにより、どの方法が最も適しているかは変わりますので、それぞれについて、順に紹介したいと思います。
今回は、ファイルシステム用の永続記憶域を使った部分アップデートの方法を二通り紹介し、次回は、ROM イメージファイルを複数に分割する方式の部分アップデートの方法を紹介します。
■アップデート対象を OS イメージに含めない方法
部分アップデートの最も簡単な方法は、部分アップデートする対象(アプリケーションなど)を OS イメージ(ROM イメージファイル)に含めず、永続記憶域に配置することです。たとえば、WinCE/WEC に付属しない、そのデバイス専用に開発したアプリケーションなどを、OS イメージには含めずに、ハードディスクや microSD カード、USB メモリなどに格納する、という方策です。
この方法の利点は、次の通りです:
・WinCE/WEC に対するカスタマイズの必要がない。
・OS イメージを配置する記憶域と、部分アップデート対象を配置する記憶域を、それぞれ違うものにできる。
たとえば、NOR Flash と NAND Flash を搭載したデバイスの場合であれば、NOR Flash に OS イメージを配置して、NAND Flash 上に部分アップデート対象を配置する、という方法です。NAND Flash 上にファイルシステムが構築されていれば、この方策を使えます。あるいは、NOR Flash と、microSD/SD スロットや USB ポートを搭載したデバイスであれば、microSD/SD カードや USB メモリを常時装着しておき、それらに部分アップデート対象を配置する、という方法が使えます。
ところで、部分アップデートする対象のアプリケーションや DLL を、Platform Builder の OS Design サブプロジェクトにして開発する場合、それらの .exe や .dll は、Platform Builder で設定すれば、OS イメージに格納されません。従って、ビルドや、カーネルデバッガを使ったデバッグまでは、OS イメージに含めるものと同様、Platform Builder で統合して行うことが可能です。
■永続記憶域上にルートファイルシステムを構築する方法
部分アップデートの二番目に簡単な方法は、永続記憶域上のファイルシステムを、ルートファイルシステムとしてマウントすることです。デフォルトのコンフィグレーションでは、WinCE/WEC は、RAMFS (Object Store) をルートファイルシステムとしてマウントしますが、永続記憶域上のファイルシステムをルートファイルシステムにすることも出来るのです。
ルートファイルシステムの設定は、WinCE 6.0 のリファレンスにある、次のページで説明されています:
Mounting an Installable File System as the Root Directory
http://msdn.microsoft.com/en-us/library/ee490194(v=winembedded.60).aspx
WEC 7 のリファレンスでは、上のページの説明に比べると若干分かりづらいですが、次のページで説明されています:
RAM File System Registry Settings (Windows Embedded Compact 7)
http://msdn.microsoft.com/en-us/library/ee490789.aspx
Mount Settings (Windows Embedded Compact 7)
http://msdn.microsoft.com/en-us/library/ee490773.aspx
WinCE 6.0 の場合、上記のページの説明を見て頂くと分かるように、必要な設定は、レジストリ内容を永続化する場合と一部共通します。レジストリ内容を永続化するための設定と、その仕組みについては、2011/02/15 のエントリ(「レジストリ変更内容の永続化(1/2)」)と、2011/02/21 のエントリ(「レジストリ変更内容の永続化(2/2)」)をご覧ください。
WinCE 6.0 の場合に、永続記憶域をルートファイルシステムとしてマウントするためには、レジストリ内容を永続化する場合の手順に加え、以下の手順が必要です:
・Platform Builder のカタログ項目ビューで、次のカタログ項目を選択する:
コア OS
CEBASE
ファイルシステムおよびデータストア
ファイルシステム – 内部(1つ選択)
★ ROM のみに適用されるファイルシステム
・当該ファイルシステムに対するレジストリ設定で、MountAsRoot の値を 1 に設定する。
2011/02/21 のエントリに書いた例(Armadillo-440 の microSD カードを使う場合)だと、次のように設定して下さい。
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory\FATFS]
"MountPermanent"=dword:1
"MountAsBootable"=dword:1
"MountAsRoot"=dword:1
この方法の利点は、次の通りです:
・WinCE/WEC のカーネル移植レイヤ(OAL)とブートローダをカスタマイズする必要がない。
・OS イメージに含めたアプリケーションやデバイスドライバも、アップデートすることが可能(ただし、出来ないものもある)。
OS イメージに含めたアプリケーションやデバイスドライバをアップデートできるのは、ルートファイルシステムに配置されたファイルによる、”shadowing” の仕組みがあるからです。この仕組みは、WinCE 6.0/WEC 7 の、以下のソースファイルで実装されています。
%_WINCEROOT%/private/winceos/COREOS/storage/fsdmgr/virtroot.cpp
%_WINCEROOT%/private/winceos/COREOS/storage/fsdmgr/pathapi.cpp
virtroot.cpp と pathapi.cpp は、FSD Manager (fsdmgr.dll) のソースファイルの一つですが、CreateFile() によるファイルオープンや、Find{First,Next}File() によるファイル走査の際に、ルートファイルシステム配下のパスが指定された場合は、そのファイルがルートファイルシステム上に存在しなければ、ROM イメージのファイルシステムをアクセスするようになっています。この仕組みにより、同じパス名のファイルが、ルートファイルシステムと ROM イメージのファイルシステム(つまり、OS イメージ)の両方に存在すると、ルートファイルシステム上のファイルが優先される、というわけです。これが、shadowing です。
(※ただし、virtroot.cpp と pathapi.cpp による shadowing は、.exe と .dll 以外のファイルに対して行われるようです。これについては、次の項で述べます。)
永続記憶域上のファイルシステムをルートファイルシステムに設定している場合、アップデート手順は、上で述べた一番目の方法と同じくらい簡単です。たとえば、ディスプレイドライバをアップデートしたい場合は、ディスプレイドライバの新しい .dll を /Windows ディレクトリに上書きコピーして、リブートするだけです。/Windows ディレクトリに上書きコピーした .dll は、永続記憶域上のファイルシステムに書き込まれ、リブートした際に、OS イメージ内の古い .dll を隠します(shadowing)。つまり、OS イメージ(ROM イメージファイル)全体を書き換えることなく、目的のファイルだけをアップデートできる、というわけです。
ただし、この方法で全てのデバイスドライバや DLL をアップデートできるわけでは、ありません。アップデートできるのは、ブートの初期フェーズ以降にロードされるデバイスドライバや DLL だけです。たとえば、microSD カード上にルートファイルシステムを構築する場合、SD ホストコントローラのドライバは、この方法ではアップデートできません。SD ホストコントローラのドライバは、ルートファイルシステムをマウントするために必要なので、ルートファイルシステムがマウントされる前にロードされます。従って、たとえルートファイルシステムに、更新した SD ホストドライバの .dll を配置したとしても、shadowing は行われず、OS イメージ内の「古い」方の .dll が動作します。
■shadowing について、もう少し
ちなみに、ROM イメージのファイルシステムのドライバは、romfsd.dll です。このドライバのソースは、開示されていません。romfsd.dll は、FSD Manager の初期化処理でロードされ、”ROM” という名前のボリュームとしてマウントされます。FSD Manager が romfsd.dll をロードする処理は、
%_WINCEROOT%/private/winceos/COREOS/storage/fsdmgr/fsdmain.cpp
にある InitializeROMFileSystem() で実装されています。InitializeROMFileSystem() は、同じファイルで実装されている STOREMGR_Initialize() の中で、最後に呼び出される関数です。つまり、WinCE/WEC のストレージ機能の中核を初期化する処理の、最終段階で呼び出される関数です。
romfsd.dll のソースコードが開示されていないので、詳細は不明ですが、おそらく、romfsd.dll は、OS イメージ内の全てのファイルに対するファイルシステムではなく、OS イメージの FILES セクションに収録されたファイルに対するものだと思われます。OS イメージの MODULES セクションに収録されたファイル(.dll および .exe)は、カーネルのローダー機能がアクセスする仕組みになっているようです。カーネルのローダー機能のソースは、
%_WINCEROOT%/private/winceos/coreos/nk/kernel/loader.c
です。loader.cpp で実装されている OpenFileFromROM() が、OS イメージ/ROM イメージの MODULES セクションから .exe や .dll をロードする関数です。この関数は、OpenExecutable() から呼び出されるのですが、OpenExecutable() は、 まず OpenFileFromFilesys() を呼び出し、ファイルシステム上にファイルが見つからなければ、OpenFileFromROM() を呼び出します。従って、永続記憶域上のルートファイルシステムに .exe や .dll が存在すれば、そちらが優先されます(shadowing)。
なお、カーネルデバッガで追ってみると、.dll や .exe は、romfsd.dll に対するアクセスでは見つからず、必ず、OpenFileFromROM() が呼ばれるようです。上で、romfsd.dll は、OS イメージの FILES セクションに収録されたファイルに対するものだと思われると書いたのは、この観測結果からの推察です。
■耐障害性の強化に関する考察
さて、永続記憶域上にルートファイルシステムを構築することにより、OAL とブートローダのカスタマイズ無しで部分アップデートできることを説明しました。ただし、ここで一つ問題があります。それは、ルートファイルシステムが破損する可能性です。不意の電源断などにより、ルートファイルシステムが破損してしまうと、WinCE/WEC は、起動できなくなってしまいます。Flash メモリなどに格納された OS イメージが無事でも、永続記憶域上のルートファイルシステムが破損してしまうと起動できない理由については、2011/08/02 のエントリ(「レジストリの永続化~RAM-Based の場合」)をご覧ください。このエントリの、三種類のレジストリ永続化方式の長短を述べた個所で、「(a) Hive-Based のレジストリ」の短所で述べたことが、ここでも当てはまるのです:
短所:レジストリの Hive を配置するファイルシステムを Bootable に設定しなければならないため、そのファイルシステムが破損するなどしてマウントできなくなった場合、ブートの第2フェーズへ遷移できず、第1フェーズの完了待ちで WinCE カーネルの起動が停止してしまう。
この問題を回避する方策としては、次のようなものが考えられます。
・ルートファイルシステム破損時の復旧用に、もう一つ OS イメージを作成し、ブートローダの操作で、復旧用の OS イメージを起動できるようにする。復旧用の OS イメージでは、ルートファイルシステムを永続記憶域に割り当てず、RAMFS (Object Store) をルートファイルシステムに割り当てる。
←復旧用の OS イメージの起動後、破損したファイルシステムをフォーマットするなどの、復旧作業を行えるようにする。
OS イメージを格納するストレージ(Flash メモリやハードディスクなど)の容量が十分大きく、OS イメージを二つ格納できる場合は、この方策が向いているでしょう。
・ファイルシステムを AutoLoad 可能な永続記憶域上に、ルートファイルシステムを割り当て、かつ、ルートファイルシステムを Bootable に設定しない。ルートファイルシステムとして正しく動作できるように、ブートの第1フェーズでファイルシステムをロードさせる。ルートファイルシステムを Bootable に設定しないので、RAMFS (Object Store) が Bootable なファイルシステムとしてマウントされる結果、永続記憶域上のルートファイルシステムをマウントできなくても、WinCE/WEC が起動する。
←この方策は、microSD/SD カードや USB メモリに対しては、使えません。使えない理由は、2011/02/21 のエントリ(「レジストリ変更内容の永続化(2/2)」)をご覧ください。SD メモリカードのドライバや USB メモリカードのドライバは、クライアントドライバなので、ロードするブートフェーズを明示的に指定できないのです。ファイルシステムを AutoLoad 可能な場合は、ブートの第1フェーズでロードされるように、レジストリの BootPhase 値を設定しておけば、たとえ RAMFS が Bootable なファイルシステムとしてマウントされても、ブートの第2フェーズへ遷移する前に、ルートファイルシステムがマウントされる筈です。
この方策は、NAND Flash やハードディスクを搭載したデバイスの場合に使えるでしょう。この方策を使った場合、そのままでは、レジストリが永続化されないという問題が残りますが、Hive ではなく、RAM ベースのレジストリにして、ルートファイルシステムを割り当てるのとは異なるストレージ(NOR Flash など)にレジストリを配置する、といった解決策が考えられます。
2012/01/10
koga
前回のエントリで、WinCE/WEC の「リモートディスプレイアプリケーション」のソースディレクトリについて述べました。
%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/CERDISP/
の配下には、前回のエントリで紹介した CERDisp と CERHost の他に、CERDRV というソースディレクトリがあるのです。今回は、前回触れなかった CERDRV について紹介します。
■CERDRV の組み込み
%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/CERDISP/ の下にある CERDRV ディレクトリには、ddi_cer という、仮想フレームバッファ機能を提供するディスプレイドライバのソースファイルが収録されています。より正確には、CERDRV ディレクトリは、ddi_cer_lib.lib という static library のソースディレクトリであって、
%_WINCEROOT%/PUBLIC/COMMON/CESYSGEN/makefile
に記述された設定によって、ddi_cer.dll が生成されます。%_WINCEROOT%/PUBLIC/COMMON/ 配下のソースのビルドについては、2011/08/14 のエントリも、ご覧になってみて下さい。
ddi_cer を OS イメージに組み込むには、BSP_DISPLAY_CER という環境変数を設定して下さい。このことは、
%_WINCEROOT%/PUBLIC/COMMON/OAK/FILES/common.bib
に書かれています。common.bib の、CE_MODULES_DISPLAY に対する条件記述は、以下のようになっています。
; @CESYSGEN IF CE_MODULES_DISPLAY
; @CESYSGEN IF CE_MODULES_MULTIMON
multimon.dll $(_FLATRELEASEDIR)\multimon.dll NK SHK
; @CESYSGEN ENDIF CE_MODULES_MULTIMON
IF BSP_NODISPLAY !
;
; MGDI Display drivers
;
; To use driver set this env var
;
; ddi_flat.dll BSP_DISPLAY_FLAT
; ddi_3dr.dll BSP_DISPLAY_SMI3DR
; ddi_ragexl.dll BSP_DISPLAY_RAGEXL
; ddi_cer.dll BSP_DISPLAY_CER
; ddi_nop.dll BSP_DISPLAY_NOP
IF BSP_DISPLAY_NOP
ddi_nop.dll $(_FLATRELEASEDIR)\ddi_nop.dll NK SHK
ENDIF BSP_DISPLAY_NOP
IF BSP_DISPLAY_CER
ddi_cer.dll $(_FLATRELEASEDIR)\ddi_cer.dll NK SHK
ENDIF BSP_DISPLAY_CER
…(途中略)
ENDIF BSP_NODISPLAY !
; @CESYSGEN ENDIF CE_MODULES_DISPLAY
最後の方にある、IF BSP_DISPLAY_CER と ENDIF BSP_DISPLAY_CER で囲われた行を見て下さい。
また、
%_WINCEROOT%/PUBLIC/COMMON/OAK/FILES/common.reg
には、以下の行があります。
IF BSP_DISPLAY_CER
[HKEY_LOCAL_MACHINE\System\GDI\Drivers]
"Display"="ddi_cer.dll"
ENDIF
Platform Builder で環境変数 BSP_DISPLAY_CER を設定することにより、common.bib と common.reg の上記個所が有効になり、ddi_cer.dll が OS イメージに組み込まれる、というわけです。
なお、お使いの BSP にディスプレイドライバが付属している場合には、BSP 付属のディスプレイドライバを無効にして下さい。BSP 付属のディスプレイドライバを無効にする方法ですが、platform.reg の中に、レジストリキー [HKEY_LOCAL_MACHINE\System\GDI\Drivers] に対する設定行があれば、ddi_cer.dll を組み込む時は、その行をコメントアウトしたうえで、環境変数 BSP_DISPLAY_CER を設定して OS イメージをビルドして下さい。
ここで、platform.reg は、BSP 固有のレジストリ設定を記述するファイルであり、
%_WINCEROOT%/PLATFORM/<BSP 名>/FILES/
に配置されています。
■WinCE/WEC のディスプレイドライバ
ddi_cer について、「仮想フレームバッファ機能を提供するディスプレイドライバ」と書きましたが、これについて、もう少しだけ詳しく書きます。
まず、WinCE/WEC のディスプレイドライバの考え方については、WinCE 6.0 のリファレンスの、以下のページが参考になります:
Display Driver Development Concepts
http://msdn.microsoft.com/en-US/library/ee485877(v=WinEmbedded.60).aspx
WEC 7 のリファレンスのディスプレイドライバの章には、このページに相当する、考え方(concept)を説明したページは無いようです:
Display Drivers (Windows Embedded Compact 7)
http://msdn.microsoft.com/en-us/library/gg159569.aspx
WinCE 6.0 と WEC 7 では、ディスプレイドライバのアーキテクチャは変わっていません。ディスプレイドライバの役割は、おおざっぱにいえば、GWES の描画エンジン機能が生成したレンダリング結果を、フレームバッファ上で合成・蓄積し、ディスプレイへ出力することです。そして、仮想フレームバッファ機能というのは、RAM 上にフレームバッファ領域を割り当て、「GWES の描画エンジン機能が生成したレンダリング結果を、フレームバッファ上で合成・蓄積」するだけの機能のことです。
Linux の場合、同様の仮想フレームバッファ機能として、X Window System の Xvfb (X virtual framebuffer) や、Linux framebuffer (fbdev) があるようです:
Xvfb
http://en.wikipedia.org/wiki/Xvfb
Linux framebuffer
http://en.wikipedia.org/wiki/Linux_framebuffer
さて、ddi_cer による仮想フレームバッファ機能と、前回紹介した「リモートディスプレイアプリケーション」(CERDisp と CERHost)を組み合わせれば、ディスプレイを持たない「ヘッドレス」のデバイスで、GUI 画面によるリモート操作を行うことが可能です。ディスプレイ付きのデバイスの場合は、CERDisp と CERHost により、デバイスに接続されたディスプレイと PC のディスプレイの両方に、WinCE の画面が表示されます。これに対し、ヘッドレスのデバイスの場合(または、ディスプレイ付きのデバイスのディスプレイドライバを無効にして、ddi_cer を組み込んだ場合)は、PC のディスプレイにだけ WinCE の画面が表示される、というわけです。
x86 ベースのボード/デバイスを除く、組み込み機器用プロセッサを用いたデバイスの場合、フレームバッファ領域は、専用の VRAM ではなく、RAM 上に確保するのが一般的です。従って、それらのデバイスについて考えると、実は、ddi_cer と通常のディスプレイドライバの違いは、フレームバッファの内容をディスプレイへ出力するかどうかだけなのです。
ただし、ddi_cer には、CERDisp と同じ機能も実装されていますので、フレームバッファ内容をリモート表示するディスプレイドライバ、という見方もできます。WinCE 6.0 のリファレンスでは、ddi_cer は “Windows Embedded CE remote graphics adapter.” と説明されています:
http://msdn.microsoft.com/en-us/library/ee482180(v=winembedded.60).aspx (Common Windows Embedded CE Modules)
ddi_cer に実装されている CERDisp 相当の機能は、レジストリ設定でオフにすることができます。ddi_cer のレジストリ項目については、
%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/CERDISP/CERDRV/
に入っている cerdrv.reg を見て下さい。cerdrv.reg には、二つのレジストリキーが記述されています。[HKEY_LOCAL_MACHINE\System\GDI\Drivers] と [HKEY_LOCAL_MACHINE\Drivers\Display\DDI_CER] です。このうち、[HKEY_LOCAL_MACHINE\System\GDI\Drivers] の方は、上述した common.reg に記述されているものと同じです。cerdrv.reg の内容は、ビルド時に OS イメージに反映されませんので、[HKEY_LOCAL_MACHINE\Drivers\Display\DDI_CER] キーの内容については、platform.reg か project.reg にコピーするのがよいでしょう。
ddi_cer の、CERDisp 相当の機能をオフにするには、[HKEY_LOCAL_MACHINE\Drivers\Display\DDI_CER] キーの NoServer サブキーを 1 に設定して下さい。ddi_cer は、NoServer の値が 1 に設定されていると、CERDisp と同様の動作を行うサーバースレッドを始動せず、仮想フレームバッファ動作のみを行います。デフォルトでは、ddi_cer の CERDisp 相当の機能が有効なので、CERDisp を実行せず、PC 上で CERHost を実行するだけで接続することができます。NoServer を 1 に設定した場合は、CERDisp も実行する必要があります。
ddi_cer の CERDsip 相当の機能と CERDisp との主な違いは、次の通りです:
・ddi_cer は、ディスプレイドライバとしてフレームバッファを自分が持っているため、画面内容をクライアントへ転送する際は、フレームバッファを直接アクセスする。
CERDisp は、BitBlt() を使って画面内容をキャプチャしたのち、キャプチャした内容をクライアントへ転送する。
・ddi_cer は、カーネルモードドライバなので、TCP/IP 通信処理は、CERDisp の場合とは異なり、カーネルモジュール用の WinSock DLL がロードされる。
ここで、ddi_cer と CERDisp は、WinSock ライブラリとして、どちらも winsock.lib をリンクしています。従って、CERDisp に対しては、winsock.dll がロードされ、ddi_cer に対しては、k.winsock.dll がロードされます。カーネルモジュール用の DLL については、2008/07/22 に書いたエントリ(「カーネルからWinSock」)も、ご覧になってみて下さい。
なお、2007/07/22 のエントリでは、WinSock の DLL は、ws2.dll と k.ws2.dll だと書いており、ddi_cer と CERDisp がロードする DLL とは違っています。実は、winsock.dll(および k.winsock.dll)の方は、古い版の WinSock で、ws2.dll は、WinCE .NET 4.2 から導入された新しい版です。真相は分かりませんが、ddi_cer が k.winsock.dll を使うようになっているのは、2007/07/22 のエントリに書いた、k.ws2.dll に関する制限を回避するためなのかも知れません。
(あるいは、単に、ddi_cer も CERDsip も、WinCE .NET 4.2 より前から付属していて、[k.]ws2.dll を使うように改訂されていない、ということなのかも知れませんが。)
■通常のディスプレイドライバとの比較
興味のある人は、ddi_cer と、WinCE 6.0 のデバイスエミュレータのディスプレイドライバのソースを読み比べてみると、面白いんじゃないかと思います。WinCE 6.0 のデバイスエミュレータは、Samsung の S3C2410 という、ARM9 コアのプロセッサのリファレンスボードをエミュレーションしています。S3C2410 は、LCD コントローラを内蔵していますので、デバイスエミュレータのディスプレイドライバは、S3C2410 の LCD コントローラを制御する処理が実装されています。このドライバのソースコードを収録したディレクトリは、
%_WINCEROOT%/PLATFORM/DEVICEEMULATOR/SRC/DRIVERS/DISPLAY/LCD
です。また、S3C2410 のデータシートは、
http://www.alldatasheet.com/view.jsp?Searchword=s3c2410
などからダウンロードできます。
ddi_cer と、WinCE 6.0 のデバイスエミュレータのディスプレイドライバの大きな違いは、次の通りです:
・ddi_cer は、フレームバッファ領域を確保する際、C++ の new 演算子を使って確保する。従って、連続した物理メモリ領域は、確保しない。
(※より正確には、GPE ライブラリの GPESurf クラスのインスタンスを生成し、GPESurf のコンストラクタによってバッファを確保します。)
デバイスエミュレータのディスプレイドライバは、config.bib の設定により、フレームバッファとして予約した領域を使用する。
・ddi_cer は、ディスプレイデバイスを制御しない。GWES の描画エンジン機能が生成したレンダリング結果を、フレームバッファ上で合成・蓄積するのみ。ただし、レジストリ設定で NoServer が 0 に設定されているか、または何も設定されていない場合は、クライアントに対してフレームバッファ内容を定期的に転送し、「リモートディスプレイ」動作を行う。
デバイスエミュレータのディスプレイドライバは、プロセッサ(S3C2410)の LCD コントローラのレジスタを、カーネル仮想アドレス空間にマップして、必要な制御動作を行う。LCD コントローラの制御動作の一部として、フレームバッファの物理アドレスを、DMA 転送対象領域として LCD コントローラに設定する。
つまり、異なるのは、ディスプレイ出力用のコントローラ(プロセッサ内蔵の LCD コントローラなど)を制御するかどうか、および、フレームバッファ領域として、連続した物理メモリ領域を確保するかどうかです。ディスプレイ出力用のコントローラを制御する、通常のディスプレイドライバの場合には、フレームバッファ全体を一括して DMA 転送できるように、フレームバッファを、連続した物理メモリ領域に確保する必要があります。
なお、デバイスエミュレータのディスプレイドライバでは、フレームバッファの物理アドレスを LCD コントローラに設定する処理は、行っていません。この処理は、OAL の初期化処理として、以下のソースファイルで実装されています:
%_WINCEROOT%/PLATFORM/DEVICEEMULATOR/src/oal/oallib/init.c
init.c の中にある、OEMInit() から呼び出される InitDisplay() で、LCD コントローラの初期化を行い、その際に、フレームバッファの物理アドレスを設定しています。
LCD コントローラの初期化動作を OAL で行う実装になっているのは、カーネル起動時にスタートアップスクリーンを表示するためのようです。ここで、LCD コントローラに設定するフレームバッファのアドレスは、物理アドレスですが、ディスプレイドライバがフレームバッファ領域としてアクセスするアドレスは、カーネル仮想アドレスであることに注意して下さい。RAM の同じ領域であっても、ハードウェア(LCD コントローラ)は、物理アドレスでしかアクセスできず、逆に、カーネルモジュールは、物理アドレスをカーネル仮想アドレス空間にマップしたカーネル仮想アドレスでしかアクセスできません。
余談になりますが、連続した物理メモリ領域をフレームバッファに割り当てる際に、必ずしも config.bib で予約する必要は、ありません。AllocPhysMem() を使って動的に割り当てて使用することも可能です。ただし、AllocPhysMem() では、割り当て先の物理アドレスを指定できないので、ブートローダや OAL がスタートアップスクリーンを表示する際に使う領域と同じ領域を割り当てることが、できません。従って、フレームバッファとして使用する領域のサイズを、仕様として固定してしまえるのであれば、config.bib の設定で割り当てる方が、どちらかといえば簡単になるでしょう。
2012/01/04
koga
■「リモートディスプレイアプリケーション」
どちらかといえば、デバッグ用の機能になりますが、WinCE/WEC には、ネットワーク経由で画面をリモート表示し、操作する機能が標準で付属しています。CERDisp というユーティリティが、そうです。
CERDisp を OS イメージへ追加するには、次のカタログ項目を選択して下さい:
コア OS
CEBASE
コア OS サービス
デバッグツール
★ リモートディスプレイアプリケーション
Platform Builder のカタログ項目ビューには、「リモートディスプレイアプリケーション」の下に、次の二つの項目があります:
CE リモートディスプレイアプリケーション
CE リモートディスプレイユーティリティ
「CE リモートディスプレイアプリケーション」が、CERDisp であり、リモート操作する対象の WinCE/WEC 上で動作します。「CE リモートディスプレイユーティリティ」は、リモート操作を行うホスト(開発用の PC など)で動かすユーティリティで、CERHost という名前です。
CERHost の方は、PC 用にあらかじめビルドされたものが、
%_WINCEROOT%/PUBLIC/COMMON/OAK/BIN/I386/
に入っています。このフォルダに入っている cerhost.exe を PC で起動しておき、その後、リモート操作したい WinCE/WEC 上で、cerdisp.exe を起動して、両者を接続すると、WinCE/WEC の画面を PC に表示できます。
CERDisp の使い方については、Nicolas BESSON という人の Blog の 2007/12/28 のエントリでも説明されています:
Enable Remote Display Application – CERDisp
http://nicolasbesson.blogspot.com/2007/12/enable-remote-display-application.html
また、Mike Hall(Windows Embedded プロダクトグループのテクニカルプロダクトマネージャ)の Blog の 2007/01/04 のエントリでは、”AutoLaunch” というツールと一緒に、CERDisp が紹介されています:
CE 6.0: Booting processes with Command Line Options.
http://blogs.msdn.com/b/mikehall/archive/2007/01/04/ce-6-0-booting-processes-with-command-line-options.aspx
このページで紹介されている AutoLaunch は、レジストリの [HKEY_LOCAL_MACHINE\init] キー下に登録して WinCE/WEC の起動直後に起動されるようになっています(そのための .reg ファイルが、ソースファイルに同梱されています)。AutoLaunch は、起動すると、レジストリの [HKEY_LOCAL_MACHINE\Startup] キー下に登録された内容を見て、登録されたアプリケーションを起動します。
AutoLaunch の便利な点は、[HKEY_LOCAL_MACHINE\Startup] キー下に登録されたアプリケーションを起動する前に、WinCE/WEC に IP アドレスが設定されるまで待つ点です。つまり、WinCE/WEC デバイスのネットワークインタフェース(Ethernet コントローラなど)と TCP/IP スタックの初期化動作が完了し、さらに、DHCP が有効な場合は DHCP サーバから IP アドレスの割り当てを受けて IP アドレスが設定されるまでの間、AutoLaunch は、登録されたアプリケーションを起動しません。従って、WinCE/WEC デバイスの IP アドレスが確定する前にネットワークアプリケーションが自動起動されてしまい、そのアプリケーションがエラーを起こしてしまう、という心配がないのです。
また、[HKEY_LOCAL_MACHINE\init] キーに登録する場合とは違い、登録するアプリケーションのコマンド引数を指定できるのも、AutoLaunch の便利な点です。[HKEY_LOCAL_MACHINE\init] キーの場合、起動されたアプリケーションが SignalStarted() を呼び出す際の引数をコマンドライン引数として渡す仕組みになっているため、コマンド引数を指定することが出来ません。詳細については、上記の Mike Hall の Blog を読んでみて下さい。
■CERDisp と CERHost の動作の仕組み
さて、以下では、CERDisp と CEHost の動作の仕組みについて、簡単に説明します。これら二つのアプリケーションのソースコードは、
%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/CERDISP/
配下にありますので、興味のある人は、ソースコードも読んでみて下さい。
上で紹介した Nicolas BESSON の Blog では、CERHost がサーバ、CERDisp がクライアントという風に説明されていますが、実際は逆で、CERDisp の方がサーバとして動作します。CERDisp と CERHost は、それぞれ、次のように動作します。
・CERDisp の動作
- 起動すると、スクリーンサイズと OS バージョンなどのデバイス情報を取得し、クライアント(CERHost)との接続用スレッドを始動する。
- クライアントとの接続用スレッドは、TCP ソケットを生成して、ポート987番に対し bind() & listen() を実行した後、ブロードキャスト用のスレッドを始動し、その後、accept() を呼び出して TCP 接続されるのを待つ。
- ブロードキャスト用のスレッドは、UDP ソケットを生成して、同じくポート987に対し、デバイス情報と自身の IP アドレスの対を5秒間隔で繰り返しブロードキャストする。
ブロードキャスト用のスレッドは、クライアントと接続したことを検出したら、自発終了する。
- クライアントとの接続用スレッドは、accept() の呼び出しが完了してクライアントと接続したら、ブロードキャスト用のスレッドの終了を待つ。ブロードキャスト用のスレッドが終了したら、クライアントからのイベント通知を受信するスレッドを始動し、その後、画面内容をクライアントへ転送するループ動作を実行する。
画面内容をクライアントへ転送するループ動作では、レジストリで設定された間隔(デフォルトは、100ミリ秒)で画面内容をキャプチャして、キャプチャした画像データをクライアントに送信する。ここで、送信する画像データは、BitBlt() でキャプチャした画面内容を、行単位でランレングス圧縮したもの。
- クライアントからのイベント通知受信スレッドは、画面内容を送信するのと同じ TCP ソケットに対して、クライアントから送られたイベントを受信して処理するループ動作を実行する。クライアントから送られたイベントは、マウスイベントであれば、mouse_event() を呼び出し、キーボードイベントであれば keybd_event() を呼び出すことにより、システムのイベントキューへ投入する。
・CERHost の動作
- 起動すると、UDP ソケットを生成して、ポート987番に対するブロードキャストメッセージを監視し、検出したサーバ(CERDisp)のリストを構築・管理する。
- 検出した CERDisp のうち、[File] → [Connect...] メニューのダイアログで指定された IP アドレスのものに TCP 接続し、通知されたスクリーンサイズと同じサイズになるよう、自身のウィンドウの(クライアント矩形の)サイズを調節する。
- 以降は、TCP ソケットから画面内容を受信して、自身のウィンドウに表示する動作と、マウスイベントおよびキーボードイベントを TCP ソケットで送信する動作を繰り返す。
このようにして、CERDisp と CERHost が連携し、WinCE/WEC のリモート操作を実現します。WinCE/WEC には、RDP (Remote Desktop Protocol) のサーバ機能は付属していませんが、CERDisp と CERHost を使えば、似たことができるというわけです。
Mike Hall が彼の Blog で書いているように、この機能は、WinCE/WEC のリファレンスボードや開発ボードを使う際、ボードにモニタや液晶パネルを繋がなくても、開発用の PC だけで、WinCE/WEC と開発環境を同時に操作する際に便利でしょう。最近のボードは、液晶パネルが付属しているものが珍しくありませんが、それでも、開発用の PC だけで操作できるというのは、便利な場合が少なくないと思います。
ところで、注意深い人は、
%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/CERDISP/
の下に、CERDisp と CERHost の他にもソースディレクトリがあることに気づいたのではないかと思います。次回は、それについて書きます。
2011/12/29
koga
来週の水曜日~金曜日(11/16-18)の三日間、パシフィコ横浜で開催される ET 2011 に出展します。今年の ET でも、日本マイクロソフトのパートナーパビリオンでの出展です:
http://www.jasa.or.jp/et/ET2011/examine/list.html#な
弊社からは、先日 Armadillo-460 にも対応した、WEC 7/WinCE 6.0 用の BSP (Lilas-am440-6/7) を出展する予定です。また、三日目(11/18)の 11:25 から、「Windows Embedded Compact CE の異機種相互接続能力を解説!~ Armadillo 400 シリーズの視点から ~」と題したミニセッションを行います:
http://www.microsoft.com/windowsembedded/ja-jp/events/japan-exhibitions-et-2011-11-16.aspx#et05
展示会場での展示に加え、日本マイクロソフトのプライベートカンファレンスが、11/16, 17 の2日間開催されます:
http://www.microsoft.com/windowsembedded/ja-jp/events/japan-exhibitions-et-2011-11-16.aspx
こちらは、事前登録制となっていますので、お早目にお申し込み下さい。2日目のキーノートセッションでは、WEC 7/WinCE 6.0 のユーザ事例紹介もあるようです。
2011/11/11
koga
Microsoft の Windows Embedded エバンジェリストである、Olivier Bloch の今月初めの Blog を読んで知りましたが、9/6 に、Windows Embedded Compact 7 の解説書が発刊されています:
http://www.amazon.co.jp/Professional-Windows-Embedded-Compact-7/dp/1118050460/ref=sr_1_1?s=english-books&ie=UTF8&qid=1317166678&sr=1-1
目次を見てみたところ、なかなか良さそうな感じです。WEC 7 に関する、まとまった技術資料が欲しいという方には、お勧めだと思います。
2011/09/28
koga
東京エレクトロンデバイス社主催の「Device2Cloud コンテスト」が、昨年に続き、今年も開催されます:
http://www.atmark-techno.com/news/press-releases/20110830_D2C2012
弊社もお手伝いしており、Armadillo-440 用の WEC 7 BSP (Lilas-am440-7) 無償版の、コンテスト向け特別バージョンを提供します。多くの学生の方に、参加して頂けると嬉しいです。
2011/08/31
koga
今日になって気づいたのですが、これまでリリースされていなかった、WEC 7 (Windows Embedded Compact 7) の月例アップデートの7月分が、8/11 に公開されていました:
http://www.microsoft.com/download/en/details.aspx?id=27111
リリースノート(Windows Embedded Compact 7_M07_2011.htm)の内容を見ると、今回の修正では、HTTP コンポーネントに対する改善のみのようです。今後、WinCE 6.0 や 5.0 など、サポート継続中のバージョンと同様、毎月少しずつアップデートが重ねられていくことを期待します。
なお、上のアップデートは、WEC 7 のダウンロードページには、記載されていません:
http://www.microsoft.com/windowsembedded/en-us/downloads/download-windows-embedded-compact-ce.aspx (Download Windows Embedded Compact 7)
WinCE 6.0 では、上記 “Home >> Downloads >> Compact & CE” の対応ページに、7月分の月例アップデートへのリンクが載っているのですが、WEC 7 については、載っていません。また、WinCE 5.0 についても、6月分までの月例アップデートは載っているものの、7月分の月例アップデートは、載っていません:
http://www.microsoft.com/windowsembedded/en-us/downloads/download-windows-embedded-ce6.aspx (Download Windows Embedded CE 6.0)
http://www.microsoft.com/windowsembedded/en-us/downloads/download-windows-embedded-ce-5.aspx (Download Windows Embedded CE 5.0)
これら、従来のダウンロードページには記載されていない、最新(2001年7月版)の月例アップデートは、Microsoft Download Center ページで検索すると、ヒットすることに気づきました。たとえば、WEC 7 であれば、URL は
http://www.microsoft.com/download/en/search.aspx?q=Windows%20CE%207.0
となります。
WinCE/WEC のアップデータは、http://www.microsoft.com/download/en/search.aspx に対して、’q=Windows%20CE%20<バージョン番号>‘ というクエリを与えることで検索できるようです。または、Microsoft Download Center のデフォルトページ(http://www.microsoft.com/download)の検索入力ボックスに、’Windows CE <バージョン番号>‘ という形式で、対象の WinCE/WEC を指定すれば、検索できます。
従来のダウンロードページにおいても、これら最新アップデータ情報を反映してもらえると助かりますが、その運用が落ち着くまでは、Microsoft Download Center ページで検索するのが良いでしょう。
2011/08/24
koga
Next Posts
Previous Posts