4.見える化

組込み

 動作中の組込みソフトウェアの内部情報を把握し易くするためには、「組込みハードウェア」の外へ、動作中の「組込み制御ソフトウェア」の中の変数の値を取り出して、評価できるようにする必要があります。ある程度複雑で規模が大きい「組込み制御ソフトウェア」の実装先の「組込みハードウェア」には、何らかのデータ取り出しのための仕組みを持っている場合もあります。また、「組込み制御ソフトウェア」開発の難しさをリスクと考える場合は、最初から「組込みハードウェア」の仕様、および「組込み制御ソフトウェア」の仕様に、内部情報を把握する機能を入れておいても良いでしょう。ここで重要な事は、「組込み制御ソフトウェア」は「動いているもの」を扱うため、“変数の値を取り出す仕組み”は、最終製品状態で使える事、もしくはそこに限りなく近い状態で利用できるようにしておく事です。言い換えると、製品出荷前の最終テストで付いていた、“変数の値を取り出す仕組み”を、出荷後の製品用で外してしまうと、外した影響で「組込み制御ソフトウェア」の挙動が変わる可能性があります。そうすると、製品で発生した「不具合」の修正が出来なくなるので、それは避けるべきです。

 少しカッコ良く表現すると、開発する製品そのものに、組込みソフトウェアの「見える化」を行うための仕組みを入れることになります。この「見える化」の逆は「隠蔽化」です。例えばC言語では、関数内スタティック変数、ファイル内スタティック変数などが「隠蔽化」の役目を果たします。一般に他のプログラム部分から「隠蔽化」して、勝手にアクセスされない様にする目的で用いられるものです。プログラミングの教科書では、プログラムの他の部分からアクセスしない変数で、値の保持が必要なものは、スタティック変数として定義する事が推奨されています。ただし、組込みソフトウェアを「見える化」するためには、この「隠蔽化」を実現するスタティック変数の利用を、止める必要があります。この様に、「組込み制御ソフトウェア」では、一般のソフトウェア開発で推奨されている事を否定する部分があります。本来のスタティック変数を利用する目的である、プログラムの他の箇所からのアクセスを回避する事については、グローバル変数名の工夫と、ファイル間検索で、意図しないアクセスをチェックするという行為で代替する事になります。実際には、組込みソフトウェアの設計仕様の中で命名ルールを工夫し、チェックツールを作るなどして、この作業を自動化するべきでしょう。

 ここで一旦補足しておきますが、グローバル変数は、ローカル変数と異なり、値がメモリ上に保持されます。組込みシステムの外にデータを取り出す最も一般的な方法は、そのメモリの値を、外部へ読み出す方法です。要は、グローバル変数に定義したものは、モニターする手段を確保できるという事です。例えば、組込み用クロスコンパイラには、通常グローバル変数について、組込みハードウェアのメモリ上のアドレスを把握するための機能が提供されています。メモリ上の値は、アドレスとデータサイズが分かれば、取出す仕組みを作ることができます。

 ということで、グローバル変数を使えば、目的である組込みソフトウェア実装時の動きを把握する事が可能になります。自動車業界では、組込みソフトウェアのパラメータ(定数)変数の適合(最適化設定)の目的のため、内部情報を取出する仕組みをASAM MCD-2 MC(ASAP2)という規格で整備しています。モニターしたい変数と、そのメモリ上のアドレス値およびサイズを所定のフォーマットに定義するものですが、ここでも通常グローバル変数を扱います。

 一方注意すべき点として、グローバル変数を使った計算は、ローカル変数を使った計算に比べて、一般に計算時間が長く掛かります。ループカウンターの様にアクセス数が非常に多い変数には、グローバル変数を使うべきではありません。ここで理解した欲しい事は、組込みソフトウェアの動作状況を知るために、役立つ情報をきちんと選んで、リスクを理解して、グローバル変数を利用する事が重要という事です。

 ここまではグローバル変数を利用する事で、実装ハードウェアの外にデータを取り出しやすくなる事、つまり「組込みソフトウェアの動作状況を把握し易くする」事を説明してきました。追加の注意事項として、モニター用のグローバル変数に、構造体の利用を避けるべきという点についても説明しておきます。

 構造体はオブジェクト指向のクラス概念の元になっており、複数の関連するデータをまとめて管理することで、ソフトウェアの保守性の向上に貢献するものです。例えば、コップに、色、材質、中に入っている液体の量、取手の数などをデータとして持たせる場合に、構造体変数を利用して、それぞれのメンバー変数を定義して値を設定して管理すると便利でしょう。また、多くのCプログラミングの教科書や記事では、その便利さから構造体の利用を推奨されています。ただし、本章の目的である「組込みソフトウェア」の動作状況を把握し易くする目的では、状況が異なってきます。例えば、液体の量だけ効率的にモニターしたい場合があります。組込ハードウェアからデータを取出す場合、データのサイズに比例して通信量が大きくなるため、構造体データ全てをパッケージとして送るのは不利です。ということで、中のメンバー変数だけ取り出してモニターしようとした場合、その構造定義を調べないと、データの型を把握できません。その時点で、組込みソフトウェアで重要な「見える化」が阻害されています。さらに重要な問題は、プロセッサやコンパイラに依存して、構造体メンバー変数の、組込みハードウェアのメモリ上の配置場所が異なる場合があります。例えば、構造体のメンバーのメモリ上の配置が、前詰めの場合もあれば、後詰めの場合もあり、さらにメモリサイズを最小化するための並び替えが行われる場合もあります。さらに問題なのは、それらメモリ配置の仕様が必ずしも公開されていない場合がある事です。そのため、構造体変数の情報を、組込みハード上のメモリから取り出して、PC上のソフトウェアで取り扱う場合には、グローバル変数単体だけの場合には不要な、専用のメモリ配置変換処理を、試行錯誤で作成する事が必要になる場合があります。これらは、ここで目的としている「組込みソフトウェア実装の動きを把握し易くする」ことに反します。

 構造体を利用出来ないことによる、データの管理上のマイナス面については、これも変数名の工夫と、管理を容易化するツールを作るなどで対策を取ることになります。

 なお、その他にも、構造体を利用するリスクはあります。仕様変更が発生しないのであれば、構造体理想的なデータパッケージングができるのですが、ある程度のチーム規模、複数チーム、複数の会社間で協力した開発を行なっている際に、たった1個のメンバーデータの変更で、その構造体を使う全てのファイルに、そのメンバー変数を使っていなくても、修正の影響が出てしまいます。これを避けたいと思う人は多いでしょう。

 本章で「組込みソフトウェアの動作状況を把握し易くする」ために、ソフトウェア内部情報のモニターのために、グローバル変数を活用し、スタティック変数を使わないこと。そして、モニター用のグローバル変数に、構造体を使わない様にする工夫について、説明しました。通常のプログラミングの知識が豊富であっても、組込み制御ソフトウェア開発の経験が十分ない人々の中には、この方針を聞いたとたんに、批判をしてくる場合があります。私も「何そのプログラム、レベル低すぎ~」と言われたことがあります。こちらは、トラブル多発でエンドレスの作業になりやすい、製品出荷前の最終試験を、最短時間で終わらせたい一心なので、そういう発言は無視していましたが、それを言いふらされると、さすがに良い思いはしませんでした。皆さんも、このような批判を受ける可能性があるので、覚悟が必要です。

 長くなってしまいましたが、次章は、「組込みソフトウェアの動作状況を把握し易くする」工夫としての第1弾となる、データ更新タイミングについて、説明します。