Преглед изворни кода

refactor(更新)
- 设备初始化基本完成

周文健 пре 4 месеци
родитељ
комит
e341090cba
23 измењених фајлова са 581 додато и 443 уклоњено
  1. 13 2
      app/src/main/java/com/grkj/iscs/ISCSApplication.kt
  2. 4 0
      app/src/main/java/com/grkj/iscs/features/init/activity/InitActivity.kt
  3. 16 1
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt
  4. 11 0
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitPointRfidRegistrationFragment.kt
  5. 7 7
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitWelcomeFragment.kt
  6. 47 34
      app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt
  7. 20 0
      app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitViewModel.kt
  8. 0 1
      app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt
  9. 1 1
      app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/UpdateRoleDialog.kt
  10. 4 0
      app/src/main/java/com/grkj/iscs/features/splash/activity/SplashActivity.kt
  11. 1 0
      app/src/main/res/layout/fragment_init_device_registration_key_and_lock.xml
  12. 5 0
      data/src/main/java/com/grkj/data/data/EventConstants.kt
  13. 1 1
      data/src/main/java/com/grkj/data/database/ISCSDatabase.kt
  14. 189 229
      ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt
  15. 1 1
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt
  16. 19 7
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt
  17. 24 0
      ui-base/src/main/java/com/grkj/ui_base/utils/event/ModbusInitCompleteEvent.kt
  18. 1 1
      ui-base/src/main/java/com/grkj/ui_base/utils/event/StartModbusEvent.kt
  19. 6 5
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt
  20. 15 0
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusCMDHelper.kt
  21. 49 25
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt
  22. 2 3
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusManager.kt
  23. 145 125
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/PortManager.kt

+ 13 - 2
app/src/main/java/com/grkj/iscs/ISCSApplication.kt

@@ -7,6 +7,7 @@ import com.grkj.data.data.EventConstants
 import com.grkj.data.di.RepositoryManager
 import com.grkj.shared.model.EventBean
 import com.grkj.ui_base.business.ModbusBusinessManager
+import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.ble.BleUtil
 import com.grkj.ui_base.utils.modbus.ModBusController
 import com.kongzue.dialogx.DialogX
@@ -21,9 +22,12 @@ import com.scwang.smart.refresh.layout.listener.DefaultRefreshHeaderCreator
 import com.sik.sikcore.SIKCore
 import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.HiltAndroidApp
+import kotlinx.coroutines.delay
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
 
 
 /**
@@ -31,6 +35,8 @@ import org.greenrobot.eventbus.ThreadMode
  */
 @HiltAndroidApp
 class ISCSApplication : Application() {
+    private val logger: Logger = LoggerFactory.getLogger(ISCSApplication::class.java)
+
     /**
      * 程序创建
      */
@@ -43,8 +49,9 @@ class ISCSApplication : Application() {
         if (!EventBus.getDefault().isRegistered(this)) {
             EventBus.getDefault().register(this)
         }
-        BleUtil.instance.initBle(this)
+        BleUtil.instance?.initBle(this)
         ThreadUtils.runOnIO {
+            ModbusBusinessManager.registerMainListener()
             RepositoryManager.init(this@ISCSApplication)
         }
     }
@@ -54,9 +61,13 @@ class ISCSApplication : Application() {
         when (event.code) {
             EventConstants.EVENT_START_MODBUS -> {
                 ThreadUtils.runOnIO {
+                    ModBusController.interruptReadTrashBinStatus(false)
                     ModBusController.start()
+                    if (!ISCSConfig.isInit) {
+                        delay(10_000)
+                    }
+                    logger.info("Application 连接完成,开始初始化")
                     ModBusController.initDevicesStatus()
-                    ModbusBusinessManager.registerMainListener()
                 }
             }
         }

+ 4 - 0
app/src/main/java/com/grkj/iscs/features/init/activity/InitActivity.kt

@@ -45,4 +45,8 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
         return super.dispatchKeyEvent(event)
     }
 
+    fun clearCardNo() {
+        cardNo = ""
+    }
+
 }

+ 16 - 1
app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt

@@ -9,6 +9,7 @@ import com.drake.brv.utils.dividerSpace
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
 import com.drake.brv.utils.setup
+import com.grkj.data.data.EventConstants
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentInitDeviceRegistrationKeyAndLockBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyBinding
@@ -17,12 +18,14 @@ import com.grkj.iscs.databinding.ItemDeviceRegistrationLockBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationLockLayoutBinding
 import com.grkj.iscs.features.init.model.DockData
 import com.grkj.iscs.features.init.viewmodel.InitDeviceRegistrationKeyAndLockViewModel
+import com.grkj.shared.model.EventBean
 import com.grkj.ui_base.base.BaseFragment
 import com.grkj.ui_base.utils.modbus.DeviceConst
 import com.grkj.ui_base.utils.modbus.DockBean
 import com.grkj.ui_base.utils.modbus.ModBusController
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.extension.setDebouncedClickListener
+import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.AndroidEntryPoint
 
 /**
@@ -76,6 +79,8 @@ class InitDeviceRegistrationKeyAndLockFragment :
             }
         }
         viewModel.isLoadComplete.observe(this) {
+            binding.stepHint.text = if (!it)getString(R.string.init_device_registration_key_and_lock_step_hint) else getString(R.string.init_device_registration_key_and_lock_complete_step_hint)
+            binding.reRecognize.isVisible = it
             val dockData =
                 ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
             val keyDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.map {
@@ -163,6 +168,17 @@ class InitDeviceRegistrationKeyAndLockFragment :
             }.models = portableDock.deviceData
     }
 
+    override fun onEvent(event: EventBean<Any>) {
+        super.onEvent(event)
+        when(event.code){
+            EventConstants.EVENT_START_MODBUS->{
+                ThreadUtils.runOnMainDelayed(1000) {
+                    viewModel.isStartCheckKey = false
+                }
+            }
+        }
+    }
+
     override fun onResume() {
         super.onResume()
         viewModel.clearKeyAndLock()
@@ -172,7 +188,6 @@ class InitDeviceRegistrationKeyAndLockFragment :
     override fun onDestroyView() {
         viewModel.isDestroy = true
         viewModel.unregisterInitListener()
-        viewModel.closeModbus()
         super.onDestroyView()
     }
 }

+ 11 - 0
app/src/main/java/com/grkj/iscs/features/init/fragment/InitPointRfidRegistrationFragment.kt

@@ -6,21 +6,27 @@ import com.drake.brv.BindingAdapter
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.setup
 import com.grkj.data.data.EventConstants
+import com.grkj.data.data.MMKVConstants
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentInitPointRfidRegistrationBinding
 import com.grkj.iscs.databinding.ItemInitHardwareRfidBinding
+import com.grkj.iscs.features.init.activity.InitActivity
 import com.grkj.iscs.features.init.viewmodel.InitViewModel
 import com.grkj.iscs.features.login.activity.LoginActivity
 import com.grkj.shared.model.EventBean
 import com.grkj.ui_base.base.BaseFragment
 import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.event.CardSwipeEvent
+import com.sik.sikcore.extension.saveMMKVData
 import com.sik.sikcore.extension.setDebouncedClickListener
+import dagger.hilt.android.AndroidEntryPoint
+import razerdp.util.KeyboardUtils
 import kotlin.getValue
 
 /**
  * 点位rfid录入
  */
+@AndroidEntryPoint
 class InitPointRfidRegistrationFragment : BaseFragment<FragmentInitPointRfidRegistrationBinding>() {
     private val viewModel: InitViewModel by viewModels()
 
@@ -33,11 +39,13 @@ class InitPointRfidRegistrationFragment : BaseFragment<FragmentInitPointRfidRegi
     }
 
     override fun initView() {
+        (requireActivity() as InitActivity).clearCardNo()
         binding.previousBtn.setDebouncedClickListener {
             navController.popBackStack()
         }
         binding.nextBtn.setDebouncedClickListener {
             viewModel.registrationPointRfidHardware(pointRfidData).observe(this) {
+                MMKVConstants.APP_INIT.saveMMKVData(true)
                 requireActivity().startActivity(
                     Intent(
                         requireActivity(),
@@ -48,6 +56,7 @@ class InitPointRfidRegistrationFragment : BaseFragment<FragmentInitPointRfidRegi
             }
         }
         binding.skipAndComplete.setDebouncedClickListener {
+            MMKVConstants.APP_INIT.saveMMKVData(true)
             requireActivity().startActivity(Intent(requireActivity(), LoginActivity::class.java))
             requireActivity().finish()
         }
@@ -57,6 +66,7 @@ class InitPointRfidRegistrationFragment : BaseFragment<FragmentInitPointRfidRegi
                 onInitHardwareBinding(this)
             }
         }.models = pointRfidData
+        viewModel.removeRfidTokenData().observe(this){}
     }
 
     private fun BindingAdapter.BindingViewHolder.onInitHardwareBinding(holder: BindingAdapter.BindingViewHolder) {
@@ -76,6 +86,7 @@ class InitPointRfidRegistrationFragment : BaseFragment<FragmentInitPointRfidRegi
                 val cardSwipeEvent = (event.data as CardSwipeEvent)
                 pointRfidData.add(cardSwipeEvent.cardNo)
                 binding.pointRfidRv.adapter?.notifyDataSetChanged()
+                KeyboardUtils.close(requireActivity())
             }
         }
     }

+ 7 - 7
app/src/main/java/com/grkj/iscs/features/init/fragment/InitWelcomeFragment.kt

@@ -4,11 +4,10 @@ import androidx.fragment.app.viewModels
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentInitWelcomeBinding
 import com.grkj.iscs.features.init.viewmodel.InitDeviceRegistrationKeyAndLockViewModel
-import com.grkj.iscs.features.init.viewmodel.InitViewModel
 import com.grkj.ui_base.base.BaseFragment
+import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.extension.setDebouncedClickListener
 import com.sik.sikcore.thread.ThreadUtils
-import com.tencent.mmkv.MMKV
 import dagger.hilt.android.AndroidEntryPoint
 
 /**
@@ -23,13 +22,14 @@ class InitWelcomeFragment : BaseFragment<FragmentInitWelcomeBinding>() {
 
     override fun initView() {
         binding.titleCn.setDebouncedClickListener {
-            MMKV.defaultMMKV().clearAll()
+            viewModel.clearDockConfig().observe(this) {
+                PopTip.tip("开始重新检测")
+            }
         }
         binding.titleEn.setDebouncedClickListener {
-            viewModel.deleteKey()
-        }
-        ThreadUtils.runOnIO {
-            viewModel.openAndDetectSlave()
+            viewModel.deleteKey().observe(this) {
+                PopTip.tip("清除成功")
+            }
         }
         binding.startBtn.setDebouncedClickListener {
             navController.navigate(R.id.action_initWelcomeFragment_to_initSetAdminAccountFragment)

+ 47 - 34
app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt

@@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.liveData
 import com.clj.fastble.BleManager
+import com.grkj.data.data.MMKVConstants
 import com.grkj.data.repository.IHardwareRepository
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.ModbusBusinessManager
@@ -12,11 +13,11 @@ import com.grkj.ui_base.utils.modbus.DeviceConst
 import com.grkj.ui_base.utils.modbus.DockBean
 import com.grkj.ui_base.utils.modbus.ModBusController
 import com.sik.sikcore.thread.ThreadUtils
+import com.tencent.mmkv.MMKV
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.suspendCancellableCoroutine
-import razerdp.util.KeyboardUtils
 import java.util.concurrent.atomic.AtomicInteger
 import javax.inject.Inject
 import kotlin.coroutines.resume
@@ -32,56 +33,42 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     private val newHardwareKeyBean: MutableMap<Byte, MutableList<DockBean.KeyBean>> = mutableMapOf()
     private val alreadyUsedMac: MutableList<String> = mutableListOf()
 
-    /**
-     * 打开并检测从机
-     */
-    fun openAndDetectSlave() {
-        ModBusController.start()
-        ModBusController.controlKeyCharge(true,0,0x01)
-        ModBusController.controlKeyCharge(true,1,0x01)
-        ModBusController.controlKeyCharge(true,0,0x02)
-        ModBusController.controlKeyCharge(true,1,0x02)
-        ModBusController.controlKeyBuckle(true,0,0x01)
-        ModBusController.controlKeyBuckle(true,1,0x01)
-        ModBusController.controlKeyBuckle(true,0,0x02)
-        ModBusController.controlKeyBuckle(true,1,0x02)
-        ModBusController.initDevicesStatus()
-        ModbusBusinessManager.registerMainListener()
-    }
-
     fun checkNewHardware(device: DockBean.DeviceBean, callback: () -> Unit) {
         if (device is DockBean.KeyBean) {
             device.mac = null
             hardwareRepository.getKeyInfo(device.rfid.toString()) {
-                device.newHardware = it == null
+                device.newHardware =
+                    it?.keyNfc?.isEmpty() == true || it?.macAddress?.isEmpty() == true
                 device.mac = it?.macAddress
                 callback()
             }
         } else if (device is DockBean.LockBean) {
             hardwareRepository.getLockInfo(device.rfid.toString()) {
-                device.newHardware = it == null
+                device.newHardware = it?.lockNfc?.isEmpty() == true
                 callback()
             }
         }
     }
 
+    /**
+     * 注册监听
+     */
     fun registerInitListener(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             isStartCheckKey = false
             newHardwareKeyBean.clear()
             alreadyUsedMac.clear()
             isLoadComplete.postValue(false)
-            val allDeviceCloseCmdSend =
-                BleConnectionManager.scanOnlineKeyLockMacAndSwitchModeToClose()
-            logger.info("设备录入-是否所有关闭命令发送成功:${allDeviceCloseCmdSend}")
-            BleManager.getInstance().disconnectAllDevice()
-            logger.info("断开所有蓝牙设备")
-            ModBusController.registerStatusListener(this) {
+            ModbusBusinessManager.registerInitListener {
                 if (isStartCheckKey) {
-                    return@registerStatusListener
+                    return@registerInitListener
                 }
                 isStartCheckKey = true
                 val dockList = ModBusController.dockList
+                if (dockList.size < DockBean.dockConfig.size) {
+                    isStartCheckKey = false
+                    return@registerInitListener
+                }
                 ThreadUtils.runOnIO {
                     val allDevice = ModBusController.dockList.map { it.deviceList }.flatten()
                         .filter { it is DockBean.KeyBean || it is DockBean.LockBean }
@@ -101,6 +88,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         }
     }
 
+    /**
+     * 检查钥匙是否是新设备
+     */
     private fun checkNewHardwareKey(dockList: MutableList<DockBean>) {
         ThreadUtils.runOnIO {
             logger.info("设备录入-重新检测是否是新设备完成")
@@ -115,6 +105,13 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
                     .map { it.deviceList }.flatten().filterIsInstance<DockBean.KeyBean>()
                     .filter { it.mac?.isNotEmpty() == true }.mapNotNull { it.mac }
             )
+            if (newHardwareKeyBean.isNotEmpty()) {
+                val allDeviceCloseCmdSend =
+                    BleConnectionManager.scanOnlineKeyLockMacAndSwitchModeToClose()
+                logger.info("设备录入-是否所有关闭命令发送成功:${allDeviceCloseCmdSend}")
+                BleManager.getInstance().disconnectAllDevice()
+                logger.info("断开所有蓝牙设备")
+            }
             logger.debug("设备录入-新设备:${newHardwareKeyBean}")
             for ((addr, keyBeans) in newHardwareKeyBean) {
                 for (keyBean in keyBeans) {
@@ -202,8 +199,11 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         }
     }
 
+    /**
+     * 取消监听
+     */
     fun unregisterInitListener() {
-        ModBusController.unregisterListener(this)
+        ModbusBusinessManager.unRegisterInitListener()
     }
 
     /**
@@ -260,6 +260,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         }
     }
 
+    /**
+     * 清除钥匙和挂锁的表
+     */
     fun clearKeyAndLock(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             hardwareRepository.clearKeyAndLock()
@@ -267,15 +270,25 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         }
     }
 
-    fun closeModbus() {
-        ModBusController.stop()
-        ModbusBusinessManager.unregisterMainListener()
+    /**
+     * 删除钥匙表
+     */
+    fun deleteKey(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            hardwareRepository.deleteKeyTable()
+            emit(true)
+        }
     }
 
     /**
-     * 删除钥匙表
+     * 清除基座和配置数据重新开始
      */
-    fun deleteKey() {
-        hardwareRepository.deleteKeyTable()
+    fun clearDockConfig(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            MMKV.defaultMMKV().removeValueForKey(MMKVConstants.KEY_PORT_CONFIG)
+            MMKV.defaultMMKV().removeValueForKey(MMKVConstants.KEY_DOCK_CONFIG)
+            ModBusController.interruptReadTrashBinStatus(false)
+            emit(true)
+        }
     }
 }

+ 20 - 0
app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitViewModel.kt

@@ -60,4 +60,24 @@ class InitViewModel @Inject constructor(
             emit(true)
         }
     }
+
+    /**
+     * 移除卡片数据
+     */
+    fun removeCardData(): LiveData<Boolean>{
+        return liveData(Dispatchers.IO){
+            hardwareRepository.removeCardData()
+            emit(true)
+        }
+    }
+
+    /**
+     * 移除rfidToken数据
+     */
+    fun removeRfidTokenData(): LiveData<Boolean>{
+        return liveData(Dispatchers.IO){
+            hardwareRepository.removeRfidTokenData()
+            emit(true)
+        }
+    }
 }

+ 0 - 1
app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt

@@ -71,7 +71,6 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
                 onLoginMenuBinding(this)
             }
         }
-        StartModbusEvent.sendStartModbusEvent()
     }
 
     private fun BindingAdapter.BindingViewHolder.onLoginMenuBinding(holder: BindingAdapter.BindingViewHolder) {

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/UpdateRoleDialog.kt

@@ -222,7 +222,7 @@ class UpdateRoleDialog(context: Context) : BasePopupWindow(context) {
         binding.roleNameEt.setText(updateRoleDataEntity.roleName)
         binding.roleKeyEt.setText(updateRoleDataEntity.roleKeys)
         binding.activateRb.isChecked = updateRoleDataEntity.status == true
-        binding.roleNameEt.isEnabled = updateRoleDataEntity.isPreset ==false
+        binding.roleKeyEt.isEnabled = updateRoleDataEntity.isPreset ==false
         this.selectedPermission.clear()
         this.selectedPermission.addAll(getSelectedData(updateRoleDataEntity.functionalPermissions))
         setSelectedData(roleManageFunctionalPermissionsData)

+ 4 - 0
app/src/main/java/com/grkj/iscs/features/splash/activity/SplashActivity.kt

@@ -9,6 +9,7 @@ import com.grkj.iscs.features.init.activity.InitActivity
 import com.grkj.iscs.features.login.activity.LoginActivity
 import com.grkj.iscs.features.splash.viewmodel.SplashViewModel
 import com.grkj.ui_base.base.BaseActivity
+import com.grkj.ui_base.utils.event.StartModbusEvent
 import com.sik.sikcore.extension.getMMKVData
 import dagger.hilt.android.AndroidEntryPoint
 
@@ -20,12 +21,15 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>() {
     }
 
     override fun initView() {
+        StartModbusEvent.sendStartModbusEvent()
         viewModel.checkSysMenuAndRole().observe(this){
             val isAppInit = MMKVConstants.APP_INIT.getMMKVData(false)
             if (isAppInit){
                 startActivity(Intent(this, LoginActivity::class.java))
+                finish()
             }else{
                 startActivity(Intent(this, InitActivity::class.java))
+                finish()
             }
         }
     }

+ 1 - 0
app/src/main/res/layout/fragment_init_device_registration_key_and_lock.xml

@@ -111,6 +111,7 @@
             android:text="@string/re_recognize"
             android:textColor="@color/black"
             android:textSize="@dimen/common_btn_text_size"
+            android:visibility="gone"
             app:layout_constraintTop_toBottomOf="@+id/next_btn"
             app:layout_constraintStart_toStartOf="@+id/previous_btn"
             app:layout_constraintEnd_toEndOf="@+id/next_btn"

+ 5 - 0
data/src/main/java/com/grkj/data/data/EventConstants.kt

@@ -46,6 +46,11 @@ object EventConstants {
      */
     const val EVENT_START_MODBUS = 100_000_008
 
+    /**
+     * 启动串口完成
+     */
+    const val EVENT_START_MODBUS_COMPLETE = 100_000_009
+
     //---------------------------作业票------------------------
     const val EVENT_GET_TICKET_STATUS: Int = 100_001_001
 

+ 1 - 1
data/src/main/java/com/grkj/data/database/ISCSDatabase.kt

@@ -67,7 +67,7 @@ abstract class ISCSDatabase : RoomDatabase() {
                 SIKCore.getApplication(), ISCSDatabase::class.java, "iscs_database"
             ).apply {
                 if (Constants.DEBUG) {
-                    fallbackToDestructiveMigration(true)
+//                    fallbackToDestructiveMigration(true)
                 }
 
             }.createFromAsset("data.db").build()

+ 189 - 229
ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt

@@ -43,6 +43,8 @@ object ModbusBusinessManager {
 
     private val listeners = ArrayList<DeviceListener>()
 
+    private var initListener: (() -> Unit)? = null
+
     /**
      * 注册状态监听
      */
@@ -62,6 +64,20 @@ object ModbusBusinessManager {
         }
     }
 
+    /**
+     * 注册初始化监听
+     */
+    fun registerInitListener(listener: () -> Unit) {
+        this.initListener = listener
+    }
+
+    /**
+     * 取消注册初始化监听
+     */
+    fun unRegisterInitListener() {
+        this.initListener = null
+    }
+
     /**
      * 添加待更新取出状态的设备
      */
@@ -207,6 +223,7 @@ object ModbusBusinessManager {
 
                 // —— 在 Default 线程做计算密集操作 ——
                 val lockMap = withContext(Dispatchers.Default) {
+                    logger.info("获取锁具数量:${needLockCount}")
                     ModBusController.getLocks(
                         needLockCount,
                         slotsPage?.records?.filter {
@@ -287,156 +304,13 @@ object ModbusBusinessManager {
             when (dockBean.type) {
                 DeviceConst.DOCK_TYPE_KEY -> {
                     dockBean.getKeyList().forEach { keyBean ->
-                        if (keyBean.isExist) {
-                            // 放回钥匙,读取rfid
-                            ModBusController.readKeyRfid(
-                                dockBean.addr, keyBean.idx
-                            ) { idx, res ->
-                                if (ISCSConfig.isInit){
-                                    ModBusController.controlKeyCharge(
-                                        true, keyBean.idx, dockBean.addr
-                                    )
-                                }
-                                if (res.size < 11) {
-                                    logger.error("Key rfid error")
-                                    return@readKeyRfid
-                                }
-                                val rfid =
-                                    res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
-                                ModBusController.updateKeyRfid(
-                                    dockBean.addr, keyBean.idx, rfid
-                                )
-                                ThreadUtils.runOnIO {
-                                    val slotStatus =
-                                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_STATUS) }
-                                    val slotType =
-                                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_TYPE) }
-                                    val slotsPageReq = async { DataBusiness.getSlotsPage() }
-                                    val keyStatusReq =
-                                        async { DataBusiness.fetchDict(DictConstants.KEY_KEY_STATUS) }
-                                    val keyPageReq = async { DataBusiness.getKeyPage() }
-                                    var keyStatus = keyStatusReq.await()
-                                    var keyData = keyPageReq.await()
-                                    val slotsPage = slotsPageReq.await()
-                                    val slotStatusList = slotStatus.await()
-                                    val slotTypeList = slotType.await()
-                                    //锁钥匙未异常正常请求锁数据,关锁
-                                    if (rfid in (keyData?.records?.filter { it.exStatus == keyStatus.find { it.dictLabel == "异常" }?.dictValue }
-                                            ?.map { it.keyNfc }?.toMutableList()
-                                            ?: mutableListOf())
-                                    ) {
-                                        PopTip.tip(
-                                            CommonUtils.getStr(R.string.key_exception_tag)
-                                        )
-                                    } else if (slotsPage?.records?.filter {
-                                            it.slotType == slotTypeList.find { d -> d.dictLabel == "钥匙" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
-                                        }
-                                            ?.find { it.row?.toInt() == dockBean.row && it.col?.toInt() == (dockBean.col + (keyBean.idx) * 2) } != null) {
-                                        PopTip.tip(
-                                            CommonUtils.getStr(R.string.slot_exception_tag)
-                                        )
-                                    } else {
-                                        // 放回钥匙,上锁
-                                        ModBusController.controlKeyBuckle(
-                                            false, keyBean.idx, dockBean.addr
-                                        ) {
-                                            RepositoryManager.hardwareRepo.getKeyInfo(rfid) {
-                                                if (it != null && !it.macAddress.isNullOrEmpty()) {
-                                                    ModBusController.updateKeyMac(
-                                                        dockBean.addr,
-                                                        keyBean.idx,
-                                                        it.macAddress ?: ""
-                                                    )
-                                                    ModBusController.updateKeyReadyStatus(
-                                                        it.macAddress ?: "", false, 5
-                                                    )
-                                                } else {
-                                                    logger.error("Get key info fail : $rfid")
-                                                    PopTip.tip(R.string.get_key_info_fail)
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        } else if (!keyBean.isCharging) {//增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
-                            // 移出待连监听集合,防止connectKey循环失败
-                            keyBean.mac?.let {
-                                BleConnectionManager.unregisterConnectListener(it)
-                            }
-                            DeviceTakeUpdateEvent.sendDeviceTakeEvent(
-                                DeviceConst.DEVICE_TYPE_KEY,
-                                keyBean.rfid
-                            )
-                        }
+                        deviceKeyHandler(dockBean, keyBean)
                     }
                 }
 
                 DeviceConst.DOCK_TYPE_LOCK -> {
                     dockBean.getLockList().forEach { lockBean ->
-                        if (lockBean.isExist) {
-                            ModBusController.readLockRfid(dockBean.addr, lockBean.idx) { res ->
-                                if (res.size < 11) {
-                                    logger.error("Lock rfid error")
-                                    return@readLockRfid
-                                }
-                                val rfid =
-                                    res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
-                                ModBusController.updateLockRfid(
-                                    dockBean.addr, lockBean.idx, rfid
-                                )
-                                ThreadUtils.runOnIO {
-                                    val lockStatusReq =
-                                        async { DataBusiness.fetchDict(DictConstants.KEY_PAD_LOCK_STATUS) }
-                                    val slotStatus =
-                                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_STATUS) }
-                                    val slotType =
-                                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_TYPE) }
-                                    val slotsPageReq = async { DataBusiness.getSlotsPage() }
-                                    var lockStatus = lockStatusReq.await()
-                                    val slotsPage = slotsPageReq.await()
-                                    val slotStatusList = slotStatus.await()
-                                    val slotTypeList = slotType.await()
-                                    RepositoryManager.hardwareRepo.getIsLockPage { lockData ->
-                                        //锁rfid未异常正常请求锁数据,关锁
-                                        if (rfid in (lockData?.records?.filter { it.exStatus == lockStatus.find { it.dictLabel == "异常" }?.dictValue }
-                                                ?.map { it.lockNfc }?.toMutableList()
-                                                ?: mutableListOf())
-                                        ) {
-                                            PopTip.tip(R.string.lock_exception_tag)
-                                        } else if (slotsPage?.records?.filter {
-                                                it.slotType == slotTypeList.find { d -> d.dictLabel == "锁" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
-                                            }
-                                                ?.find { it.row?.toInt() == dockBean.row && (lockBean.idx + 1) == it.col?.toInt() } != null) {
-                                            PopTip.tip(R.string.slot_exception_tag)
-                                        } else {
-                                            RepositoryManager.hardwareRepo.getLockInfo(rfid) {
-                                                if (it != null) {
-                                                    // TODO 考虑快速拿取
-                                                    ModBusController.controlLockBuckle(
-                                                        false, dockBean.addr, lockBean.idx
-                                                    ) { itRst ->
-                                                        if (itRst.isNotEmpty()) {
-                                                            // 上报锁具信息
-                                                            RepositoryManager.jobTicketRepo.updateLockReturn(
-                                                                rfid,
-                                                                SIKCore.getApplication().serialNo()
-                                                            ) {}
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        } else {
-                            logger.info("挂锁取出-:${lockBean.rfid}")
-                            DeviceTakeUpdateEvent.sendDeviceTakeEvent(
-                                DeviceConst.DEVICE_TYPE_LOCK,
-                                lockBean.rfid
-                            )
-                        }
+                        deviceLockHandler(dockBean, lockBean)
                     }
                 }
 
@@ -450,89 +324,11 @@ object ModbusBusinessManager {
                         if (deviceBean.isExist) {
                             when (deviceBean.type) {
                                 DeviceConst.DEVICE_TYPE_KEY -> {
-                                    ModBusController.readKeyRfid(
-                                        dockBean.addr, deviceBean.idx
-                                    ) { idx, res ->
-                                        if (res.size < 11) {
-                                            logger.error("Key rfid error")
-                                            return@readKeyRfid
-                                        }
-                                        val rfid = res.copyOfRange(3, 11).toHexStrings(false)
-                                            .removeLeadingZeros()
-                                        ModBusController.updateKeyRfid(
-                                            dockBean.addr, deviceBean.idx, rfid
-                                        )
-                                        RepositoryManager.hardwareRepo.getKeyInfo(rfid) {
-                                            ModBusController.updateKeyNewHardware(
-                                                dockBean.addr, deviceBean.idx, it == null
-                                            )
-                                            if (it != null && !it.macAddress.isNullOrEmpty()) {
-                                                ModBusController.updateKeyMac(
-                                                    dockBean.addr,
-                                                    deviceBean.idx,
-                                                    it.macAddress ?: ""
-                                                )
-//                                                    showKeyReturnDialog(it.macAddress, isLeft, dockBean.addr)
-                                            } else {
-                                                PopTip.tip(R.string.get_key_info_fail)
-                                            }
-                                        }
-                                        // TODO 蓝牙通信
-                                    }
+                                    deviceKeyHandler(dockBean, deviceBean as DockBean.KeyBean)
                                 }
 
                                 DeviceConst.DEVICE_TYPE_LOCK -> {
-                                    ModBusController.readLockRfid(
-                                        dockBean.addr, deviceBean.idx
-                                    ) { res ->
-                                        if (res.size < 11) {
-                                            logger.error("Lock rfid error")
-                                            return@readLockRfid
-                                        }
-                                        val rfid = res.copyOfRange(3, 11).toHexStrings(false)
-                                            .removeLeadingZeros()
-                                        ModBusController.updateLockRfid(
-                                            dockBean.addr, deviceBean.idx, rfid
-                                        )
-                                        ThreadUtils.runOnIO {
-                                            val lockStatusReq = async {
-                                                DataBusiness.fetchDict(
-                                                    DictConstants.KEY_PAD_LOCK_STATUS
-                                                )
-                                            }
-                                            var lockStatus = lockStatusReq.await()
-                                            RepositoryManager.hardwareRepo.getIsLockPage { lockData ->
-                                                //锁rfid未异常正常请求锁数据,关锁
-                                                if (rfid !in (lockData?.records?.filter { it.exStatus == lockStatus.find { it.dictLabel == "异常" }?.dictValue }
-                                                        ?.map { it.lockNfc }?.toMutableList()
-                                                        ?: mutableListOf())
-                                                ) {
-                                                    RepositoryManager.hardwareRepo.getLockInfo(rfid) {
-                                                        ModBusController.updateLockNewHardware(
-                                                            dockBean.addr,
-                                                            deviceBean.idx,
-                                                            it == null
-                                                        )
-                                                        if (it != null) {
-                                                            // TODO 考虑快速拿取
-                                                            ModBusController.controlLockBuckle(
-                                                                false, dockBean.addr, deviceBean.idx
-                                                            ) { itRst ->
-                                                                if (itRst.isNotEmpty()) {
-                                                                    // 上报锁具信息
-                                                                    RepositoryManager.jobTicketRepo.updateLockReturn(
-                                                                        rfid,
-                                                                        SIKCore.getApplication()
-                                                                            .serialNo()
-                                                                    ) {}
-                                                                }
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
+                                    deviceLockHandler(dockBean, deviceBean as DockBean.LockBean)
                                 }
 
                                 DeviceConst.DEVICE_TYPE_CARD -> {
@@ -559,6 +355,174 @@ object ModbusBusinessManager {
                 listeners.forEach { it.callBack(dockBean) }
             }
         }
+        Executor.delayOnMain(200) {
+            if (!ISCSConfig.isInit) {
+                initListener?.invoke()
+            }
+        }
+    }
+
+    /**
+     * 设备挂锁处理
+     */
+    private fun deviceLockHandler(
+        dockBean: DockBean,
+        lockBean: DockBean.LockBean
+    ) {
+        if (lockBean.isExist) {
+            ModBusController.readLockRfid(dockBean.addr, lockBean.idx) { res ->
+                if (res.size < 11) {
+                    logger.error("Lock rfid error")
+                    return@readLockRfid
+                }
+                val rfid =
+                    res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                ModBusController.updateLockRfid(
+                    dockBean.addr, lockBean.idx, rfid
+                )
+                ThreadUtils.runOnIO {
+                    val lockStatusReq =
+                        async { DataBusiness.fetchDict(DictConstants.KEY_PAD_LOCK_STATUS) }
+                    val slotStatus =
+                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_STATUS) }
+                    val slotType =
+                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_TYPE) }
+                    val slotsPageReq = async { DataBusiness.getSlotsPage() }
+                    var lockStatus = lockStatusReq.await()
+                    val slotsPage = slotsPageReq.await()
+                    val slotStatusList = slotStatus.await()
+                    val slotTypeList = slotType.await()
+                    RepositoryManager.hardwareRepo.getIsLockPage { lockData ->
+                        //锁rfid未异常正常请求锁数据,关锁
+                        if (rfid in (lockData?.records?.filter { it.exStatus == lockStatus.find { it.dictLabel == "异常" }?.dictValue }
+                                ?.map { it.lockNfc }?.toMutableList()
+                                ?: mutableListOf())
+                        ) {
+                            PopTip.tip(R.string.lock_exception_tag)
+                        } else if (slotsPage?.records?.filter {
+                                it.slotType == slotTypeList.find { d -> d.dictLabel == "锁" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
+                            }
+                                ?.find { it.row?.toInt() == dockBean.row && (lockBean.idx + 1) == it.col?.toInt() } != null) {
+                            PopTip.tip(R.string.slot_exception_tag)
+                        } else {
+                            RepositoryManager.hardwareRepo.getLockInfo(rfid) {
+                                if (it != null && it?.lockNfc?.isNotEmpty() == true) {
+                                    // TODO 考虑快速拿取
+                                    ModBusController.controlLockBuckle(
+                                        false, dockBean.addr, lockBean.idx
+                                    ) { itRst ->
+                                        if (itRst.isNotEmpty()) {
+                                            // 上报锁具信息
+                                            RepositoryManager.jobTicketRepo.updateLockReturn(
+                                                rfid,
+                                                SIKCore.getApplication().serialNo()
+                                            ) {}
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            logger.info("挂锁取出-:${lockBean.rfid}")
+            handleDeviceTake(DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_LOCK, lockBean.rfid),lockBean.rfid)
+        }
+    }
+
+    /**
+     * 钥匙设备处理
+     */
+    private fun deviceKeyHandler(
+        dockBean: DockBean,
+        keyBean: DockBean.KeyBean
+    ) {
+        if (keyBean.isExist) {
+            // 放回钥匙,读取rfid
+            ModBusController.readKeyRfid(
+                dockBean.addr, keyBean.idx
+            ) { idx, res ->
+                if (ISCSConfig.isInit) {
+                    ModBusController.controlKeyCharge(
+                        true, keyBean.idx, dockBean.addr
+                    )
+                }
+                if (res.size < 11) {
+                    logger.error("Key rfid error")
+                    return@readKeyRfid
+                }
+                val rfid =
+                    res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                ModBusController.updateKeyRfid(
+                    dockBean.addr, keyBean.idx, rfid
+                )
+                ThreadUtils.runOnIO {
+                    val slotStatus =
+                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_STATUS) }
+                    val slotType =
+                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_TYPE) }
+                    val slotsPageReq = async { DataBusiness.getSlotsPage() }
+                    val keyStatusReq =
+                        async { DataBusiness.fetchDict(DictConstants.KEY_KEY_STATUS) }
+                    val keyPageReq = async { DataBusiness.getKeyPage() }
+                    var keyStatus = keyStatusReq.await()
+                    var keyData = keyPageReq.await()
+                    val slotsPage = slotsPageReq.await()
+                    val slotStatusList = slotStatus.await()
+                    val slotTypeList = slotType.await()
+                    //锁钥匙未异常正常请求锁数据,关锁
+                    if (rfid in (keyData?.records?.filter { it.exStatus == keyStatus.find { it.dictLabel == "异常" }?.dictValue }
+                            ?.map { it.keyNfc }?.toMutableList()
+                            ?: mutableListOf())
+                    ) {
+                        PopTip.tip(
+                            CommonUtils.getStr(R.string.key_exception_tag)
+                        )
+                    } else if (slotsPage?.records?.filter {
+                            it.slotType == slotTypeList.find { d -> d.dictLabel == "钥匙" }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
+                        }
+                            ?.find { it.row?.toInt() == dockBean.row && it.col?.toInt() == (dockBean.col + (keyBean.idx) * 2) } != null) {
+                        PopTip.tip(
+                            CommonUtils.getStr(R.string.slot_exception_tag)
+                        )
+                    } else {
+                        // 放回钥匙,上锁
+                        ModBusController.controlKeyBuckle(
+                            false, keyBean.idx, dockBean.addr
+                        ) {
+                            RepositoryManager.hardwareRepo.getKeyInfo(rfid) {
+                                logger.info("钥匙:${rfid},${it}")
+                                if (it != null && !it.macAddress.isNullOrEmpty()) {
+                                    ModBusController.updateKeyMac(
+                                        dockBean.addr,
+                                        keyBean.idx,
+                                        it.macAddress ?: ""
+                                    )
+                                    ModBusController.updateKeyReadyStatus(
+                                        it.macAddress ?: "", false, 5
+                                    )
+                                } else {
+                                    logger.error("Get key info fail : $rfid")
+                                    if (!ISCSConfig.isInit) {
+                                        PopTip.tip(R.string.get_key_info_fail)
+                                    }
+                                    ModBusController.controlKeyBuckle(
+                                        true, keyBean.idx, dockBean.addr
+                                    )
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else if (!keyBean.isCharging) {//增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
+            // 移出待连监听集合,防止connectKey循环失败
+            keyBean.mac?.let {
+                BleConnectionManager.unregisterConnectListener(it)
+            }
+            handleDeviceTake(DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid),keyBean.rfid)
+        }
     }
 
     /**
@@ -569,8 +533,4 @@ object ModbusBusinessManager {
             deviceStatusHandle(res)
         }
     }
-
-    fun unregisterMainListener() {
-        ModBusController.unregisterListener(this)
-    }
 }

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt

@@ -650,7 +650,7 @@ object BleConnectionManager {
      */
     suspend fun scanOnlineKeyLockMacAndSwitchModeToClose(): Boolean {
         return suspendCancellableCoroutine { parentCont ->
-            BleUtil.instance.scan(object : CustomBleScanCallback() {
+            BleUtil.instance?.scan(object : CustomBleScanCallback() {
                 override fun onPrompt(promptStr: String?) {
                     // 蓝牙未启动重试
                     logger.debug("设备录入-参数:${promptStr}")

+ 19 - 7
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt

@@ -21,23 +21,31 @@ class BleUtil private constructor() {
     private val logger: Logger = LoggerFactory.getLogger(BleUtil::class.java)
 
     companion object {
-        val instance: BleUtil by lazy { BleUtil() }
+        var instance: BleUtil? = null
+            get() {
+                if (field == null) field = BleUtil()
+                return field
+            }
+            private set
 
         const val OPERATE_TIMEOUT = 10 * 1000
     }
 
-    fun initBle(application: Application) {
+    fun initBle(application: Application?) {
         try {
             BleManager.getInstance().init(application)
-            BleManager.getInstance().enableLog(true).setConnectOverTime(10 * 1000L)
+            BleManager.getInstance().enableLog(false)
+                .setConnectOverTime(10 * 1000L)
                 .setReConnectCount(3, 300) // 设置重新连接次数和间隔时间,默认为0次,不重连
-                .setSplitWriteNum(500).operateTimeout =
+                .setSplitWriteNum(500)
+                .operateTimeout =
                 OPERATE_TIMEOUT // 设置操作readRssi、setMtu、write、read、notify、indicate的超时时间(毫秒)
             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
                 //Android 12及以上不允许添加过滤器
                 val bleScanRuleConfig = BleScanRuleConfig.Builder()
 //                .setServiceUuids(arrayOf(UUID.fromString(BLUETOOTH_SERVICEUUID)))
-                    .setDeviceName(true, BleConst.BLE_LOCAL_NAME).build()
+                    .setDeviceName(true, BleConst.BLE_LOCAL_NAME)
+                    .build()
                 BleManager.getInstance().initScanRule(bleScanRuleConfig)
             }
         } catch (e: Exception) {
@@ -127,7 +135,9 @@ class BleUtil private constructor() {
                 }
 
                 override fun onConnectSuccess(
-                    bleDevice: BleDevice, gatt: BluetoothGatt, status: Int
+                    bleDevice: BleDevice,
+                    gatt: BluetoothGatt,
+                    status: Int
                 ) {
                     BleManager.getInstance().removeConnectGattCallback(bleDevice)
                     BleManager.getInstance()
@@ -177,7 +187,9 @@ class BleUtil private constructor() {
                 }
 
                 override fun onConnectSuccess(
-                    bleDevice: BleDevice, gatt: BluetoothGatt, status: Int
+                    bleDevice: BleDevice,
+                    gatt: BluetoothGatt,
+                    status: Int
                 ) {
                     BleManager.getInstance().removeConnectGattCallback(bleDevice)
                     BleManager.getInstance()

+ 24 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/event/ModbusInitCompleteEvent.kt

@@ -0,0 +1,24 @@
+package com.grkj.ui_base.utils.event
+
+import com.grkj.shared.model.EventBean
+import com.grkj.data.data.EventConstants
+
+/**
+ * 启动串口完成
+ */
+class ModbusInitCompleteEvent() {
+
+    companion object {
+        /**
+         * 发送启动串口事件
+         */
+        @JvmStatic
+        fun sendModbusInitCompleteEvent() {
+            val startModbusCompleteEvent = ModbusInitCompleteEvent()
+            val startModbusCompleteEventBean = EventBean<ModbusInitCompleteEvent>(
+                EventConstants.EVENT_START_MODBUS_COMPLETE, startModbusCompleteEvent
+            )
+            EventHelper.sendEvent(startModbusCompleteEventBean)
+        }
+    }
+}

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/event/StartModbusEvent.kt

@@ -16,7 +16,7 @@ class StartModbusEvent() {
         fun sendStartModbusEvent() {
             val startModbusEvent = StartModbusEvent()
             val startModbusEventBean = EventBean<StartModbusEvent>(
-                EventConstants.EVENT_LOGOUT, startModbusEvent
+                EventConstants.EVENT_START_MODBUS, startModbusEvent
             )
             EventHelper.sendEvent(startModbusEventBean)
         }

+ 6 - 5
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt

@@ -27,11 +27,12 @@ class DockBean(
 
     companion object {
         private val logger: Logger = LoggerFactory.getLogger(DockBean::class.java)
-        val dockConfig: List<DockBean> by lazy {
-            val json = MMKVConstants.KEY_DOCK_CONFIG.getMMKVData("[]")
-            val type = object : TypeToken<List<DockBean>>() {}.type
-            return@lazy Gson().fromJson(json, type)
-        }
+        val dockConfig: List<DockBean>
+            get() = run {
+                val json = MMKVConstants.KEY_DOCK_CONFIG.getMMKVData("[]")
+                val type = object : TypeToken<List<DockBean>>() {}.type
+                return Gson().fromJson(json, type)
+            }
     }
 
     /**

+ 15 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusCMDHelper.kt

@@ -120,6 +120,21 @@ object ModBusCMDHelper {
         )
     }
 
+    /**
+     * 操作钥匙/便携式底座钥匙卡扣 打开,所有
+     */
+    fun generateAllKeyBuckleOpenCmd(type: Byte): MBFrame {
+        return MBFrame(
+            FRAME_TYPE_WRITE,
+            byteArrayOf(
+                0x00,
+                0x11,
+                (if (type == DeviceConst.DOCK_TYPE_PORTABLE) 0b00110000 else 0xff).toByte(),
+                0x00
+            )
+        )
+    }
+
     /**
      * 操作钥匙/便携式底座钥匙充电,一次只操作一个卡扣
      *

+ 49 - 25
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt

@@ -3,14 +3,12 @@ package com.grkj.ui_base.utils.modbus
 import com.clj.fastble.BleManager
 import com.grkj.data.di.RepositoryManager
 import com.grkj.data.model.res.CabinetSlotsRecord
-import com.grkj.data.repository.IHardwareRepository
-import com.grkj.data.repository.impl.HardwareRepository
 import com.grkj.ui_base.R
-import com.grkj.ui_base.business.BleBusinessManager
 import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.Executor
 import com.grkj.ui_base.utils.ble.BleConnectionManager
+import com.grkj.ui_base.utils.event.ModbusInitCompleteEvent
 import com.grkj.ui_base.utils.extension.removeLeadingZeros
 import com.grkj.ui_base.utils.extension.toHexStrings
 import com.kongzue.dialogx.dialogs.PopTip
@@ -18,8 +16,6 @@ import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import java.util.concurrent.atomic.AtomicInteger
 import java.util.stream.Collectors
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
 
 
 /**
@@ -113,13 +109,6 @@ object ModBusController {
         }
     }
 
-    /**
-     * 停止引擎
-     */
-    fun stop() {
-        modBusManager?.stop()
-    }
-
     /**
      * 引擎是否运行中
      */
@@ -133,7 +122,9 @@ object ModBusController {
      * 初始化所有设备的状态
      */
     fun initDevicesStatus() {
+        logger.info("发送设备类型读取")
         readDeviceType { res ->
+            logger.info("获取设备类型")
             res.forEach { bytes ->
                 if (bytes.size < 5) return@forEach
                 // 设备具体数据由0x0011寄存器提供
@@ -148,6 +139,7 @@ object ModBusController {
                 }
                 logger.info("initDevicesStatus 设备(${bytes[0].toInt()})类型:$type")
             }
+            controlAllKeyBuckleOpen()
             // TODO 待完善
             Executor.repeatOnMain({
                 if (isInitReady) {
@@ -182,6 +174,14 @@ object ModBusController {
                         val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                         logger.info("初始化锁具 RFID : $rfid")
                         updateLockRfid(dockBean.addr, idx, rfid)
+                        //todo 为设备录入增加
+                        RepositoryManager.hardwareRepo.getLockInfo(rfid) {
+                            updateLockNewHardware(
+                                dockBean.addr,
+                                idx,
+                                it?.lockNfc?.isEmpty() == true
+                            )
+                        }
                     }
                 }
                 controlLockBuckle(false, dockBean.addr, hasLockIdxList)
@@ -212,11 +212,16 @@ object ModBusController {
                             // 蓝牙准备操作
                             RepositoryManager.hardwareRepo.getKeyInfo(rfid) {
                                 logger.info("getKeyInfo : $rfid - ${it?.macAddress}")
-                                updateKeyNewHardware(dockBean.addr, key.idx, it == null)
-                                if (ISCSConfig.isInit) {
-                                    if (it != null && !it.macAddress.isNullOrEmpty()) {
-                                        // 更新mac
-                                        updateKeyMac(dockBean.addr, key.idx, it.macAddress!!)
+                                updateKeyNewHardware(
+                                    dockBean.addr,
+                                    key.idx,
+                                    it?.keyNfc?.isEmpty() == true || it?.macAddress?.isEmpty() == true
+                                )
+                                if (it != null && !it.macAddress.isNullOrEmpty()) {
+                                    // 更新mac
+                                    updateKeyMac(dockBean.addr, key.idx, it.macAddress!!)
+                                    //已经初始化完成才会去连接
+                                    if (ISCSConfig.isInit) {
                                         BleConnectionManager.registerConnectListener(
                                             it.macAddress!!
                                         ) { isDone, bleBean ->
@@ -229,23 +234,24 @@ object ModBusController {
                                                 }
                                             }
                                         }
-                                    } else {
+                                    }
+                                    controlKeyBuckle(false, key.idx, dockBean.addr)
+                                } else {
+                                    if (!ISCSConfig.isInit) {
                                         PopTip.tip(CommonUtils.getStr(R.string.get_key_info_fail))
                                     }
+                                    controlKeyBuckle(true, key.idx, dockBean.addr)
                                 }
                             }
                         }
-                        controlKeyBuckle(false, key.idx, dockBean.addr)
                     } else {
                         controlKeyBuckle(true, key.idx, dockBean.addr)
-                        controlKeyCharge(
-                            false,
-                            key.idx,
-                            dockBean.addr
-                        )
                     }
                 }
             }
+        if (!ISCSConfig.isInit) {
+            ModbusInitCompleteEvent.sendModbusInitCompleteEvent()
+        }
     }
 
     /**
@@ -688,6 +694,22 @@ object ModBusController {
         }
     }
 
+    /**
+     * 打开所有钥匙锁仓并关闭充电
+     */
+    fun controlAllKeyBuckleOpen() {
+        dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+            .forEach { dock ->
+                dock.type?.let { dockType ->
+                    ModBusCMDHelper.generateAllKeyBuckleOpenCmd(dockType).let { cmd ->
+                        logger.info("硬件:打开所有钥匙锁仓,${dock.addr},${cmd.data}")
+                        modBusManager?.sendTo(dock.addr, cmd) { res ->
+                        }
+                    }
+                }
+            }
+    }
+
     /**
      * 控制钥匙充电
      */
@@ -1013,6 +1035,7 @@ object ModBusController {
         exceptionLocks: MutableList<String>
     ): MutableMap<Byte, MutableList<DockBean.LockBean>> {
         val map = mutableMapOf<Byte, MutableList<DockBean.LockBean>>()
+        logger.info("需要的锁具:${needLockCount}")
         if (needLockCount == 0) {
             return map
         }
@@ -1020,11 +1043,12 @@ object ModBusController {
             dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
         lockDockList.sortedBy { it.addr }
         var provideCount = 0
+        logger.info("锁具基座列表:${lockDockList}")
         logger.info("异常锁rfid:${exceptionLocks}")
         logger.info("异常锁仓位:${exceptionSlots.joinToString(",") { "${it.row},${it.col}" }}")
         for (lockDockIndex in lockDockList.indices) {
             if (provideCount >= needLockCount) break
-
+            logger.info("锁具信息:${lockDockList[lockDockIndex].getLockList()}")
             val validLocks =
                 lockDockList[lockDockIndex].getLockList().filter { it.rfid !in exceptionLocks }
                     .filter {

+ 2 - 3
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusManager.kt

@@ -57,10 +57,9 @@ class ModBusManager(
             }
         }
         // 初始化地址池
-        val dockConfig = MMKVConstants.KEY_DOCK_CONFIG.getMMKVData("")
+        val dockConfig = MMKVConstants.KEY_DOCK_CONFIG.getMMKVData("[]")
         logger.info("基座配置: ${dockConfig}")
-        dockConfig
-            ?.takeIf { it.isNotEmpty() }
+        dockConfig.takeIf { it.isNotEmpty() }
             ?.let { json ->
                 val type = object : TypeToken<List<DockBean>>() {}.type
                 val list: List<DockBean> = Gson().fromJson(json, type)

+ 145 - 125
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/PortManager.kt

@@ -3,29 +3,21 @@ package com.grkj.ui_base.utils.modbus
 import androidx.annotation.WorkerThread
 import com.epton.sdk.SerialPort
 import com.grkj.data.data.MMKVConstants
-import com.grkj.ui_base.utils.SPUtils
 import com.grkj.ui_base.utils.extension.toHexStrings
 import com.kongzue.dialogx.dialogs.PopTip
-import com.sik.sikcore.SIKCore
 import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.extension.saveMMKVData
 import com.sik.sikcore.extension.toJson
 import com.sik.sikcore.thread.ThreadUtils
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import kotlinx.coroutines.withTimeout
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import java.io.File
 import java.io.IOException
 import java.io.InputStream
 import java.io.OutputStream
-import java.util.concurrent.Callable
-import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
-import kotlin.coroutines.cancellation.CancellationException
 
 /**
  * 串口通信管理器
@@ -96,38 +88,7 @@ class PortManager private constructor(
     companion object {
         private val logger: Logger = LoggerFactory.getLogger(PortManager::class.java)
         private const val BUFFER_SIZE = 256
-
-        /**
-         * 打开串口
-         * @param port 串口号,从 0 开始
-         * @param bps 波特率,正整数
-         */
-        @JvmStatic
-        @WorkerThread
-        fun open(port: Int, bps: Int, usb: Boolean): PortManager? {
-            var blocked = true
-            val thread = Thread.currentThread()
-            ThreadUtils.runOnMainDelayed(500) {
-                // 如果线程被阻塞达到 1 秒,则打断唤醒
-                if (blocked) {
-                    logger.warn("超 0.5 秒未打开串口,打断唤醒")
-                    thread.interrupt()
-                }
-            }
-            try {
-                val file = File(if (usb) "/dev/ttyUSB${port}" else "/dev/ttyS${port}")
-                logger.info("连接 port file")
-                SerialPort(file, bps, 0).run {
-                    blocked = false
-                    logger.info("建立 SerialPort")
-                    return PortManager(inputStream, outputStream)
-                }
-            } catch (e: Exception) {
-                blocked = false
-                logger.error("异常 : ${e.message}")
-                return null
-            }
-        }
+        private var isDetectMode = true
 
         /**
          * 打开串口
@@ -172,91 +133,137 @@ class PortManager private constructor(
         @JvmStatic
         fun detectSlave(
             baudRate: Int = 115200,
-            perAddrTimeoutMs: Long = 100,
-            perPortTimeoutMs: Long = 5000   // 每个端口最大 500ms
+            perAddrTimeoutMs: Long = 700        // 地址检测超时 700 ms
         ): String? {
+            isDetectMode = true
+            // 1. 列出所有串口
             val devs = File("/dev").listFiles { _, name ->
-                name.startsWith("ttyS") || name.startsWith("ttyUSB")
+                name.startsWith("ttyS")
             }?.map { it.absolutePath } ?: return null
+            logger.info("共发现 ${devs.size} 个串口,开始依次串行检测")
+
+            // 2. 用线程池来做 open()/checkSlave() 的超时调度
+            val executor = Executors.newCachedThreadPool()
+            var foundPort: String? = null
 
-            val executor: ExecutorService = Executors.newCachedThreadPool()
             try {
-                devs.forEach { path ->
-                    val future = executor.submit(Callable<String?> {
-                        val dockConfig = mutableListOf<DockBean>()
-                        SerialPort(File(path), baudRate, 0).let { sp ->
-                            val input = sp.inputStream
-                            val output = sp.outputStream
+                for (path in devs) {
+                    logger.info("[$path] 尝试打开串口,超时 500 ms")
+                    // 2.1 open 串口,500 ms 超时
+                    val openFuture = executor.submit<SerialPort> {
+                        SerialPort(File(path), baudRate, 0)
+                    }
 
-                            // 1..0x16
-                            for (addr in 1..0x16) {
-                                tryCheckSlave(
-                                    executor,
-                                    addr.toInt(),
-                                    input,
-                                    output,
-                                    dockConfig,
-                                    perAddrTimeoutMs
-                                )
+                    val sp = try {
+                        val port = openFuture.get(500, TimeUnit.MILLISECONDS)
+                        logger.info("[$path] 串口打开成功")
+                        port
+                    } catch (e: TimeoutException) {
+                        openFuture.cancel(true)
+                        logger.warn("[$path] 打开超时 500 ms,跳过此端口")
+                        continue
+                    } catch (e: Exception) {
+                        logger.warn("[$path] 打开失败: ${e.message},跳过此端口")
+                        continue
+                    }
+
+                    // 3. 打开成功后,扫描所有地址
+                    val dockConfig = mutableListOf<DockBean>()
+                    val startTime = System.currentTimeMillis()
+                    try {
+                        val input = sp.inputStream
+                        val output = sp.outputStream
+                        var hasAnyResponse = false
+
+                        fun scanAddr(addrInt: Int) {
+                            val hex = "%02X".format(addrInt)
+                            logger.info("[$path][0x$hex] 检测开始")
+                            // wrap checkSlave
+                            val addrFuture = executor.submit<Boolean> {
+                                checkSlave(addrInt, input, output, dockConfig)
+                                dockConfig.any { it.addr == addrInt.toByte() }
                             }
-                            // 0xA1
-                            tryCheckSlave(
-                                executor,
-                                0xA1.toInt(),
-                                input,
-                                output,
-                                dockConfig,
-                                perAddrTimeoutMs
-                            )
-                            if (dockConfig.isNotEmpty()) {
-                                MMKVConstants.KEY_DOCK_CONFIG.saveMMKVData(dockConfig.toJson())
-                                return@Callable path
+
+                            val responded = try {
+                                addrFuture.get(perAddrTimeoutMs, TimeUnit.MILLISECONDS)
+                            } catch (te: TimeoutException) {
+                                addrFuture.cancel(true)
+                                logger.debug("[$path][0x$hex] 超时 ${perAddrTimeoutMs} ms,无响应")
+                                false
+                            } catch (e: Exception) {
+                                logger.warn("[$path][0x$hex] 检测异常: ${e.message}")
+                                false
+                            }
+
+                            if (responded) {
+                                hasAnyResponse = true
+                                logger.info("[$path][0x$hex] 有响应,已记录")
                             }
                         }
-                        null
-                    })
 
-                    try {
-                        val result = future.get(perPortTimeoutMs, TimeUnit.MILLISECONDS)
-                        if (result != null) return result
-                    } catch (e: TimeoutException) {
-                        future.cancel(true)
-                        logger.warn("[$path] 打开/扫描超时 ${perPortTimeoutMs}ms,跳过")
+                        // 顺序扫描 1..0x16,再扫 0xA1
+                        for (i in 1..0x16) scanAddr(i)
+                        scanAddr(0xA1)
+
+                        if (hasAnyResponse) {
+                            try {
+                                sp.inputStream?.close()
+                            } catch (_: Exception) {
+                            }
+                            try {
+                                sp.outputStream?.close()
+                            } catch (_: Exception) {
+                            }
+                            try {
+                                sp.close()
+                            } catch (_: Exception) {
+                            }
+                            val elapsed = System.currentTimeMillis() - startTime
+                            logger.info("[$path] 扫描完成,共发现 ${dockConfig.size} 个从设备,耗时 ${elapsed} ms")
+                            logger.info("[$path] 基座配置: ${dockConfig.toJson()}")
+                            MMKVConstants.KEY_DOCK_CONFIG.saveMMKVData(dockConfig.toJson())
+                            foundPort = path
+                            break
+                        } else {
+                            logger.info("[$path] 无任何响应,继续下一个串口")
+                        }
                     } catch (e: Exception) {
-                        future.cancel(true)
-                        logger.warn("[$path] 扫描出错:${e.message}")
+                        logger.warn("[$path] 扫描过程中异常: ${e.message}")
+                    } finally {
+                        // 4. 关闭串口
+                        try {
+                            sp.inputStream?.close()
+                        } catch (_: Exception) {
+                        }
+                        try {
+                            sp.outputStream?.close()
+                        } catch (_: Exception) {
+                        }
+                        try {
+                            sp.close()
+                        } catch (_: Exception) {
+                        }
                     }
                 }
             } finally {
+                // 5. 确保所有任务都结束后再返回
                 executor.shutdownNow()
+                try {
+                    if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
+                        logger.warn("线程池未在 5s 内终止")
+                    }
+                } catch (ie: InterruptedException) {
+                    logger.warn("等待线程池终止被中断")
+                }
             }
-            return null
-        }
 
-        private fun tryCheckSlave(
-            executor: ExecutorService,
-            addrInt: Int,
-            input: InputStream,
-            output: OutputStream,
-            dockConfig: MutableList<DockBean>,
-            timeoutMs: Long
-        ): Boolean {
-            return try {
-                val future = executor.submit(Callable {
-                    checkSlave(addrInt, input, output, dockConfig)
-                    dockConfig.any { it.addr.toInt() == addrInt }
-                })
-                future.get(timeoutMs, TimeUnit.MILLISECONDS)
-            } catch (_: TimeoutException) {
-                logger.warn("addr=$addrInt 检测超时 ${timeoutMs}ms")
-                false
-            } catch (e: Exception) {
-                logger.warn("addr=$addrInt 检测出错:${e.message}")
-                false
-            }
+            if (foundPort != null) return foundPort
+            logger.info("所有串口扫描完毕,未发现任何从设备")
+            return null
         }
 
-        // 原始阻塞版,不变
+        // 原始阻塞检测,不变
+        @JvmStatic
         private fun checkSlave(
             addrInt: Int,
             input: InputStream,
@@ -265,28 +272,41 @@ class PortManager private constructor(
         ) {
             val addr = addrInt.toByte()
             val cmd = ModBusCMDHelper.generateReadDeviceTypeCmd().compile(addr)
+            if (!isDetectMode) {
+                return
+            }
+            logger.info("发送命令:${cmd.toHexStrings()}")
             output.write(cmd); output.flush()
 
-            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
+            val buffer = ByteArray(BUFFER_SIZE)
+            val data = ByteArray(input.read(buffer))
+            System.arraycopy(buffer, 0, data, 0, data.size)
+            if (!isDetectMode) {
+                return
             }
-
-            if (received == buf.size && buf[1] == 0x03.toByte()) {
-                val deviceType = ((buf[3].toInt() and 0xFF) shl 8) or (buf[4].toInt() and 0xFF)
-                dockConfig.add(
-                    DockBean(
-                        addr = addr,
-                        row = dockConfig.count(),
-                        col = dockConfig.count { it.type == deviceType.toByte() } + 1,
-                        type = deviceType.toByte(),
-                        deviceList = mutableListOf()
-                    )
-                )
+            logger.info("接受指令:${data.toHexStrings()}")
+            if (data.size < 5) return
+            val type = when (data[4]) {
+                DeviceConst.DOCK_TYPE_KEY -> "钥匙底座"
+                DeviceConst.DOCK_TYPE_LOCK -> "锁具底座"
+                DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板"
+                DeviceConst.DOCK_TYPE_PORTABLE -> "便携式底座"
+                DeviceConst.DOCK_TYPE_COLLECT -> "开关量采集板"
+                else -> "未知"
             }
+            logger.info("检测到地址:0x${"%02X".format(data[0])}, 设备类型:${type}")
+            val dockBean = DockBean(
+                addr = data[0],
+                row = if (data[4] == DeviceConst.DOCK_TYPE_KEY) dockConfig.find { it.type == data[4] }?.row
+                    ?: 0 else dockConfig.count { it.type != DeviceConst.DOCK_TYPE_KEY } + 1,
+                col = if (data[4] == DeviceConst.DOCK_TYPE_KEY) dockConfig.count { it.type == data[4] } + 1 else 1,
+                type = data[4],
+                deviceList = mutableListOf()
+            )
+            logger.info("基座数据:${dockBean}")
+            dockConfig.add(
+                dockBean
+            )
         }
 
         /**
@@ -317,6 +337,7 @@ class PortManager private constructor(
 
             // 2. 缓存无效或打开失败,走自动扫描
             val newPort = detectSlave(baud)
+            isDetectMode = false
             if (newPort != null) {
                 // 3. 扫描到就保存,下次直接用
                 MMKVConstants.KEY_PORT_CONFIG.saveMMKVData(newPort)
@@ -328,7 +349,6 @@ class PortManager private constructor(
             }
         }
 
-
     }
 
 }