1

RxTx 経由でデバイス (車の ECU、具体的にはELM327 ) に一度に複数のクエリを送信しようとしています。RxTx を利用するクラスは次のとおりです。

import collection.JavaConversions._
import gnu.io._
import java.io._
import java.util.TooManyListenersException

class Serial private (portName: String, 
                      baudRate: Int, 
                      dataBits: Int, 
                      stopBits: Int, 
                      parity: Int, 
                      flowControl: Int) {

  private val portId = CommPortIdentifier.getPortIdentifier(portName)
  private val serial = portId.open("Serial Connection from OBDScan", 
                                   5000).asInstanceOf[SerialPort]
  setPortParameters(baudRate, dataBits, stopBits, parity, flowControl)

  private val istream = serial.getInputStream
  private val ostream = serial.getOutputStream

  def this(portName: String, baudRate: Int = 115200) = this(portName, baudRate,
    SerialPort.DATABITS_8,
    SerialPort.STOPBITS_1,
    SerialPort.PARITY_NONE,
    SerialPort.FLOWCONTROL_NONE)

  def close = {
    try {
      istream.close
      ostream.close
    } catch {
      case ioe: IOException => // don't care, it's ended already
    }

    serial.close
  }

  def query(command: String) = {
    ostream.write(command.getBytes)
    ostream.write("\r\n".getBytes) // neccessary for Serial port.
  }

  def queryResult: String = {
    try {
      val availableBytes = istream.available
      val buffer = new Array[Byte](availableBytes)

      if (availableBytes > 0) {
        istream.read(buffer, 0, availableBytes)
      }
      new String(buffer, 0, availableBytes)
    } catch {
      case ioe: IOException => "Something wrong! Please try again."
    }
  }

  def addListener(listener: SerialPortEventListener) = {
    try {
      serial.addEventListener(listener)
      serial.notifyOnDataAvailable(true)
    } catch {
      case tm: TooManyListenersException => println("Too many listener")
    }
  }

  def removeListener = {
    serial.removeEventListener
  }

  private def setPortParameters(br: Int, 
                                db: Int, 
                                sb: Int, 
                                p: Int, 
                                fc: Int) = {
    serial.setSerialPortParams(baudRate, dataBits, stopBits, parity)
    serial.setFlowControlMode(flowControl)
  }
}

object Serial {
  def connect(portName: String, baudRate: Int = 115200): Serial = {
    try {
      val ret = new Serial(portName, baudRate)
      ret
    } catch {
      // exception handling omitted.
    }
  }
}

現在、クエリは正常に機能し、正しい結果が得られます。一度に複数のクエリを送信すると、問題が発生します。

val serial = Serial.connect("COM34")
serial.query("AT Z")
serial.query("10 00")

デバイスは両方のクエリを受け取りましたが、1 つの結果のみを返します。次の結果を取得したい場合は、別のクエリを送信する必要があります。これにより、プログラムはクエリが 1 つ遅れます。Thread.sleep各クエリの後に呼び出す場合:

val serial = Serial.connect("COM34")
serial.query("AT Z")
Thread.sleep(500)
serial.query("10 00")

問題は解決しましたが、もちろんThread.sleepが呼び出されるとアプリケーション全体が停止します。アプリケーションは常にこのクエリを実行するため、これは望ましくありません (これを行うと、常にハングアップすることを意味します)。

私はScalaなので、Actorsなどを使用することを考えていますが、デスクトップアプリケーションとしてはやり過ぎだと思います。アクターなしでこれを行う方法はありますか? たぶん、シリアルポートからの応答を間違って読んでいますか?

TL;DR:アプリケーション全体をロックせずに、RxTx 経由でシリアル デバイスにいくつかのクエリを実行したい (現在のソリューションはThread.sleep、アプリケーション全体をブロックします)。どうやってやるの?

4

0 に答える 0