#android #android-studio #kotlin #serial-port
#Android #android-studio #kotlin #последовательный порт
Вопрос:
У меня есть приложение kotlin, которое имеет 4 датчика и около 120 числовых значений TextView (с цифровой чертой) и последовательный адаптер, который получает поток данных, затем декодирует его и отображает, затем получает больше данных и повторяет. Проблема в том, что дисплей никогда не обновляется, пока не будет остановлен последовательный поток. У меня есть управление потоком, но я не могу понять, как определить, когда экран был обновлен, или вставить задержку, чтобы экран догнал. Thread.sleep() не работает, поскольку, похоже, все останавливает, так же как и запуск счетчика до 100 миллионов или миллиардов. Использование последовательной библиотеки Mik3y. При использовании felHR85 экран работал, но управление потоком — нет. Я пытался использовать SerialInputOutputManager для получения прерываний при поступлении новых данных, но, похоже, у экрана все еще недостаточно времени для обновления. Использование Samsung Tab A 10.1, который находится на нижнем уровне, но должен иметь достаточную мощность на Android 10 (версия Sdk 30) Есть мысли? С наилучшими пожеланиями, Блейк, вот функция чтения, я думаю, вы правы, возможно, поможет перенести это в другой поток, я не уверен на 100%, как это сделать, и передать буфер массива (rsdash — это массив байтов из 8196) между потоками. Я также не уверен, как настроить поток.
fun receive(count: Int, timeout: Int): Int {
_serial.setRTS(true)
val startTime = System.currentTimeMillis()
val buffer = ByteArray(8196)
readBytes = 0
try {
while (readBytes <= count) {
val lend = _serial.read(buffer, timeout)
for (i in 0 until lend) {
rsdash[i readBytes] = buffer[i]
}
readBytes = readBytes lend
if (readBytes >= count) {
_serial.setRTS(false)
//if(count==387){display(rsdash)}
return readBytes
}
val duration = System.currentTimeMillis() - startTime
if (duration > timeout) {
_serial.setRTS(false)
break
}
}
_serial.setRTS(false)
return readBytes
} catch (e: IOException) {
_serial.setRTS(false)
return 0
}
}
// This code is not working, (no interupt, I assume) I am calling Receive() from the main program
val mListener: SerialInputOutputManager.Listener =
object : SerialInputOutputManager.Listener {
override fun onNewData(data: ByteArray) {
len = receive(387, 400)
_serial.write("0x52".toByteArray(), 2)
if (len == 387) {
chksum = 0
for (i in 0 until 384) chksum = chksum (rsdash[i].toInt() and 0xFF)
chksum = (chksum and 0xFFFF)
val chktst =
(rsdash[385].toInt() and 0xFF shl 8 or (rsdash[384].toInt() and 0xFF)).toInt()
if (chksum == chktst) {
cnt
display(rsdash)
Air2.setText(cnt.toString())
LED.setTextColor(Color.parseColor("#FF00FF"))
} else {
_serial.purgeHwBuffers(true, true)
// display(rsdash)
LED.setTextColor(Color.parseColor("#00FFFF"))
// _serial.purgeHwBuffers(true, true)
}
}
_serial.setRTS(true)
}
override fun onRunError(e: Exception) {
_serial.purgeHwBuffers(true, true)
_serial.setRTS(true)
}
}
// это также автоматически подключает последовательный порт, я также вызываю con =connect() из основной программы
broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == INTENT_ACTION_GRANT_USB) {
usbPermission = if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED,
false
)
) UsbPermission.Granted else UsbPermission.Denied
con=connect()
}
}
}
// Вот код в «главном», который работает. Как только цикл for завершен, экран обновляется. В области видимости все выглядит хорошо, все контрольные суммы пройдены.
if(con==false){con=connect()}
if (con == true) {
if (_connected == true) {
for (i in 0 until 200) {
// _serial.setRTS(true)
len = receive(387, 400)
_serial.write("0x52".toByteArray(), 2)
if (len == 387) {
chksum = 0
for (i in 0 until 384) chksum = chksum (rsdash[i].toInt() and 0xFF)
chksum = (chksum and 0xFFFF)
val chktst =
(rsdash[385].toInt() and 0xFF shl 8 or (rsdash[384].toInt() and 0xFF)).toInt()
if (chksum == chktst) {
cnt
display(rsdash)
Air2.setText(cnt.toString())
LED.setTextColor(Color.parseColor("#FF00FF"))
} else {
_serial.purgeHwBuffers(true, true)
// display(rsdash)
LED.setTextColor(Color.parseColor("#00FFFF"))
// _serial.purgeHwBuffers(true, true)
}
}
//The display function is long here are all the values on the display if that helps
val EgtA = findViewById<ProgressBar>(R.id.EgtA)
val EgtB = findViewById<ProgressBar>(R.id.EgtB)
val EgtC = findViewById<ProgressBar>(R.id.EgtC)
val EgtD = findViewById<ProgressBar>(R.id.EgtD)
val EgtE = findViewById<ProgressBar>(R.id.EgtE)
val EgtF = findViewById<ProgressBar>(R.id.EgtF)
val EgtG = findViewById<ProgressBar>(R.id.EgtG)
val EgtH = findViewById<ProgressBar>(R.id.EgtH)
val EgtAN = findViewById<TextView>(R.id.EgtAN)
val EgtBN = findViewById<TextView>(R.id.EgtBN)
val EgtCN = findViewById<TextView>(R.id.EgtCN)
val EgtDN = findViewById<TextView>(R.id.EgtDN)
val EgtEN = findViewById<TextView>(R.id.EgtEN)
val EgtFN = findViewById<TextView>(R.id.EgtFN)
val EgtGN = findViewById<TextView>(R.id.EgtGN)
val EgtHN = findViewById<TextView>(R.id.EgtHN)
val O2A = findViewById<ProgressBar>(R.id.O2A)
val O2B = findViewById<ProgressBar>(R.id.O2B)
val O2C = findViewById<ProgressBar>(R.id.O2C)
val O2D = findViewById<ProgressBar>(R.id.O2D)
val O2E = findViewById<ProgressBar>(R.id.O2E)
val O2F = findViewById<ProgressBar>(R.id.O2F)
val O2G = findViewById<ProgressBar>(R.id.O2G)
val O2H = findViewById<ProgressBar>(R.id.O2H)
val O2AN = findViewById<TextView>(R.id.O2AN)
val O2BN = findViewById<TextView>(R.id.O2BN)
val O2CN = findViewById<TextView>(R.id.O2CN)
val O2DN = findViewById<TextView>(R.id.O2DN)
val O2EN = findViewById<TextView>(R.id.O2EN)
val O2FN = findViewById<TextView>(R.id.O2FN)
val O2GN = findViewById<TextView>(R.id.O2GN)
val O2HN = findViewById<TextView>(R.id.O2HN)
val CFA = findViewById<TextView>(R.id.CFA)
val CFB = findViewById<TextView>(R.id.CFB)
val CFC = findViewById<TextView>(R.id.CFC)
val CFD = findViewById<TextView>(R.id.CFD)
val CFE = findViewById<TextView>(R.id.CFE)
val CFF = findViewById<TextView>(R.id.CFF)
val CFG = findViewById<TextView>(R.id.CFG)
val CFH = findViewById<TextView>(R.id.CFH)
val Pr1 = findViewById<TextView>(R.id.Pr1)
val Pr2 = findViewById<TextView>(R.id.Pr2)
val Pr3 = findViewById<TextView>(R.id.Pr3)
val Pr4 = findViewById<TextView>(R.id.Pr4)
val Pr5 = findViewById<TextView>(R.id.Pr5)
val throt = findViewById<ProgressBar>(R.id.throt)
val Throt = findViewById<TextView>(R.id.Throt)
val Flbs = findViewById<TextView>(R.id.Flbs)
val Afl = findViewById<TextView>(R.id.Afl)
val Tim = findViewById<TextView>(R.id.Tim)
val tach = findViewById<Gauge>(R.id.tach)
val fuel = findViewById<Gauge>(R.id.fuel)
val Inj = findViewById<TextView>(R.id.Inj)
val oil = findViewById<Gauge>(R.id.oil)
val eng = findViewById<Gauge>(R.id.eng)
val Batt = findViewById<TextView>(R.id.Batt)
val O2v = findViewById<TextView>(R.id.O2v)
val Map = findViewById<TextView>(R.id.Map)
val Mat = findViewById<TextView>(R.id.Mat)
val Baro = findViewById<TextView>(R.id.Baro)
val Air = findViewById<TextView>(R.id.Air)
val Air2 = findViewById<TextView>(R.id.Air2)
val CF = findViewById<TextView>(R.id.CF)
val TO2 = findViewById<TextView>(R.id.TO2)
val Oilt = findViewById<TextView>(R.id.Oilt)
val Trnt = findViewById<TextView>(R.id.Trnt)
val TTL = findViewById<TextView>(R.id.TTL)
val TTR = findViewById<TextView>(R.id.TTR)
val Cjl = findViewById<TextView>(R.id.Cjl)
val Cjr = findViewById<TextView>(R.id.Cjr)
val Cjs = findViewById<TextView>(R.id.Cjs)
val Sp1 = findViewById<TextView>(R.id.Sp1)
val Sp2 = findViewById<TextView>(R.id.Sp2)
val Sp3 = findViewById<TextView>(R.id.Sp3)
val Sp4 = findViewById<TextView>(R.id.Sp4)
val Sp5 = findViewById<TextView>(R.id.Sp5)
val Xa = findViewById<TextView>(R.id.Xa)
val Ya = findViewById<TextView>(R.id.Ya)
val Za = findViewById<TextView>(R.id.Za)
Комментарии:
1. Похоже, вам нужно прочитать поток в фоновом потоке и заставить его сообщать новые данные для пользовательского интерфейса в основном потоке, но нам нужно будет просмотреть ваш код, чтобы понять, как это нужно исправить.
Ответ №1:
Я не уверен, правильно ли я это сделал, но он работает, и, похоже, он поместил последовательный приемник в отдельный поток. Вот код для справки.
fun connect(): Boolean {
val drivers = UsbSerialProber.getDefaultProber().findAllDrivers(_usbManager)
if (drivers.isEmpty()) {
return false
}
val driver = drivers[0]
val _connection = _usbManager.openDevice(driver.device)
if (_connection == null) {
_connected = false
return false
}
val port = driver.ports[0]
if (port == null) {
_connected = false
return false
}
try {
port.open(_connection)
port.setParameters(
115200,
8,
UsbSerialPort.STOPBITS_1,
UsbSerialPort.PARITY_NONE
)
port.purgeHwBuffers(true, true)
_serial = port
_connected = true
// if (withIoManager) {
// usbIoManager = SerialInputOutputManager(usbSerialPort)
// Executors.newSingleThreadExecutor().submit(usbIoManager)
// }
//usbIoManager = SerialInputOutputManager(_serial,this)
usbIoManager = SerialInputOutputManager(_serial, mListener)
Executors.newSingleThreadExecutor().submit(usbIoManager)
// val submit = Executors.newSingleThreadExecutor().submit(usbIoManager)
// Executors.newSingleThreadExecutor().asCoroutineDispatcher(usbIoManager)
_serial.setRTS(true)
return true
} catch (e: IOException) {
//e.printStackTrace()
if(_connected==true){port.close()}
_connected = false
return false
}
}
// mainLooper = Handler(Looper.getMainLooper())
broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == INTENT_ACTION_GRANT_USB) {
usbPermission = if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED,
false
)
) UsbPermission.Granted else UsbPermission.Denied
con=connect()
}
}
}
//mainLooper = Handler(Looper.getMainLooper())