Imaginary Code

from kougaku-navi.net

Processingのシリアル通信で「Error, disabling serialEvent()」というエラーがでたら

ProcessingでArduinoとかとシリアル通信をやるとき、

Error, disabling serialEvent() for <ポート番号>

というエラーにでくわすことがあります。

なぜこのエラーがでるのか、なにを疑えばいいのか

このエラーメッセージを表示しているのは、Serialライブラリの以下の箇所です。

processing/Serial.java at master · processing/processing · GitHub

if (serialEventMethod != null) {
  if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer-readOffset) ||
    (0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer-1])) {
    try {
      // serialEvent() is invoked in the context of the current (serial) thread
      // which means that serialization and atomic variables need to be used to
      // guarantee reliable operation (and better not draw() etc..)
      // serialAvailable() does not provide any real benefits over using
      // available() and read() inside draw - but this function has no
      // thread-safety issues since it's being invoked during pre in the context
      // of the Processing applet
      serialEventMethod.invoke(parent, this);
    } catch (Exception e) {
      System.err.println("Error, disabling serialEvent() for "+port.getPortName());
      System.err.println(e.getLocalizedMessage());
      serialEventMethod = null;
    }
  }
}

このコードから、serialEvent()関数の実行により例外が発生したときにこのメッセージが表示されることがわかります。つまり、「Error, disabling serialEvent() 」というメッセージがでたら、serialEvent()関数の中で何かまずい処理をやっていないか疑うべきです。

エラーがでる例

ひとつ例を見てみましょう。以下のコードは一見すると問題なさそうに見えますが、実行すると「Error, disabling serialEvent() 」というエラーがでます。

import  processing.serial.*;
Serial  serial;

void setup() {  
  size(400,300);
  serial = new Serial( this, Serial.list()[0], 9600 );  // シリアル通信を設定
}

void draw() {
  background(0);
}

void serialEvent(Serial port) {
  if ( port.available() > 0 ) {                // データが受信されたら
    String recv = port.readStringUntil('\n');  // 改行まで文字列を読み込む
    recv = recv.replace("\n", "");             // 受信したデータから改行を消す
    println(recv);                             // 受信したデータを表示する
  }
}

原因はどこかと言うと、

    String recv = port.readStringUntil('\n');  // 改行まで文字列を読み込む
    recv = recv.replace("\n", "");             // 受信したデータから改行を消す

の部分です。

readStringUntil()の受信結果はnullになる可能性があり、recvがnullだった場合にreplace()のところでエラーが発生します。ここでせめて「NullPointerException」と言ってくれればすぐに気づきそうなものですが、「Error, disabling serialEvent() for <ポート番号>」と言われると通信エラーかな?と思ってしまいますし、通信相手のデバイスが悪いのかな? ケーブルが悪いのかな?とハードウェアのほうを疑いだすとなかなか気づけません。

たまにこの罠にひっかかるので備忘録として書きました。以上。