あるツールを使ってデータを記録したが、ツールに手を加えたためにデータの互換性がなくなってしまったのを「互換性がないなら、スクリプトで変更すればいいじゃない」という作業の流れを書きだしたものが、この記事です。
どういう仕組みで何を記録したのか
LMS511 という平面の距離を計測できるセンサがあるのですが、そのセンサとの通信内容を全て記録しました。通信データの記録は LMS11 から距離データを取得するために C++ で実装した Lms_driver というクラスで行なっています。
この Lms_driver クラスは Connection インターフェースを継承させていて、Connection インターフェースはセンサに対する open, read, write を提供します。そのため、Connection インターフェースの中身を差し替えることで、センサからのデータ取得、センサからデータを取得しつつログを記録、ログからデータを読み出して再生、ということが実現できます。
ただ、この仕組みでデータの記録と再生を実現しようとすると Lms_driver でセンサとの通信に使っているコマンドの順番を変えると記録済みのデータが再生できなくなる、という欠点があります。今回は、いろいろ機能を追加すべく Lms_driver を変更した結果、過去に記録したデータが再生できなくなってしまいました。
行う必要があること
過去の実装から変更した点は、センサに発行するコマンドを追加した程度なので、そのセンサからの応答を過去のデータに追加してしまえば O.K. です。
実際に行ったこと
LMS511 との通信は STX, ETX が付加された以外は普通の ASCII 文字列で行われるため、Ruby スクリプトを用いて必要な箇所を置換していくことにします。
具体的に行う処理は
- 追加したコマンドぶんの応答を追加
- データ取得コマンドの変更による、データ先頭のコマンド文字列の置換
くらいかな。
改めて書きだしてみると、大したことはないですね。作成するスクリプトの方針としては、引数で与えたファイルの内容を読み込んで、置換でどうにかすることにします。
まず、引数で与えたファイル名を読み出すあたりまでの実装は、こんな感じでしょうか?
# -*- coding: utf-8 -*-
# LMS のログデータを変換するスクリプト
# 引数で渡されたファイルを順に処理する
ARGV.each { |log_file|
original = File.open(log_file).read
# コマンドの応答を追加する
# !!!
# 必要な置換を行う
# !!!
}
次に、置換まわりのコードを追加します。(コードの一部の通信データを省略しています)
# -*- coding: utf-8 -*-
# LMS のログデータを変換するスクリプト
# 引数で渡されたファイルを順に処理する
ARGV.each { |log_file|
converted = File.open(log_file).read
# 最初のコマンド応答の部分を切り取る
converted.sub!(/.+?/, "")
# 必要な置換を行う
converted.gsub!(/sRA/, "sSN")
# 最初のコマンド応答を追加する
converted = "sRA (省略) sEA LMDscandata 1" + converted
# ファイル名を変更して出力する
output_file = "converted_" + log_file
File.open(output_file, "w").write(converted)
}
いつものことですが、実際に手を動かしてみると簡単です。
個人的には、面倒くさがらずに簡単ならもう少し早く取りかかれるようになりたいのですが「怠惰」はプログラマにとって美徳なので悩ましいところです。
まとめ
これからは怠惰な気持ちで楽することを考えつつも、実際には怠惰にならないようにする。