PiNub その2 [Raspberry Pi]
仕事で使うRaspberry Piに汎用的なソフトウェアを乗せたいという話の続き。仕事用にはRaspberry PiをGPIOを経由して他のハードウェアと接続するのに使うのが多く、全く異なる用途を想定する必要は少ない。そこで共通のソフトウェアで、一気に対応してしまいたい、と考えた。他のハードウェアの機能と接続経路、それとその使い方を記述したファイルを格納しておいて、それを読み出してソフトウェアが自分自身を構成する。
そのソフトウェアをPiNubと名付けた。その構造を考える....
PiNubはRaspberry Piのどのバスにどんなデバイスがいくつ繋がっていても対応できるように、いわゆるマルチインスタンスな書き方をしないといけない。そのためには外部デバイスを表現するオブジェクトとそれを複数個生成して接続するような、オブジェクト指向な書き方になる。Swiftならそのままその通り書けばいいんだけど、まだSwiftの環境が整わない。環境整備を優先したいところだけど、放っておくと整備できる前に、同じようなソフトウェアを次々書き散らさないといけなくなるので、Swift化は後回しにすることにした。そのせいでオブジェクト指向風な表現をCで書く、ということになる。
Cによるオブジェクト指向風な書き方というとGObjectがある。今回の場合はプログラマティックにオブジェクトを定義できる必要はなく、あらかじめ決まったオブジェクトを生成して接続できればいいだけなので、GObjectは大袈裟すぎる感じがする。そうすると例えばObjective-Cとの互換性を無視したCoreFoundationを実装するような感じでいい。つまりオブジェクトはふつうのCの構造体で
オブジェクト構造をざぁっくり考えてみると、 みたいな感じにしたい。つまり、busオブジェクトはSPIやI2Cを抽象化したもので、Threadを作ってその中でループを回す。ループではdeviceオブジェクトにラウンドロビンで作業のスロットを渡す。
deviceオブジェクトはA/D変換やD/A変換用のチップの抽象化。それぞれにpigpioのhandleを保持する。interfaceオブジェクトはpigpioでのバスのオープンやクローズを行って、handleをdeviceオブジェクトに渡す。
driverオブジェクトはdeviceチップのチャンネルのひとつを表す。例えばA/D変換チップのMCP3208には0〜7まで8つのチャンネルがあって、それぞれ別のアナログ信号を受け付ける。driverオブジェクトはチャンネルのひとつとしてdeviceに作業を依頼(A/D変換deviceならひとつのアナログ信号をサンプリングしてデジタルに変換してその数値を受け取る)して、その結果を適切な物理量に変換する。オーバーサンプリングなどもこのオブジェクトの仕事だな。
controllerオブジェクトはユーザインターフェイスからの指示に従ってdriverオブジェクトをキックする。deviceとdriverオブジェクトはbusのthread上で動作するけど、controllerオブジェクトはその外で、thread間通信の機能を持っていないといけない。
PiNubが動いているときの状態はこんな感じだな。これをCで書かないといけない。少数の決まったオブジェクトがあればいいだけなので、GObjectのように複雑で厳密にする必要はない。記述に従ってそれぞれのオブジェクトを生成できて、オブジェクト間を接続できればいい。また極端にいえば実行中に回路構成が変更されることはないので、オブジェクトの解放もそれほど厳密にする必要はない。解放はPiNubのプロセス終了処理に任せてしまってもいい。
メモリの解放よりも重要なのは、デバイスの実体の方をニュートラルな状態に戻しておくことである。特に出力を実行するデバイス、例えばD/Aの出力はGroundに、リレーはオフ状態に、GPIOのBCMピンは読み込み状態に、などにしてから終了すべきである。
オブジェクト設計はしっかり固めないとCで書くのが大変になるので、詳細を詰めるときにまたやりなおすことにする。
そのソフトウェアをPiNubと名付けた。その構造を考える....
PiNubはRaspberry Piのどのバスにどんなデバイスがいくつ繋がっていても対応できるように、いわゆるマルチインスタンスな書き方をしないといけない。そのためには外部デバイスを表現するオブジェクトとそれを複数個生成して接続するような、オブジェクト指向な書き方になる。Swiftならそのままその通り書けばいいんだけど、まだSwiftの環境が整わない。環境整備を優先したいところだけど、放っておくと整備できる前に、同じようなソフトウェアを次々書き散らさないといけなくなるので、Swift化は後回しにすることにした。そのせいでオブジェクト指向風な表現をCで書く、ということになる。
Cによるオブジェクト指向風な書き方というとGObjectがある。今回の場合はプログラマティックにオブジェクトを定義できる必要はなく、あらかじめ決まったオブジェクトを生成して接続できればいいだけなので、GObjectは大袈裟すぎる感じがする。そうすると例えばObjective-Cとの互換性を無視したCoreFoundationを実装するような感じでいい。つまりオブジェクトはふつうのCの構造体で
typedef struct _PNObject PNObject; PNObject *createPNObject(some arguments); void releasePNObject(PNObject *obj);みたいにしてオブジェクトを独立に生成消滅できるようにするのが基本である。今回の場合、すべてをオブジェクトにする必要はない。ハードウェア構成を抽象化するオブジェクトがあればいい。つまりRaspberry Piのバスやそれにつながるデバイスなどがオブジェクトとして表現できればいい。
オブジェクト構造をざぁっくり考えてみると、 みたいな感じにしたい。つまり、busオブジェクトはSPIやI2Cを抽象化したもので、Threadを作ってその中でループを回す。ループではdeviceオブジェクトにラウンドロビンで作業のスロットを渡す。
deviceオブジェクトはA/D変換やD/A変換用のチップの抽象化。それぞれにpigpioのhandleを保持する。interfaceオブジェクトはpigpioでのバスのオープンやクローズを行って、handleをdeviceオブジェクトに渡す。
driverオブジェクトはdeviceチップのチャンネルのひとつを表す。例えばA/D変換チップのMCP3208には0〜7まで8つのチャンネルがあって、それぞれ別のアナログ信号を受け付ける。driverオブジェクトはチャンネルのひとつとしてdeviceに作業を依頼(A/D変換deviceならひとつのアナログ信号をサンプリングしてデジタルに変換してその数値を受け取る)して、その結果を適切な物理量に変換する。オーバーサンプリングなどもこのオブジェクトの仕事だな。
controllerオブジェクトはユーザインターフェイスからの指示に従ってdriverオブジェクトをキックする。deviceとdriverオブジェクトはbusのthread上で動作するけど、controllerオブジェクトはその外で、thread間通信の機能を持っていないといけない。
PiNubが動いているときの状態はこんな感じだな。これをCで書かないといけない。少数の決まったオブジェクトがあればいいだけなので、GObjectのように複雑で厳密にする必要はない。記述に従ってそれぞれのオブジェクトを生成できて、オブジェクト間を接続できればいい。また極端にいえば実行中に回路構成が変更されることはないので、オブジェクトの解放もそれほど厳密にする必要はない。解放はPiNubのプロセス終了処理に任せてしまってもいい。
メモリの解放よりも重要なのは、デバイスの実体の方をニュートラルな状態に戻しておくことである。特に出力を実行するデバイス、例えばD/Aの出力はGroundに、リレーはオフ状態に、GPIOのBCMピンは読み込み状態に、などにしてから終了すべきである。
オブジェクト設計はしっかり固めないとCで書くのが大変になるので、詳細を詰めるときにまたやりなおすことにする。
2019-11-02 21:03
nice!(0)
コメント(0)
コメント 0