So-net無料ブログ作成
検索選択

Raspberry Pi用pigpio Library - その6 [Raspberry Pi]

僕の今いる会社が今年に入って左前なので、去年まで専門の設備屋さんに投げていた新規製品用の調整設備や光学測定装置は、僕が自分で構想して組図を描いてバラシのメカ図面の漫画を描いて加工屋さんに加工図面を起こしてもらってそれで加工してもらって上がってきたらメカを組んで回路基板やケーブルを半田付けしてプログラムを書いて、と何から何まで全部やる事にした。そうすると設備屋さんに投げるのに比べて、見た目はカッコ悪いわ信頼性は低いわで人には見せられないけど、費用は2、3割で済ますことができる。

調整法と評価法の確立は光学設計の一部である、と普段から言っているのでその延長線上ではある。が、やはり時間はかなり取られてしまう。ここんとこずっと土日はホスト用のMacとハードウェア制御用のRaspberry Piのソフトを書くので潰れてしまっている。昨日今日もせっかく天気が良かったのに、ずっとうちでシコシコ過ごしてしまった。

それから解放されるためには会社が黒に浮かなければいけないけど、いつになるんだろう。それはいいとして、こんなことを繰り返してしまうと、僕がある日突然ボケたり、いや、それはもうすでにそうなってるのでそうではなくて、例えば僕が会社を辞めたり事故にでもあって死んだらどうするのか。でもまあそれは小さな会社ならどこでも同じかもしれないけど。

というようなことではあるけど、このブログではそんなことはどうでもよくて、pigpioライブラリの概観(その1その2その3その4その5)を続ける。前回コールバックは便利である、という話をした。実はpigpioのコールバックは前回のだけでなくて他にもいろいろ用意されていてなかなか面白い。今日はその残りについて....

2.6.4  signalによるコールバック

unixのsignalを受け取るとコールバックが呼ばれる。
int gpioSetSignalFunc(unsigned signum, gpioSignalFunc_t f);
int gpioSetSignalFuncEx(unsigned signum, gpioSignalFuncEx_t f, void *userdata);
これはどうやらsignalのsigactionのラッパになっているようなので、これもわかって使わないと痛い目にあう。

2.6.5  ISR割り込みによるコールバック

Linux固有の機能らしいsysfsというのを使うとpigpio標準のコールバックよりずっと速い(レイテンシは50μsecぐらいと言っている)コールバックができるらしい。
int gpioSetISRFunc(unsigned user_gpio,
                   unsigned edge,
                   int timeout,
                   gpioISRFunc_t f);
int gpioSetISRFuncEx(unsigned user_gpio,
                     unsigned edge,
                     int timeout,
                     gpioISRFuncEx_t f,
                     void *userdata);
使われているメカニズムが違うだけで動作はgpioSetAlertFunc()などと同じらしい。僕はsysfsというのを全然知らないし、速いけどなかなか中途半端なレイテンシで、これを使わなければならない動機も僕には今のところないので、必要な方の研究にお任せする。

2.6.6  タイマ

typedef void (*gpioTimerFunc_t) (void);
int gpioSetTimerFunc(unsigned timer, unsigned millis, gpioTimerFunc_t f);
timer引数で指定されたタイマ別にmsec単位で定期的に呼ばれる。タイマは0から9までの10個指定できるので10通りの時間間隔が指定できることになる。時間間隔は10msecから1分まで1msec刻みで指定できる。タイマを止めるためにはコールバックにNULLを指定する。

これもさっきのgpioSetAlertFunc()と同じメカニズムを使っているので最大で1msec遅れる可能性があるということになるが、制約のない割り込みとして使うことができる。つまり、OS X(macOS)のNSTimer、あるいはCFTimerと同じような使い方ができる。

タイマ動作というのは実装の下層では案外使うことが多いので、Raspberry Piではいろんなやり方で独自実装をしがちだけど、 こういう簡単な形で提供されているのは使い慣れると便利である。
同じようにRefConつきの
typedef void (*gpioTimerFuncEx_t) (void *userdata);
int gpioSetTimerFuncEx(unsigned timer,
                       unsigned millis,
                       gpioTimerFuncEx_t f,
                       void *userdata);
がある。

2.6.7  ウォッチドッグ

GPIOの特定のピンに対していわゆるウォッチドッグタイマ(Watchdog timer)が設定できる。
int gpioSetWatchdog(unsigned user_gpio, unsigned timeout);
指定したGPIOピンに、timeout引数で指定した時間(msec単位)以内にレベル変化がなかったとき、先にgpioSetAlertFunc()で指定しておいたコールバックが呼ばれる。

普通の組み込みシステムなんかでは最後の砦として、ハードウェアで実装されるけど、これはもちろんソフトウェアウォッチドッグである。外部ハードウェアとのやりとりの信頼性をあげたい、あるいは相手がハングする可能性がある場合などに使うのが普通だろうけど、他の使い方もできるかもしれない。それなりに大きなシステムでないと使い道はないけど、面白い機能である。

2.6.8  Notify

同じメカニズムを使って、GPIOピンに状態変化があったときに他のアプリケーションに知らせることができる。
int gpioNotifyOpen(void);
int gpioNotifyOpenWithSize(int bufSize);
int gpioNotifyBegin(unsigned handle, uint32_t bits);
int gpioNotifyPause(unsigned handle);
int gpioNotifyClose(unsigned handle);
これを使うには、まずgpioNotifyOpen()を呼ぶ。そうするとハンドル(unixのファイルディスクリプタと同じような正の整数値)が返る。例えばハンドルの値が3だったら
/dev/pigpio3
というデバイスファイルが作られる。これはまた例によって/dev以下にあるのでデバイスファイルみたいな気がするだけで、実体は名前付きパイプである。

そしてgpioNotifyBegin()を呼ぶ。ふたつめの引数bitsがGPIOのピン番号に対応していて、bitsに1が立ってるビット位置のピン番号にGPIOに変化があるとパイプに
typedef struct
{
   uint16_t seqno;
   uint16_t flags;
   uint32_t tick;
   uint32_t level;
} gpioReport_t;
という構造体が生で(テキストに変換されずに)書き込まれるので、他のアプリから読み出すことができる。この構造体は何回めの状態変化かを示すseqnoと、タイムスタンプや変化の値などが書かれている。

要するに自分自身がコールバックで知るのではなく、パイプを監視しているアプリに知らせるということができる。使い道としては作業ごとにプロセスを細かく分けて全体をシプルにする、というぐらいしか思い浮かばないけど、その場合は作業ごとの結びつきを弱くできるので、簡単に作業単位を取り替える必要があるときなんかに便利かもしれない。

本家の説明ではパイプだけでなくsocketにも対応していると書いてあるけど、どうやってsocketを呼ぶのかよくわからない。

2.6.9  sample

コールバックを総括するようなsampleと言うのがある。
int gpioSetGetSamplesFunc(gpioGetSamplesFunc_t f, uint32_t bits);
int gpioSetGetSamplesFuncEx(gpioGetSamplesFuncEx_t f, uint32_t bits, void *userdata);
このコールバック関数は
typedef void (*gpioGetSamplesFunc_t)
   (const gpioSample_t *samples, int numSamples);
typedef void (*gpioGetSamplesFuncEx_t)
   (const gpioSample_t *samples, int numSamples, void *userdata);
で、これには
typedef struct
{
   uint32_t tick;
   uint32_t level;
} gpioSample_t;
と言うような構造体の配列が渡される。

これは何をするものかというと、
  • あらかじめAlert(一番基本的なコールバック)が設定されている
  • あらかじめNotify(パイプ経由のコールバック)が設定されている
  • bits引数にピンの位置に対応するビットが立っている
のピンに変化があると、それらがすべて報告されるというもの。

コールバックは1msecに1回呼ばれて、それまでの1msec内のすべてのピンの変化とその時のタイムスタンプがぜんぶわかるようになっている。

これでどうこうする、というようなものではなくて、例えば何らかの変化があった時に表示を更新する、とかそういう副作用的なものだと思われるが、簡単な動作ならこれで済ませてしまうこともできる。

非常に親切ではある。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

メッセージを送る