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
、アプリケーション全体をブロックします)。どうやってやるの?