|
|
@@ -5,6 +5,7 @@ import com.epton.sdk.SerialPort
|
|
|
import com.grkj.data.data.MMKVConstants
|
|
|
import com.kongzue.dialogx.dialogs.PopTip
|
|
|
import com.sik.sikcore.extension.getMMKVData
|
|
|
+import com.sik.sikcore.extension.saveMMKVData
|
|
|
import com.sik.sikcore.thread.ThreadUtils
|
|
|
import org.slf4j.Logger
|
|
|
import org.slf4j.LoggerFactory
|
|
|
@@ -87,6 +88,7 @@ class PortManager private constructor(
|
|
|
* @param port 串口号,从 0 开始
|
|
|
* @param bps 波特率,正整数
|
|
|
*/
|
|
|
+ @JvmStatic
|
|
|
@WorkerThread
|
|
|
fun open(port: Int, bps: Int, usb: Boolean): PortManager? {
|
|
|
var blocked = true
|
|
|
@@ -118,6 +120,7 @@ class PortManager private constructor(
|
|
|
* @param port 串口号,从 0 开始
|
|
|
* @param bps 波特率,正整数
|
|
|
*/
|
|
|
+ @JvmStatic
|
|
|
@WorkerThread
|
|
|
fun open(port: String?, bps: Int): PortManager? {
|
|
|
if (port == null) {
|
|
|
@@ -148,23 +151,117 @@ class PortManager private constructor(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 自动扫描所有 ttyS/ttyUSB 口,尝试从机地址 1–0x16,找到第一个正确响应的设备。
|
|
|
+ */
|
|
|
+ @WorkerThread
|
|
|
+ @JvmStatic
|
|
|
+ fun detectSlave(baudRate: Int = 115200): String? {
|
|
|
+ val devs = File("/dev").listFiles { _, name ->
|
|
|
+ name.startsWith("ttyS") || name.startsWith("ttyUSB")
|
|
|
+ }?.map { it.absolutePath } ?: return null
|
|
|
+ val dockConfig = mutableListOf<DockBean>()
|
|
|
+ devs.forEach { path ->
|
|
|
+ try {
|
|
|
+ dockConfig.clear()
|
|
|
+ SerialPort(File(path), baudRate, 0).let { sp ->
|
|
|
+ val input = sp.inputStream
|
|
|
+ val output = sp.outputStream
|
|
|
+ val slaveInfo = path
|
|
|
+ for (addrInt in 1..0x16) {
|
|
|
+ checkSlave(addrInt, input, output, dockConfig)
|
|
|
+ }
|
|
|
+ checkSlave(0xA1, input, output, dockConfig)
|
|
|
+ if (slaveInfo.isNotEmpty() && dockConfig.isNotEmpty()) {
|
|
|
+ logger.info("扫描到设备:${slaveInfo},从机:${dockConfig}")
|
|
|
+ return slaveInfo
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e: Exception) {
|
|
|
+ logger.warn("扫描 $path 失败:${e.message}")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
- * 打开主控板
|
|
|
+ * 检查从机
|
|
|
+ */
|
|
|
+ private fun checkSlave(
|
|
|
+ addrInt: Int,
|
|
|
+ input: InputStream,
|
|
|
+ output: OutputStream,
|
|
|
+ dockConfig: MutableList<DockBean>
|
|
|
+ ) {
|
|
|
+ val addr = addrInt.toByte()
|
|
|
+ val cmdFrame = ModBusCMDHelper.generateReadDeviceTypeCmd()
|
|
|
+ val cmdBytes = cmdFrame.compile(addr)
|
|
|
+
|
|
|
+ output.write(cmdBytes)
|
|
|
+ output.flush()
|
|
|
+ // 简单阻塞读 7 字节
|
|
|
+ val buf = ByteArray(7)
|
|
|
+ var received = 0
|
|
|
+ while (received < buf.size) {
|
|
|
+ val n = input.read(buf, received, buf.size - received)
|
|
|
+ if (n <= 0) break
|
|
|
+ received += n
|
|
|
+ }
|
|
|
+ if (received == buf.size && buf[1] == 0x03.toByte()) {
|
|
|
+ val hi = buf[3].toInt() and 0xFF
|
|
|
+ val lo = buf[4].toInt() and 0xFF
|
|
|
+ val deviceType = (hi shl 8) or lo
|
|
|
+ dockConfig.add(
|
|
|
+ DockBean(
|
|
|
+ addr,
|
|
|
+ addrInt,
|
|
|
+ dockConfig.count { it.type == deviceType.toByte() } + 1,
|
|
|
+ deviceType.toByte(), deviceList = mutableListOf()
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 打开主控板:先自动检测,从机检测到后保存 MMKV,再打开。
|
|
|
+ */
|
|
|
+ /**
|
|
|
+ * 打开主控板:优先用缓存配置,失败后重新扫描并保存新配置
|
|
|
*/
|
|
|
@WorkerThread
|
|
|
+ @JvmStatic
|
|
|
fun openCtrlBord(): PortManager? {
|
|
|
- // TODO 端口号待定:大屏调试设备-1,小屏调试设备-0
|
|
|
-// val port = 4
|
|
|
-// val bps = 115200
|
|
|
-// val usb = true
|
|
|
-// LogUtil.i("主控板 port = ${port}, bps = ${bps}, usb = $usb")
|
|
|
-// return open(port, bps, usb)
|
|
|
- val port = MMKVConstants.KEY_PORT_CONFIG.getMMKVData("")
|
|
|
- val bps = 115200
|
|
|
- logger.info("主控板 port = $port, bps = $bps")
|
|
|
- return open(port, bps)
|
|
|
+ val baud = 115200
|
|
|
+
|
|
|
+ // 1. 先尝试用上次保存的路径打开
|
|
|
+ val savedPort = MMKVConstants.KEY_PORT_CONFIG.getMMKVData("")
|
|
|
+ if (savedPort.isNotEmpty()) {
|
|
|
+ logger.info("尝试打开上次缓存的串口: $savedPort, bps=$baud")
|
|
|
+ val pm = open(savedPort, baud)
|
|
|
+ if (pm != null) {
|
|
|
+ return pm
|
|
|
+ } else {
|
|
|
+ // 打开失败,清掉旧配置,提示一下
|
|
|
+ logger.warn("缓存的串口 $savedPort 打开失败,准备重新扫描")
|
|
|
+ MMKVConstants.KEY_PORT_CONFIG.saveMMKVData("")
|
|
|
+ PopTip.tip("主控板串口已变更,正在重新扫描…")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 缓存无效或打开失败,走自动扫描
|
|
|
+ val newPort = detectSlave(baud)
|
|
|
+ if (newPort != null) {
|
|
|
+ // 3. 扫描到就保存,下次直接用
|
|
|
+ MMKVConstants.KEY_PORT_CONFIG.saveMMKVData(newPort)
|
|
|
+ logger.info("扫描到新主控板串口: $newPort")
|
|
|
+ return open(newPort, baud)
|
|
|
+ } else {
|
|
|
+ PopTip.tip("未找到从机,请检查硬件连接")
|
|
|
+ return null
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|