pySerial でシリアルポートの入力を受け取る
仕事で使うためにシリアルポートからの入力を表示するコンソールのようなものを作りました。TeraTerm の簡易版みたいなものです。
pySerial モジュールを利用することでシリアルポートからのデータの受け取りはものすごく簡単に出来ます。通信に関するいくつかの設定が分かっていれば、 serial モジュールのクラス Serial のインスタンスを作成して、あとはファイルオブジェクトと同じ様にデータを取り出せます。
で、最初は以下のような方法で表示を行っていました。
class MainFrame(resource.xrcMainFrame): # スレッド処理関数 def run(self): while self.running: buf=self.com.readlines() self.text_ctrl.AppendText(buf)
しかしどうもこの方法だとデータが一気に押し寄せてきたときに取りこぼしが出てしまいます。そこで次のように変更しました。
class MainFrame(resource.xrcMainFrame): # 受信処理スレッド def receive(self): while self.running: buf=self.com.readlines() self.lock.acquire() self.buffer.append(buf) self.lock.release() # スレッド処理関数 def run(self): while self.running: self.lock.acquire() buf=self.buffer.pop(0) self.lock.release() self.text_ctrl.AppendText(buf)
リスト buffer を FIFO のキューとして用意し、受信処理とテキストコントロールにテキストを追加していく処理を別スレッドに分けました。このやり方で今のところは上手くいっているようです。
あと、このプログラムは GUI ですが、その終了処理部分は次のようになっています。
@binder(wx.EVT_WINDOW_DESTROY, id=XRCID('MainFrame') def Exit(self, evt): self.running=False # スレッドの while ループを抜けさせる self.thread.join() # テキストコントロールへの追加スレッドの終了待ち self.receiver.join() # 受信処理スレッドの終了待ち self.com.close() # シリアルポートを閉じる
スレッドの終了を待たないと、最後に受け取ったデータを既に破棄されてしまったテキストコントロールに追加しようとしてエラーが発生する場合があります。