2015年12月10日木曜日

Excel VBA Win32API シリアル通信(続編)

Excel VBA いまさらの Win32API シリアル通信の続編

【やり残している事】
  • コマンド送信(WriteFile)してからレスポンス受信(ReadFile)まで100msのタイマ(Sleep)を入れる事でデータを取得できるようになったが、この100msを削りたい
  • レスポンスが無い場合(断線や、電池切れ)に対応が必要
【オシロスコープで調べた結果/100msが必要だった訳】
  • コマンドに対する反応時間は、変動するが50ms以内に全文字受信完了している
  • 従って、最後まで受信した後、ReadFile関数を起動していることになる
  • タイマが無い場合、ReadFile がタイムアウトして受信失敗する
    SetCommTimeouts の設定が不適切
【調べた事/同期I/Oと非同期I/O】
  • WriteFile, ReadFile には同期I/Oと非同期I/Oの使い方があり、
    ユーザーフォームのモーダルモーダレスの関係と似ている
  • 非同期I/Oで使用する場合は、OVERLAPPED構造体による指定が必要
  • 今回の要件からは、非同期I/Oにする必要は無いと思われる
【調べた事/イベント駆動】
  • タイマに頼らず、通信条件変更に対応するにはイベント駆動する必要がある
  • 同期I/Oと非同期I/Oどちらも使える
  • 送信し終わった(WaitCommEvent)(ただしライン上の信号は不明)
  • 受信開始はわかる(WaitCommEvent)
  • 受信文字数を予め調べることが出来る(ClearCommError)
【実施方針】
  • 100msタイマを置き換えられればいいだけなので、拘りすぎないで
【試行1】
  • ClearCommError で受信文字数を予め調べる方法
  • コマンド送信後100ms経過後に挿入しても、文字数ゼロで取得できず頓挫
  • 考えが変わり次の手へ
【試行2】
  • ReadFile 関数に規定の文字に達するまで受信する機能がある
  • 受信すべき文字数を設定すると100msタイマは不要となり、問題解決
  • 規定文字に達しない場合のタイムアウトの設定が必要
【試行3】
  • 変動要素の文字数より、決まっている最終文字でイベント発生すればいい
  • SetCommState関数のDCB構造体に、このイベント発生文字を指定
  • WaitCommEvent関数で待って、ReadFile へ
  • これは簡単に出来て、問題解決
【試行4】
  • 後の処理で受信文字数の算出は必要である
  • 従って、受信文字数を監視すればよく、試行3の WaitCommEventで最終文字を待って ReadFile する必要は無く、試行2の受信文字数で抜ければいい
  • ただし、すぐに ReadFile に入るので、待ち受け開始から受信終了までビジー状態が長く続く
  • 正常時はタイムアウトで抜けるのではなくて、最後の文字受信で抜けるから最速
  • レスポンスが無い場合に対応するため、タイムアウトの設定は必須
【レスポンスが無い場合】
  • WaitCommEvent はそれ自体にタイムアウトの設定が無いので
    レスポンスが無い場合にハングアップしないよう別途タイマ設定が必要になる
  • タイムアウトは、ReadFile だけで済むのだから イベント待ちする必要はない
    (レスボンスが返るまで長時間待つ場合はNG)
【タイマ/SetCommTimeouts の設定の確認】
  • コマンド送信と、レスポンス受信を100回繰り返すループにして、時間を計測した
  • 当初、10秒を超えていたが、4秒程度まで詰められた
  • タイマで抜ける方法より、規定文字数で抜ける方法が早い
  • タイマのインターバルの設定は、受信文字数で抜けない使い方の場合、最終文字かどうかは分からないのでこのタイムアウトが大きく影響するので、通信速度に応じて小さく
  • タイマの トータルの設定は、ReadFile 関数に指定した文字数に影響を受ける
【○○の手習い】
「この100msを削りたい」という問題解決のため、どうすればいいかを調べ始めるも、全く頭に入ってこない。同じことを何度も読み返したりしているうちに少しずつ言葉に慣れ、分からない事が何かが分かり始めた感じ。ネットの情報は多いのだが一気に解決に結びつくサイトやサンプルを今回は見つけられなくて、他言語の解説やMSDNの解説を眺めざるを得なかった(さらに分からなくなる)、で一進一退。
最近は、集中力が持続できず、他へ逃げてしまう自分との戦いになってきている気がする。