Procházet zdrojové kódy

refactor(硬件): 硬件抽象层重构,支持Modbus和CAN模式切换
- 将蓝牙、Modbus等硬件相关类移至data模块的hardware包下
- 新增`HardwareMode`枚举及`IHardwareHelper`接口,用于统一硬件操作
- 新增`CanHardwareHelper`和`ModBusHardwareHelper`实现类
- `HardwareBusinessManager`替换`ModbusBusinessManager`,根据配置的硬件模式调用相应Helper
- 新增`CanDeviceListener`用于监听CAN设备状态变化
- 新增`ToastEvent`用于统一显示提示信息
- 将部分 Event 类移至 data 模块
- 更新相关业务逻辑以适配新的硬件抽象层
- 调整设置页面硬件模式提示文本

周文健 před 2 měsíci
rodič
revize
3a452d85ce
76 změnil soubory, kde provedl 1889 přidání a 819 odebrání
  1. 1 1
      app/src/main/assets/i18n/en-US.json
  2. 1 1
      app/src/main/assets/i18n/zh-CN.json
  3. 5 5
      app/src/main/java/com/grkj/iscs/ISCSApplication.kt
  4. 1 1
      app/src/main/java/com/grkj/iscs/features/init/activity/InitActivity.kt
  5. 1 6
      app/src/main/java/com/grkj/iscs/features/init/activity/SetRemoteServerActivity.kt
  6. 15 42
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt
  7. 1 1
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitSetRemoteServerFragment.kt
  8. 0 29
      app/src/main/java/com/grkj/iscs/features/init/model/DockData.kt
  9. 78 79
      app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt
  10. 0 1
      app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt
  11. 1 1
      app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt
  12. 0 2
      app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt
  13. 1 1
      app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/AddUserDialog.kt
  14. 1 1
      app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/FilterUserDialog.kt
  15. 1 1
      app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/UpdateUserDialog.kt
  16. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataManageHomeFragment.kt
  17. 2 3
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/SwitchLayoutFragment.kt
  18. 61 52
      app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/SlotsManageFragment.kt
  19. 12 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SettingsFragment.kt
  20. 115 48
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt
  21. 3 4
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionViewModel.kt
  22. 38 52
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/hardware_manage/SlotsManageViewModel.kt
  23. 29 29
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt
  24. 1 0
      data/build.gradle.kts
  25. 1 1
      data/src/main/java/com/grkj/data/config/ISCSConfig.kt
  26. 4 0
      data/src/main/java/com/grkj/data/data/EventConstants.kt
  27. 20 0
      data/src/main/java/com/grkj/data/enums/HardwareMode.kt
  28. 48 0
      data/src/main/java/com/grkj/data/hardware/DockData.kt
  29. 170 0
      data/src/main/java/com/grkj/data/hardware/IHardwareHelper.kt
  30. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/BleBean.kt
  31. 11 4
      data/src/main/java/com/grkj/data/hardware/ble/BleCmdManager.kt
  32. 36 32
      data/src/main/java/com/grkj/data/hardware/ble/BleConnectionManager.kt
  33. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/BleConst.kt
  34. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/BleIndicateListener.kt
  35. 22 9
      data/src/main/java/com/grkj/data/hardware/ble/BleQueueDispatcher.kt
  36. 3 3
      data/src/main/java/com/grkj/data/hardware/ble/BleReturnDispatcher.kt
  37. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/BleSendDispatcher.kt
  38. 2 3
      data/src/main/java/com/grkj/data/hardware/ble/BleUtil.kt
  39. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/CustomBleGattCallback.kt
  40. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/CustomBleIndicateCallback.kt
  41. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/CustomBleScanCallback.kt
  42. 1 1
      data/src/main/java/com/grkj/data/hardware/ble/CustomBleWriteCallback.kt
  43. 4 55
      data/src/main/java/com/grkj/data/hardware/can/CanDeviceConst.kt
  44. 186 0
      data/src/main/java/com/grkj/data/hardware/can/CanHardwareHelper.kt
  45. 172 11
      data/src/main/java/com/grkj/data/hardware/can/CanHelper.kt
  46. 6 1
      data/src/main/java/com/grkj/data/hardware/can/DeviceModel.kt
  47. 15 45
      data/src/main/java/com/grkj/data/hardware/can/DeviceParseStatus.kt
  48. 1 1
      data/src/main/java/com/grkj/data/hardware/modbus/DeviceConst.kt
  49. 2 2
      data/src/main/java/com/grkj/data/hardware/modbus/DockBean.kt
  50. 1 1
      data/src/main/java/com/grkj/data/hardware/modbus/FrameTask.kt
  51. 1 1
      data/src/main/java/com/grkj/data/hardware/modbus/MBFrame.kt
  52. 1 3
      data/src/main/java/com/grkj/data/hardware/modbus/ModBusCMDHelper.kt
  53. 1 1
      data/src/main/java/com/grkj/data/hardware/modbus/ModBusConstants.kt
  54. 22 24
      data/src/main/java/com/grkj/data/hardware/modbus/ModBusController.kt
  55. 260 0
      data/src/main/java/com/grkj/data/hardware/modbus/ModBusHardwareHelper.kt
  56. 11 7
      data/src/main/java/com/grkj/data/hardware/modbus/ModBusManager.kt
  57. 8 15
      data/src/main/java/com/grkj/data/hardware/modbus/PortManager.kt
  58. 1 1
      data/src/main/java/com/grkj/data/hardware/modbus/StatusListener.kt
  59. 2 2
      data/src/main/java/com/grkj/data/utils/event/GetTicketStatusEvent.kt
  60. 2 2
      data/src/main/java/com/grkj/data/utils/event/ModbusInitCompleteEvent.kt
  61. 2 2
      data/src/main/java/com/grkj/data/utils/event/RestartAppEvent.kt
  62. 2 2
      data/src/main/java/com/grkj/data/utils/event/SwitchCollectionUpdateEvent.kt
  63. 28 0
      data/src/main/java/com/grkj/data/utils/event/ToastEvent.kt
  64. 1 0
      shared/build.gradle.kts
  65. 0 2
      ui-base/build.gradle.kts
  66. 9 1
      ui-base/src/main/java/com/grkj/ui_base/base/BaseActivity.kt
  67. 1 1
      ui-base/src/main/java/com/grkj/ui_base/base/BaseFragment.kt
  68. 74 82
      ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt
  69. 1 1
      ui-base/src/main/java/com/grkj/ui_base/business/DataBusiness.kt
  70. 362 121
      ui-base/src/main/java/com/grkj/ui_base/business/HardwareBusinessManager.kt
  71. 7 0
      ui-base/src/main/java/com/grkj/ui_base/listeners/CanDeviceListener.kt
  72. 1 1
      ui-base/src/main/java/com/grkj/ui_base/listeners/DeviceListener.kt
  73. 6 5
      ui-base/src/main/java/com/grkj/ui_base/service/CheckKeyInfoTask.kt
  74. 1 1
      ui-base/src/main/java/com/grkj/ui_base/utils/event/CurrentModeEvent.kt
  75. 1 2
      ui-base/src/main/java/com/grkj/ui_base/widget/CustomNavBar.kt
  76. 3 4
      ui-base/src/main/java/com/grkj/ui_base/widget/CustomSwitchStationLayer.kt

+ 1 - 1
app/src/main/assets/i18n/en-US.json

@@ -4111,6 +4111,6 @@
   "hardware_mode": {
     "key": "hardware_mode",
     "type": "text",
-    "value": "Hardware Mode"
+    "value": "Hardware mode (mode modification and saving require restarting the application)"
   }
 }

+ 1 - 1
app/src/main/assets/i18n/zh-CN.json

@@ -4117,6 +4117,6 @@
   "hardware_mode": {
     "key": "hardware_mode",
     "type": "text",
-    "value": "硬件模式"
+    "value": "硬件模式(模式修改保存需要重启应用)"
   }
 }

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

@@ -23,12 +23,12 @@ import com.grkj.shared.utils.i18n.LanguageCatalog
 import com.grkj.shared.utils.i18n.LanguageStore
 import com.grkj.shared.utils.i18n.source.AssetsI18nSource
 import com.grkj.shared.utils.i18n.source.FileI18nSource
-import com.grkj.ui_base.business.ModbusBusinessManager
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.ui_base.business.HardwareBusinessManager
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.service.CheckKeyInfoTask
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.ui_base.utils.ble.BleUtil
-import com.grkj.ui_base.utils.modbus.ModBusController
+import com.grkj.data.hardware.ble.BleUtil
+import com.grkj.data.hardware.modbus.ModBusController
 import com.kongzue.dialogx.DialogX
 import com.scwang.smart.refresh.footer.ClassicsFooter
 import com.scwang.smart.refresh.header.ClassicsHeader
@@ -108,7 +108,7 @@ class ISCSApplication : Application() {
         StateConfig.emptyLayout = com.grkj.ui_base.R.layout.layout_empty
         ThreadUtils.runOnIO {
             DbReadyGate.await()
-            ModbusBusinessManager.registerMainListener()
+            HardwareBusinessManager.registerMainListener()
             LogicManager.init(this@ISCSApplication)
             initImageLoader()
         }

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

@@ -6,7 +6,7 @@ import com.grkj.iscs.R
 import com.grkj.iscs.databinding.ActivityInitBinding
 import com.grkj.shared.config.Constants
 import com.grkj.ui_base.base.BaseActivity
-import com.grkj.ui_base.utils.ble.BleUtil
+import com.grkj.data.hardware.ble.BleUtil
 import com.grkj.ui_base.utils.event.CardSwipeEvent
 import com.grkj.shared.utils.extension.toByteArrays
 import com.grkj.shared.utils.extension.toHexStrings

+ 1 - 6
app/src/main/java/com/grkj/iscs/features/init/activity/SetRemoteServerActivity.kt

@@ -1,15 +1,10 @@
 package com.grkj.iscs.features.init.activity
 
-import android.view.InputDevice
-import android.view.KeyEvent
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.ActivitySetRemoteServerBinding
 import com.grkj.shared.config.Constants
-import com.grkj.shared.utils.extension.toByteArrays
-import com.grkj.shared.utils.extension.toHexStrings
 import com.grkj.ui_base.base.BaseActivity
-import com.grkj.ui_base.utils.ble.BleUtil
-import com.grkj.ui_base.utils.event.CardSwipeEvent
+import com.grkj.data.hardware.ble.BleUtil
 import com.sik.sikcore.SIKCore
 import dagger.hilt.android.AndroidEntryPoint
 

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

@@ -1,6 +1,5 @@
 package com.grkj.iscs.features.init.fragment
 
-import android.widget.LinearLayout
 import androidx.core.view.isVisible
 import androidx.fragment.app.viewModels
 import com.drake.brv.BindingAdapter
@@ -16,22 +15,19 @@ import com.google.android.flexbox.FlexWrap
 import com.google.android.flexbox.FlexboxLayoutManager
 import com.google.android.flexbox.JustifyContent
 import com.grkj.data.data.EventConstants
+import com.grkj.data.enums.HardwareMode
+import com.grkj.data.hardware.DockData
+import com.grkj.data.hardware.modbus.DockBean
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentInitDeviceRegistrationKeyAndLockBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyLayoutBinding
 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.CommonUtils
-import com.grkj.ui_base.utils.extension.tip
-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
@@ -96,33 +92,17 @@ class InitDeviceRegistrationKeyAndLockFragment :
                     "init_device_registration_key_and_lock_complete_step_hint"
                 )
             binding.dockRv.isVisible = it
-//            binding.checkDeviceInfo.isVisible = it
             binding.reRecognize.isVisible = it
             if (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 {
-                    DockData.KeyDock().apply {
-                        keyData.addAll(it.deviceList.filterIsInstance<DockBean.KeyBean>())
-                    }
-                }
-                val keyDatas = keyDock.map { it.keyData }.flatten()
+                val keyDock = HardwareMode.getCurrentHardwareMode().getKeyDockData()
+                val keyDatas = keyDock.flatMap { it.keyData }
                 val newKeyDock = DockData.KeyDock()
                 newKeyDock.keyData.addAll(keyDatas)
                 val newKeyDockList = newKeyDock.keyData.chunked(4).map { subList ->
                     DockData.KeyDock().apply { keyData.addAll(subList) }
                 }
-                val lockDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_LOCK }.map {
-                    DockData.LockDock().apply {
-                        lockData.addAll(it.deviceList.filterIsInstance<DockBean.LockBean>())
-                    }
-                }
-                val portableDock =
-                    dockData.filter { it.type == DeviceConst.DOCK_TYPE_PORTABLE }.map {
-                        DockData.PortableDock().apply {
-                            deviceData.addAll(it.deviceList.toList())
-                        }
-                    }
+                val lockDock = HardwareMode.getCurrentHardwareMode().getLockDockData()
+                val portableDock = HardwareMode.getCurrentHardwareMode().getPortableDock()
                 binding.reRecognize.isVisible =
                     (newKeyDockList + portableDock + lockDock).isNotEmpty()
                 val allDevice = newKeyDockList + portableDock + lockDock
@@ -144,11 +124,10 @@ class InitDeviceRegistrationKeyAndLockFragment :
     ) {
         val itemBinding = getBinding<ItemDeviceRegistrationLockLayoutBinding>()
         itemBinding.rvLockLayout.grid(10).dividerSpace(10, DividerOrientation.GRID).setup {
-            addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
+            addType<DockData.LockDock.LockBean>(R.layout.item_device_registration_lock)
             onBind {
                 val itemLockBinding = getBinding<ItemDeviceRegistrationLockBinding>()
-                val itemLock = getModel<DockBean.LockBean>()
-//                    itemLockBinding.tvNewDevice.isVisible = itemLock.newHardware
+                val itemLock = getModel<DockData.LockDock.LockBean>()
                 itemLockBinding.root.isSelected = itemLock.isExist
             }
         }.models = lockDock.lockData
@@ -165,12 +144,10 @@ class InitDeviceRegistrationKeyAndLockFragment :
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
         itemBinding.rvKeyLayout.setup {
-            addType<DockBean.KeyBean>(R.layout.item_device_registration_key)
+            addType<DockData.KeyDock.KeyBean>(R.layout.item_device_registration_key)
             onBind {
                 val itemKeyBinding = getBinding<ItemDeviceRegistrationKeyBinding>()
-                val itemKey = getModel<DockBean.KeyBean>()
-//                    itemKeyBinding.tvNewDevice.isVisible = itemKey.newHardware
-//                    itemKeyBinding.tvNewDeviceMac.isVisible = itemKey.mac?.isNotEmpty() == true
+                val itemKey = getModel<DockData.KeyDock.KeyBean>()
                 itemKeyBinding.tvNewDeviceMac.text = itemKey.mac
                 itemKeyBinding.ivKey.isSelected = itemKey.isExist
             }
@@ -187,22 +164,18 @@ class InitDeviceRegistrationKeyAndLockFragment :
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
         itemBinding.rvKeyLayout.setup {
-            addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
-            addType<DockBean.KeyBean>(R.layout.item_device_registration_protable_key)
+            addType<DockData.LockDock.LockBean>(R.layout.item_device_registration_lock)
+            addType<DockData.KeyDock.KeyBean>(R.layout.item_device_registration_protable_key)
             onBind {
                 when (val itemPortable = getModel<Any>()) {
-                    is DockBean.KeyBean -> {
+                    is DockData.KeyDock.KeyBean -> {
                         val itemKeyBinding = getBinding<ItemDeviceRegistrationKeyBinding>()
-//                            itemKeyBinding.tvNewDevice.isVisible = itemPortable.newHardware
-//                            itemKeyBinding.tvNewDeviceMac.isVisible =
-//                                itemPortable.mac?.isNotEmpty() == true
                         itemKeyBinding.tvNewDeviceMac.text = itemPortable.mac
                         itemKeyBinding.ivKey.isSelected = itemPortable.isExist
                     }
 
-                    is DockBean.LockBean -> {
+                    is DockData.LockDock.LockBean -> {
                         val itemLockBinding = getBinding<ItemDeviceRegistrationLockBinding>()
-//                            itemLockBinding.tvNewDevice.isVisible = itemPortable.newHardware
                         itemLockBinding.root.isSelected = itemPortable.isExist
                     }
                 }

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

@@ -7,7 +7,7 @@ import com.grkj.iscs.databinding.FragmentInitSetRemoteServerBinding
 import com.grkj.iscs.utils.ServerUtils
 import com.grkj.ui_base.base.BaseFragment
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.ui_base.utils.event.RestartAppEvent
+import com.grkj.data.utils.event.RestartAppEvent
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.extension.saveMMKVData
 import com.sik.sikcore.extension.setDebouncedClickListener

+ 0 - 29
app/src/main/java/com/grkj/iscs/features/init/model/DockData.kt

@@ -1,29 +0,0 @@
-package com.grkj.iscs.features.init.model
-
-import com.grkj.ui_base.utils.modbus.DockBean
-
-/**
- * Dock数据
- */
-interface DockData {
-    /**
-     * 钥匙Dock
-     */
-    class KeyDock : DockData {
-        val keyData: MutableList<DockBean.KeyBean> = mutableListOf()
-    }
-
-    /**
-     * 挂锁Dock
-     */
-    class LockDock : DockData {
-        val lockData: MutableList<DockBean.LockBean> = mutableListOf()
-    }
-
-    /**
-     * 便携Dock
-     */
-    class PortableDock : DockData {
-        val deviceData: MutableList<DockBean.DeviceBean> = mutableListOf()
-    }
-}

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

@@ -3,16 +3,17 @@ package com.grkj.iscs.features.init.viewmodel
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.liveData
+import com.grkj.data.config.ISCSConfig
 import com.grkj.data.data.MMKVConstants
+import com.grkj.data.enums.HardwareMode
+import com.grkj.data.hardware.DockData
+import com.grkj.data.hardware.ble.BleConnectionManager
+import com.grkj.data.hardware.modbus.DeviceConst
+import com.grkj.data.hardware.modbus.DockBean
 import com.grkj.data.logic.IHardwareLogic
 import com.grkj.data.model.dos.IsLockCabinetSlots
 import com.grkj.ui_base.base.BaseViewModel
-import com.grkj.ui_base.business.ModbusBusinessManager
-import com.grkj.ui_base.config.ISCSConfig
-import com.grkj.ui_base.utils.ble.BleConnectionManager
-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.grkj.ui_base.business.HardwareBusinessManager
 import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.thread.ThreadUtils
 import com.tencent.mmkv.MMKV
@@ -32,7 +33,8 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     var newHardwareKeySize: Int = 0
     var newHardwareLockSize: Int = 0
     var isInDeviceInit: Boolean = false
-    private val newHardwareKeyBean: MutableMap<Byte, MutableList<DockBean.KeyBean>> = mutableMapOf()
+    private val newHardwareKeyBean: MutableMap<Int, MutableList<DockData.KeyDock.KeyBean>> =
+        mutableMapOf()
     private val alreadyUsedMac: MutableList<String> = mutableListOf()
 
     /**
@@ -43,20 +45,21 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
             newHardwareKeyBean.clear()
             alreadyUsedMac.clear()
             isLoadComplete.postValue(false)
-            ModBusController.controlAllKeyBuckleOpen {
-                ModbusBusinessManager.registerInitListener {
+            HardwareMode.getCurrentHardwareMode().controlAllKeyBuckleOpen {
+                HardwareBusinessManager.registerInitListener {
                     if (!ISCSConfig.canInitDevice || isInDeviceInit) {
                         logger.info("设备录入-正在初始化设备:${ISCSConfig.canInitDevice},${isInDeviceInit}")
                         return@registerInitListener
                     }
                     isInDeviceInit = true
-                    val dockList = ModBusController.dockList
-                    if (dockList.size < DockBean.dockConfig.size) {
+                    if (HardwareMode.getCurrentHardwareMode().checkDock()) {
                         isInDeviceInit = true
                         return@registerInitListener
                     }
                     ThreadUtils.runOnIO {
-                        checkNewHardwareKey(dockList)
+                        checkNewHardwareKey(
+                            HardwareMode.getCurrentHardwareMode().getKeyDockData().toMutableList()
+                        )
                         emit(true)
                     }
                 }
@@ -67,23 +70,20 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     /**
      * 检查钥匙是否是新设备
      */
-    private fun checkNewHardwareKey(dockList: MutableList<DockBean>) {
+    private fun checkNewHardwareKey(dockList: MutableList<DockData.KeyDock>) {
         ThreadUtils.runOnIO {
             logger.info("设备录入-重新检测是否是新设备完成")
-            newHardwareKeyBean.putAll(dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
-                .associate {
-                    it.addr to it.deviceList.filterIsInstance<DockBean.KeyBean>()
-                        .filter { it.newHardware && it.isExist }
-                        .toMutableList()
-                })
+            dockList
+                .flatMap { it.keyData }
+                .groupBy { it.addr }
+                .mapValues { it.value.toMutableList() } // 把 List 转成 MutableList
+                .let { newHardwareKeyBean.putAll(it) }
             if (newHardwareKeyBean.isNotEmpty()) {
                 BleConnectionManager.deviceList.clear()
                 logger.info("断开所有蓝牙设备")
             }
             alreadyUsedMac.addAll(
-                dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
-                    .map { it.deviceList }.flatten().filterIsInstance<DockBean.KeyBean>()
-                    .filter { it.mac?.isNotEmpty() == true }.mapNotNull { it.mac }
+                dockList.map { it.keyData }.flatten().map { it.mac }
             )
             logger.debug("设备录入-新设备:${newHardwareKeyBean}")
             for ((addr, keyBeans) in newHardwareKeyBean) {
@@ -96,8 +96,8 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
             }
             newHardwareKeySize = newHardwareKeyBean.map { it.value }.flatten().size
             newHardwareLockSize =
-                ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
-                    .map { it.deviceList }.flatten().filterIsInstance<DockBean.LockBean>()
+                HardwareMode.getCurrentHardwareMode().getLockDockData().map { it.lockData }
+                    .flatten()
                     .count { it.newHardware && it.isExist }
             isLoadComplete.postValue(true)
         }
@@ -107,59 +107,64 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
      * 打开充电并扫描蓝牙
      */
     suspend fun openChargeAndScanMac(
-        addr: Byte,
-        keyBean: DockBean.KeyBean,
+        addr: Int,
+        keyBean: DockData.KeyDock.KeyBean,
         retryCount: Int = 3
     ): Boolean {
         return suspendCancellableCoroutine<Boolean> { cont ->
             logger.info("设备录入-关闭充电:${addr},${keyBean.idx}")
-            ModBusController.controlKeyCharge(false, keyBean.idx, addr) {
+            HardwareMode.getCurrentHardwareMode().controlKeyCharge(false, keyBean.idx, addr) {
                 ThreadUtils.runOnIO {
                     delay(800)
                     logger.info("设备录入-打开充电:${addr},${keyBean.idx}")
-                    ModBusController.controlKeyLockAndCharge(true, keyBean.idx, addr) {
-                        ThreadUtils.runOnIO {
-                            delay(3000)
-                            logger.info("设备录入-开始扫描在线蓝牙Mac")
-                            withContext(Dispatchers.Main) {
-                                BleConnectionManager.scanOnlineKeyLockMac(alreadyUsedMac) { mac ->
-                                    logger.info(
-                                        "设备录入-在线的蓝牙设备:${keyBean.rfid},${mac}"
-                                    )
-                                    if (isDestroy) {
+                    HardwareMode.getCurrentHardwareMode()
+                        .controlKeyLockAndCharge(true, keyBean.idx, addr) {
+                            ThreadUtils.runOnIO {
+                                delay(3000)
+                                logger.info("设备录入-开始扫描在线蓝牙Mac")
+                                withContext(Dispatchers.Main) {
+                                    BleConnectionManager.scanOnlineKeyLockMac(alreadyUsedMac) { mac ->
                                         logger.info(
-                                            "设备录入-界面已销毁"
+                                            "设备录入-在线的蓝牙设备:${keyBean.rfid},${mac}"
                                         )
-                                        cont.cancel()
-                                        return@scanOnlineKeyLockMac
-                                    }
-                                    if (mac == null) {
+                                        if (isDestroy) {
+                                            logger.info(
+                                                "设备录入-界面已销毁"
+                                            )
+                                            cont.cancel()
+                                            return@scanOnlineKeyLockMac
+                                        }
+                                        if (mac == null) {
+                                            logger.info(
+                                                "设备录入-设备mac空:${keyBean.rfid}"
+                                            )
+                                            ThreadUtils.runOnIO {
+                                                if (retryCount > 0) {
+                                                    openChargeAndScanMac(
+                                                        addr,
+                                                        keyBean,
+                                                        retryCount - 1
+                                                    )
+                                                } else {
+                                                    cont.resume(false)
+                                                }
+                                            }
+                                            return@scanOnlineKeyLockMac
+                                        }
                                         logger.info(
-                                            "设备录入-设备mac空:${keyBean.rfid}"
+                                            "设备录入-没有使用过的mac:${keyBean.rfid},${
+                                                mac
+                                            }"
                                         )
-                                        ThreadUtils.runOnIO {
-                                            if (retryCount > 0) {
-                                                openChargeAndScanMac(addr, keyBean, retryCount - 1)
-                                            } else {
-                                                cont.resume(false)
-                                            }
+                                        keyBean.mac = mac
+                                        alreadyUsedMac.add(mac)
+                                        if (cont.isActive) {
+                                            cont.resume(true)
                                         }
-                                        return@scanOnlineKeyLockMac
-                                    }
-                                    logger.info(
-                                        "设备录入-没有使用过的mac:${keyBean.rfid},${
-                                            mac
-                                        }"
-                                    )
-                                    keyBean.mac = mac
-                                    alreadyUsedMac.add(mac)
-                                    if (cont.isActive) {
-                                        cont.resume(true)
                                     }
                                 }
                             }
                         }
-                    }
                 }
             }
         }
@@ -169,7 +174,7 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
      * 取消监听
      */
     fun unregisterInitListener() {
-        ModbusBusinessManager.unRegisterInitListener()
+        HardwareBusinessManager.unRegisterInitListener()
     }
 
     /**
@@ -260,27 +265,21 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
      */
     fun deviceRegistrationData(): LiveData<Triple<Boolean, Int, Int>> {
         return liveData(Dispatchers.IO) {
-            val dockList = ModBusController.dockList
-            val deviceList = dockList.map { it.deviceList }.flatten()
-            var startIndex = 0
-            dockList.sortedBy { it.type }.forEachIndexed { index, dock ->
-                startIndex = deviceInputSlotsSuspend(index, dock, startIndex)
-            }
-            val lockDevice = deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_LOCK }
-                .filterIsInstance<DockBean.LockBean>()
-                .filter { it.newHardware == true && it.rfid != null }
-            val keyDevice = deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_KEY }
-                .filterIsInstance<DockBean.KeyBean>()
-                .filter { it.newHardware == true && it.rfid != null && it.mac != null }
+            val lockDevice = HardwareMode.getCurrentHardwareMode().getLockDockData()
+                .flatMap { it.lockData }
+                .filter { it.newHardware && it.rfid.isNotEmpty() }
+            val keyDevice = HardwareMode.getCurrentHardwareMode().getKeyDockData()
+                .flatMap { it.keyData }
+                .filter { it.newHardware && it.rfid.isNotEmpty() && it.mac.isNotEmpty() }
             lockDevice.forEach { lockDevice ->
-                val isBind = deviceInputLockSuspend(lockDevice.rfid.toString())
+                val isBind = deviceInputLockSuspend(lockDevice.rfid)
                 if (isBind) {
                     lockDevice.newHardware = false
                 }
             }
             keyDevice.forEach { keyDevice ->
                 val isBind =
-                    deviceInputKeySuspend(keyDevice.rfid.toString(), keyDevice.mac.toString())
+                    deviceInputKeySuspend(keyDevice.rfid, keyDevice.mac)
                 if (isBind) {
                     keyDevice.newHardware = false
                 }
@@ -288,8 +287,8 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
             emit(
                 Triple(
                     true,
-                    keyDevice.count { it.rfid?.isNotEmpty() == true && it.mac?.isNotEmpty() == true },
-                    lockDevice.count { it.rfid?.isNotEmpty() == true })
+                    keyDevice.count { it.rfid.isNotEmpty() && it.mac.isNotEmpty() },
+                    lockDevice.count { it.rfid.isNotEmpty() })
             )
         }
     }
@@ -322,7 +321,7 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         return liveData(Dispatchers.IO) {
             MMKV.defaultMMKV().removeValueForKey(MMKVConstants.KEY_PORT_CONFIG)
             MMKV.defaultMMKV().removeValueForKey(MMKVConstants.KEY_DOCK_CONFIG)
-            ModBusController.interruptReadTrashBinStatus(false)
+            HardwareMode.getCurrentHardwareMode().interruptReadTrashBinStatus(false)
             emit(true)
         }
     }

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

@@ -9,7 +9,6 @@ import com.grkj.iscs.databinding.DialogLoginBinding
 import com.grkj.iscs.features.login.viewmodel.LoginViewModel
 import com.grkj.shared.utils.ArcSoftUtil
 import com.grkj.shared.utils.ArcSoftUtil.inDetecting
-import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.data.utils.event.LoadingEvent

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt

@@ -28,7 +28,7 @@ import com.grkj.ui_base.base.BaseActivity
 import com.grkj.shared.utils.extension.toByteArrays
 import com.grkj.shared.utils.extension.toHexStrings
 import com.grkj.shared.utils.i18n.I18nManager
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
+import com.grkj.data.hardware.ble.BleSendDispatcher
 import com.grkj.ui_base.utils.event.FlashTipEvent
 import com.grkj.ui_base.utils.event.RFIDCardReadEvent
 import com.grkj.ui_base.utils.extension.removeTint

+ 0 - 2
app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt

@@ -8,7 +8,6 @@ import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogCheckFaceBinding
 import com.grkj.shared.utils.ArcSoftUtil
 import com.grkj.ui_base.base.BaseViewModel
-import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.data.utils.event.LoadingEvent
@@ -20,7 +19,6 @@ import com.kongzue.dialogx.interfaces.OnBindView
 import com.sik.sikandroid.activity.ActivityTracker
 import com.sik.sikcore.SIKCore
 import com.sik.sikcore.extension.setDebouncedClickListener
-import com.sik.sikcore.thread.ThreadUtils
 import com.sik.sikimage.ImageConvertUtils
 
 /**

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

@@ -6,7 +6,7 @@ import com.grkj.data.model.vo.AddUserDataVo
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogAddUserBinding
 import com.grkj.iscs.features.main.dialog.TextDropDownDialog
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.extension.tip
 import com.kongzue.dialogx.dialogs.CustomDialog

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

@@ -5,7 +5,7 @@ import androidx.core.view.isVisible
 import com.grkj.data.model.vo.UserManageFilterVo
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogFilterUserBinding
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.kongzue.dialogx.dialogs.CustomDialog
 import com.kongzue.dialogx.interfaces.OnBindView

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

@@ -7,7 +7,7 @@ import com.grkj.data.model.vo.UserManageVo
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogUpdateUserBinding
 import com.grkj.iscs.features.main.dialog.TextDropDownDialog
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.extension.tip
 import com.kongzue.dialogx.dialogs.CustomDialog

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataManageHomeFragment.kt

@@ -19,7 +19,7 @@ import com.grkj.iscs.databinding.ItemHomeMenuBinding
 import com.grkj.iscs.features.main.entity.MenuItemEntity
 import com.grkj.shared.utils.i18n.I18nManager
 import com.grkj.ui_base.base.BaseFragment
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.grkj.ui_base.utils.changeBgTint
 import com.grkj.ui_base.utils.event.BottomNavVisibilityEvent

+ 2 - 3
app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/SwitchLayoutFragment.kt

@@ -29,9 +29,8 @@ import com.grkj.iscs.features.main.viewmodel.data_manage.SwitchLayoutViewModel
 import com.grkj.shared.config.Constants
 import com.grkj.shared.model.EventBean
 import com.grkj.shared.utils.AssetsCopyUtil
-import com.grkj.shared.utils.i18n.I18nManager
 import com.grkj.ui_base.base.BaseFragment
-import com.grkj.ui_base.business.ModbusBusinessManager
+import com.grkj.ui_base.business.HardwareBusinessManager
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.widget.CustomSwitchStationLayer
@@ -144,7 +143,7 @@ class SwitchLayoutFragment : BaseFragment<FragmentSwitchLayoutBinding>() {
     private fun BindingAdapter.BindingViewHolder.onRVListBinding() {
         val itemBinding = getBinding<ItemSwitchBinding>()
         val item = getModel<MapInfoRespVO.IsMapPoint>()
-        val switchData = ModbusBusinessManager.getSwitchData()
+        val switchData = HardwareBusinessManager.getSwitchData()
         itemBinding.switchName.text = item.entityName
         itemBinding.switchId.text = CommonUtils.getStr("switch_id", item.pointNfc)
         val switchStatus = switchData

+ 61 - 52
app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/SlotsManageFragment.kt

@@ -14,26 +14,25 @@ import com.google.android.flexbox.FlexDirection
 import com.google.android.flexbox.FlexWrap
 import com.google.android.flexbox.FlexboxLayoutManager
 import com.google.android.flexbox.JustifyContent
+import com.grkj.data.config.ISCSConfig
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.enums.CommonDictDataEnum
+import com.grkj.data.enums.HardwareMode
 import com.grkj.data.enums.RoleEnum
+import com.grkj.data.hardware.DockData
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentSlotsManageBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyLayoutBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationLockLayoutBinding
 import com.grkj.iscs.databinding.ItemDeviceSlotManageKeyBinding
 import com.grkj.iscs.databinding.ItemDeviceSlotManageLockBinding
-import com.grkj.iscs.features.init.model.DockData
 import com.grkj.iscs.features.main.dialog.hardware_manage.SlotsExceptionReportDialog
 import com.grkj.iscs.features.main.viewmodel.hardware_manage.SlotsManageViewModel
 import com.grkj.shared.utils.i18n.I18nManager
 import com.grkj.ui_base.base.BaseFragment
-import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.data.utils.event.LoadingEvent
-import com.grkj.ui_base.utils.modbus.DockBean
-import com.grkj.ui_base.utils.modbus.ModBusController
 import com.sik.sikcore.extension.setDebouncedClickListener
 import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.AndroidEntryPoint
@@ -82,14 +81,18 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
         ) {
             ISCSConfig.isDeviceRegistration = true
         }
-        ModBusController.controlAllKeyChargeDown()
+        HardwareMode.getCurrentHardwareMode().controlAllKeyChargeDown()
         viewModel.isDestroy = false
     }
 
     /**
      * 显示长按菜单
      */
-    private fun showLongClickMenu(v: View, deviceBean: DockBean.DeviceBean, modelPosition: Int) {
+    private fun showLongClickMenu(
+        v: View,
+        deviceBean: DockData.DeviceBean,
+        modelPosition: Int
+    ) {
         SlotsExceptionReportDialog.show(
             requireContext(),
             deviceBean.row,
@@ -113,12 +116,12 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
     /**
      * 仓位检测
      */
-    private fun detectSlot(deviceBean: DockBean.DeviceBean) {
+    private fun detectSlot(deviceBean: DockData.DeviceBean) {
         when (deviceBean) {
-            is DockBean.KeyBean -> {
+            is DockData.KeyDock.KeyBean -> {
                 LoadingEvent.sendLoadingEvent(CommonUtils.getStr("start_detect_key_slot"))
                 ThreadUtils.runOnIO {
-                    ModBusController.readKeyRfidStr(
+                    HardwareMode.getCurrentHardwareMode().readKeyRfidStr(
                         deviceBean.addr,
                         deviceBean.idx
                     ) { idx, keyRfid ->
@@ -156,45 +159,49 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
                                         LoadingEvent.sendLoadingEvent()
                                         showToast(CommonUtils.getStr("key_info_already_exists"))
                                     }
-
                                 }
                         }
                     }
                 }
             }
 
-            is DockBean.LockBean -> {
+            is DockData.LockDock.LockBean -> {
                 LoadingEvent.sendLoadingEvent(CommonUtils.getStr("start_detect_lock_slot"))
                 ThreadUtils.runOnIO {
-                    ModBusController.readLockRfidStr(deviceBean.addr, deviceBean.idx) { lockRfid ->
-                        ThreadUtils.runOnMain {
-                            LoadingEvent.sendLoadingEvent(CommonUtils.getStr("check_lock_is_new_device"))
-                            viewModel.checkLockRfidIsNewDevice(lockRfid)
-                                .observe(this@SlotsManageFragment) {
-                                    LoadingEvent.sendLoadingEvent()
-                                    if (it) {
-                                        TipDialog.showInfo(
-                                            msg = CommonUtils.getStr("check_new_lock_need_register"),
-                                            onConfirmClick = {
-                                                viewModel.registerLockInfo(lockRfid)
-                                                    .observe(this@SlotsManageFragment) {
-                                                        if (it) {
-                                                            TipDialog.showSuccess(
-                                                                CommonUtils.getStr(
-                                                                    "register_success"
+                    HardwareMode.getCurrentHardwareMode()
+                        .readLockRfidStr(deviceBean.addr, deviceBean.idx) { lockRfid ->
+                            ThreadUtils.runOnMain {
+                                LoadingEvent.sendLoadingEvent(CommonUtils.getStr("check_lock_is_new_device"))
+                                viewModel.checkLockRfidIsNewDevice(lockRfid)
+                                    .observe(this@SlotsManageFragment) {
+                                        LoadingEvent.sendLoadingEvent()
+                                        if (it) {
+                                            TipDialog.showInfo(
+                                                msg = CommonUtils.getStr("check_new_lock_need_register"),
+                                                onConfirmClick = {
+                                                    viewModel.registerLockInfo(lockRfid)
+                                                        .observe(this@SlotsManageFragment) {
+                                                            if (it) {
+                                                                TipDialog.showSuccess(
+                                                                    CommonUtils.getStr(
+                                                                        "register_success"
+                                                                    )
                                                                 )
-                                                            )
-                                                        } else {
-                                                            TipDialog.showError(CommonUtils.getStr("register_failed"))
+                                                            } else {
+                                                                TipDialog.showError(
+                                                                    CommonUtils.getStr(
+                                                                        "register_failed"
+                                                                    )
+                                                                )
+                                                            }
                                                         }
-                                                    }
-                                            })
-                                    } else {
-                                        showToast(CommonUtils.getStr("lock_already_exists"))
+                                                })
+                                        } else {
+                                            showToast(CommonUtils.getStr("lock_already_exists"))
+                                        }
                                     }
-                                }
+                            }
                         }
-                    }
                 }
             }
 
@@ -205,21 +212,23 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
     /**
      * 仓位开关
      */
-    private fun slotSwitch(isOpen: Boolean, deviceBean: DockBean.DeviceBean) {
+    private fun slotSwitch(isOpen: Boolean, deviceBean: DockData.DeviceBean) {
         when (deviceBean) {
-            is DockBean.KeyBean -> {
-                ModBusController.controlKeyBuckle(isOpen, deviceBean.idx, deviceBean.addr)
-                ModBusController.controlKeyCharge(
+            is DockData.KeyDock.KeyBean -> {
+                HardwareMode.getCurrentHardwareMode()
+                    .controlKeyBuckle(isOpen, deviceBean.idx, deviceBean.addr)
+                HardwareMode.getCurrentHardwareMode().controlKeyCharge(
                     !isOpen, deviceBean.idx,
                     deviceBean.addr
                 )
+
             }
 
-            is DockBean.LockBean -> {
-                ModBusController.controlLockBuckle(
+            is DockData.LockDock.LockBean -> {
+                HardwareMode.getCurrentHardwareMode().controlLockBuckle(
                     isOpen,
                     deviceBean.addr,
-                    deviceBean.idx,
+                    deviceBean.idx
                 )
             }
 
@@ -240,10 +249,10 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
         // 强制请求重新布局
         itemBinding.rvKeyLayout.requestLayout()
         itemBinding.rvKeyLayout.setup {
-            addType<DockBean.KeyBean>(R.layout.item_device_slot_manage_key)
+            addType<DockData.KeyDock.KeyBean>(R.layout.item_device_slot_manage_key)
             onBind {
                 val itemKeyBinding = getBinding<ItemDeviceSlotManageKeyBinding>()
-                val itemKey = getModel<DockBean.KeyBean>()
+                val itemKey = getModel<DockData.KeyDock.KeyBean>()
                 itemKeyBinding.exceptionIv.isVisible =
                     viewModel.exceptionKeyData.find { it.keyNfc == itemKey.rfid } != null ||
                             viewModel.exceptionSlotsData.find {
@@ -319,10 +328,10 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
     ) {
         val itemBinding = getBinding<ItemDeviceRegistrationLockLayoutBinding>()
         itemBinding.rvLockLayout.grid(10).setup {
-            addType<DockBean.LockBean>(R.layout.item_device_slot_manage_lock)
+            addType<DockData.LockDock.LockBean>(R.layout.item_device_slot_manage_lock)
             onBind {
                 val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
-                val itemLock = getModel<DockBean.LockBean>()
+                val itemLock = getModel<DockData.LockDock.LockBean>()
                 itemLockBinding.exceptionIv.isVisible =
                     viewModel.exceptionLockData.find { it.lockNfc == itemLock.rfid } != null ||
                             viewModel.exceptionSlotsData.find {
@@ -402,11 +411,11 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
         itemBinding.rvKeyLayout.setup {
-            addType<DockBean.LockBean>(R.layout.item_device_slot_manage_lock)
-            addType<DockBean.KeyBean>(R.layout.item_device_registration_protable_key)
+            addType<DockData.LockDock.LockBean>(R.layout.item_device_slot_manage_lock)
+            addType<DockData.KeyDock.KeyBean>(R.layout.item_device_registration_protable_key)
             onBind {
                 when (val itemPortable = getModel<Any>()) {
-                    is DockBean.KeyBean -> {
+                    is DockData.KeyDock.KeyBean -> {
                         val itemKeyBinding = getBinding<ItemDeviceSlotManageKeyBinding>()
                         itemKeyBinding.exceptionIv.isVisible =
                             viewModel.exceptionKeyData.find { it.keyNfc == itemPortable.rfid } != null ||
@@ -479,7 +488,7 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
                         }
                     }
 
-                    is DockBean.LockBean -> {
+                    is DockData.LockDock.LockBean -> {
                         val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
                         itemLockBinding.exceptionIv.isVisible =
                             viewModel.exceptionLockData.find { it.lockNfc == itemPortable.rfid } != null ||

+ 12 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SettingsFragment.kt

@@ -10,6 +10,7 @@ import com.grkj.iscs.features.main.dialog.TextDropDownDialog
 import com.grkj.shared.utils.CountdownTimer
 import com.grkj.ui_base.base.BaseFragment
 import com.grkj.ui_base.utils.CommonUtils
+import com.grkj.data.utils.event.RestartAppEvent
 import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.extension.saveMMKVData
 import com.sik.sikcore.extension.setDebouncedClickListener
@@ -20,6 +21,10 @@ import dagger.hilt.android.AndroidEntryPoint
  */
 @AndroidEntryPoint
 class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
+    /**
+     * 硬件模式修改
+     */
+    private var hardwareModeChanged: Boolean = false
     override fun getLayoutId(): Int {
         return R.layout.fragment_settings
     }
@@ -50,6 +55,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
             TextDropDownDialog.showSingle(hardwareModeData, binding.hardwareMode) {
                 binding.hardwareMode.text = it.getShowText()
                 MMKVConstants.KEY_HARDWARE_MODE.saveMMKVData(it.getShowText())
+                hardwareModeChanged = true
             }
         }
         binding.confirm.setDebouncedClickListener {
@@ -63,7 +69,12 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
                     autoLogoutTime
                 )
                 CountdownTimer.reset(autoLogoutTime)
-                showToast(CommonUtils.getStr("save_success"))
+                if (hardwareModeChanged) {
+                    showToast(CommonUtils.getStr("save_success"))
+                    RestartAppEvent.sendRestartAppEvent()
+                } else {
+                    showToast(CommonUtils.getStr("save_success"))
+                }
             }
         }
     }

+ 115 - 48
app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt

@@ -3,31 +3,31 @@ package com.grkj.iscs.features.main.viewmodel
 import android.annotation.SuppressLint
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
+import com.grkj.data.config.ISCSConfig
+import com.grkj.data.data.MMKVConstants
 import com.grkj.data.data.MainDomainData
+import com.grkj.data.enums.HardwareMode
+import com.grkj.data.hardware.ble.BleBean
+import com.grkj.data.hardware.ble.BleConnectionManager
+import com.grkj.data.hardware.ble.BleIndicateListener
+import com.grkj.data.hardware.ble.BleReturnDispatcher
+import com.grkj.data.hardware.can.CanCommands
+import com.grkj.data.hardware.can.CanDeviceConst
+import com.grkj.data.hardware.can.CanHelper
+import com.grkj.data.hardware.can.DeviceModel
+import com.grkj.data.hardware.modbus.DeviceConst
 import com.grkj.data.logic.IJobTicketLogic
-import com.grkj.shared.utils.extension.startsWith
-import com.grkj.ui_base.R
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.BleBusinessManager
 import com.grkj.ui_base.business.DataBusiness
-import com.grkj.ui_base.business.ModbusBusinessManager
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.ui_base.business.HardwareBusinessManager
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.Executor
-import com.grkj.ui_base.utils.ble.BleBean
-import com.grkj.ui_base.utils.ble.BleCmdManager
-import com.grkj.ui_base.utils.ble.BleConnectionManager
-import com.grkj.ui_base.utils.ble.BleConst
-import com.grkj.ui_base.utils.ble.BleIndicateListener
-import com.grkj.ui_base.utils.ble.BleReturnDispatcher
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
-import com.grkj.data.utils.event.LoadingEvent
-import com.grkj.ui_base.utils.modbus.DeviceConst
-import com.grkj.ui_base.utils.modbus.ModBusController
+import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
 import javax.inject.Inject
 
 /**
@@ -81,53 +81,120 @@ class MainViewModel @Inject constructor(
     /**
      * 取消注册状态监听
      */
-    fun unregisterStatusListener(){
-        ModbusBusinessManager.unregisterListener(this)
+    fun unregisterStatusListener() {
+        if (MMKVConstants.KEY_HARDWARE_MODE.getMMKVData(HardwareMode.MODBUS.name) == HardwareMode.MODBUS.name) {
+            HardwareBusinessManager.unregisterListener(this)
+        } else {
+            HardwareBusinessManager.unregisterCanListener(this)
+        }
     }
 
     /**
      * 注册状态监听
      */
     fun registerStatusListener() {
-        ModbusBusinessManager.registerStatusListener(this) { dockBean ->
-            if (MainDomainData.userInfo == null || ISCSConfig.isDeviceRegistration) {
-                return@registerStatusListener
+        if (MMKVConstants.KEY_HARDWARE_MODE.getMMKVData(HardwareMode.MODBUS.name) == HardwareMode.MODBUS.name) {
+            HardwareBusinessManager.registerStatusListener(this) { dockBean ->
+                if (MainDomainData.userInfo == null || ISCSConfig.isDeviceRegistration) {
+                    return@registerStatusListener
+                }
+                when (dockBean.type) {
+                    DeviceConst.DOCK_TYPE_KEY -> {
+                        dockBean.getKeyList().forEach { keyBean ->
+                            if (keyBean.isExist) {
+                                keyBean.mac?.let { mac ->
+                                    ThreadUtils.runOnIO {
+                                        @SuppressLint("MissingPermission")
+                                        fun readJobTicket(mac: String) {
+                                            ThreadUtils.runOnIO {
+                                                BleReturnDispatcher.submit(mac) { isConnect ->
+                                                    if (isConnect) {
+                                                        val bleBean =
+                                                            BleConnectionManager.getBleDeviceByMac(
+                                                                mac
+                                                            )
+                                                        Executor.delayOnMain(300) {
+                                                            bleBean?.let {
+                                                                LoadingEvent.sendLoadingEvent(
+                                                                    CommonUtils.getStr("loading_msg_get_ticket_status_start"),
+                                                                    true
+                                                                )
+                                                                BleConnectionManager.getCurrentStatus(
+                                                                    4,
+                                                                    it.bleDevice
+                                                                )
+                                                            }
+                                                        }
+                                                    } else {
+                                                        HardwareMode.getCurrentHardwareMode()
+                                                            .controlKeyBuckle(true, mac) {
+                                                                showTip(
+                                                                    CommonUtils.getStr("ticket_get_failed")
+                                                                        .toString()
+                                                                )
+                                                            }
+                                                    }
+                                                }
+                                            }
+                                        }
+                                        if (!ISCSConfig.isDeviceRegistration) {
+                                            readJobTicket(mac)
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
             }
-            when (dockBean.type) {
-                DeviceConst.DOCK_TYPE_KEY -> {
-                    dockBean.getKeyList().forEach { keyBean ->
-                        if (keyBean.isExist) {
-                            keyBean.mac?.let { mac ->
-                                ThreadUtils.runOnIO {
-                                    @SuppressLint("MissingPermission")
-                                    fun readJobTicket(mac: String) {
-                                        ThreadUtils.runOnIO {
-                                            BleReturnDispatcher.submit(mac) { isConnect ->
-                                                if (isConnect) {
-                                                    val bleBean =
-                                                        BleConnectionManager.getBleDeviceByMac(mac)
-                                                    Executor.delayOnMain(300) {
-                                                        bleBean?.let {
-                                                            LoadingEvent.sendLoadingEvent(
-                                                                CommonUtils.getStr("loading_msg_get_ticket_status_start"),
-                                                                true
+        } else {
+            HardwareBusinessManager.registerCanStatusListener(this) { deviceDatas ->
+                if (MainDomainData.userInfo == null || ISCSConfig.isDeviceRegistration) {
+                    return@registerCanStatusListener
+                }
+                deviceDatas.filterIsInstance<DeviceModel.DeviceKey>().forEach { deviceModel ->
+                    when (deviceModel.deviceType) {
+                        CanDeviceConst.DEVICE_KEY_DOCK -> {
+                            if (deviceModel.isExist) {
+                                deviceModel.mac.let { mac ->
+                                    ThreadUtils.runOnIO {
+                                        @SuppressLint("MissingPermission")
+                                        fun readJobTicket(mac: String) {
+                                            ThreadUtils.runOnIO {
+                                                BleReturnDispatcher.submit(mac) { isConnect ->
+                                                    if (isConnect) {
+                                                        val bleBean =
+                                                            BleConnectionManager.getBleDeviceByMac(
+                                                                mac
                                                             )
-                                                            BleConnectionManager.getCurrentStatus(
-                                                                4,
-                                                                it.bleDevice
+                                                        Executor.delayOnMain(300) {
+                                                            bleBean?.let {
+                                                                LoadingEvent.sendLoadingEvent(
+                                                                    CommonUtils.getStr("loading_msg_get_ticket_status_start"),
+                                                                    true
+                                                                )
+                                                                BleConnectionManager.getCurrentStatus(
+                                                                    4,
+                                                                    it.bleDevice
+                                                                )
+                                                            }
+                                                        }
+                                                    } else {
+                                                        val req =
+                                                            CanCommands.forDevice(deviceModel.nodeId)
+                                                                .controlLatch(deviceModel.id, 0)
+                                                        CanHelper.writeTo(req) {
+                                                            showTip(
+                                                                CommonUtils.getStr("ticket_get_failed")
                                                             )
                                                         }
                                                     }
-                                                }else{
-                                                    ModBusController.controlKeyBuckle(true,mac){
-                                                        showTip(CommonUtils.getStr("ticket_get_failed").toString())
-                                                    }
                                                 }
                                             }
                                         }
-                                    }
-                                    if (!ISCSConfig.isDeviceRegistration) {
-                                        readJobTicket(mac)
+                                        if (!ISCSConfig.isDeviceRegistration) {
+                                            readJobTicket(mac)
+                                        }
                                     }
                                 }
                             }

+ 3 - 4
app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionViewModel.kt

@@ -10,12 +10,11 @@ import com.grkj.data.model.vo.IsExceptionStandardVo
 import com.grkj.data.logic.IExceptionLogic
 import com.grkj.data.logic.IHardwareLogic
 import com.grkj.data.logic.IJobTicketLogic
-import com.grkj.iscs.R
 import com.grkj.iscs.features.main.entity.ExceptionSourceDataEntity
 import com.grkj.shared.utils.i18n.I18nManager
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.DataBusiness
-import com.grkj.ui_base.business.ModbusBusinessManager
+import com.grkj.ui_base.business.HardwareBusinessManager
 import com.grkj.ui_base.utils.CommonUtils
 import com.sik.sikcore.extension.toJson
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -287,7 +286,7 @@ class ExceptionViewModel @Inject constructor(
                         val exceptionSourceDataEntity =
                             ExceptionSourceDataEntity(itemGroupPosition = 1)
                         exceptionSourceDataEntity.sourceDataText =
-                            "钥匙${it.keyNfc}(${ModbusBusinessManager.getKeySlotPosition(it.keyNfc ?: "")})"
+                            "钥匙${it.keyNfc}(${HardwareBusinessManager.getKeySlotPosition(it.keyNfc ?: "")})"
                         exceptionSourceDataEntity.sourceDataId = it.keyId
                         exceptionSourceDataEntity.sourceDataType =
                             exceptionSourceDataType.find { I18nManager.t(it.dictLabel) == I18nManager.t("key") }?.dictValue?.toInt()
@@ -315,7 +314,7 @@ class ExceptionViewModel @Inject constructor(
                         val exceptionSourceDataEntity =
                             ExceptionSourceDataEntity(itemGroupPosition = 1)
                         exceptionSourceDataEntity.sourceDataText =
-                            "挂锁${it.lockNfc}(${ModbusBusinessManager.getLockSlotPosition(it.lockNfc ?: "")})"
+                            "挂锁${it.lockNfc}(${HardwareBusinessManager.getLockSlotPosition(it.lockNfc ?: "")})"
                         exceptionSourceDataEntity.sourceDataId = it.lockId
                         exceptionSourceDataEntity.sourceDataType =
                             exceptionSourceDataType.find { I18nManager.t(it.dictLabel) ==  I18nManager.t("lock")  }?.dictValue?.toInt()

+ 38 - 52
app/src/main/java/com/grkj/iscs/features/main/viewmodel/hardware_manage/SlotsManageViewModel.kt

@@ -2,17 +2,17 @@ package com.grkj.iscs.features.main.viewmodel.hardware_manage
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
+import com.grkj.data.enums.HardwareMode
 import com.grkj.data.model.dos.IsKey
 import com.grkj.data.model.dos.IsLock
 import com.grkj.data.model.dos.IsLockCabinetSlots
 import com.grkj.data.logic.IHardwareLogic
-import com.grkj.iscs.features.init.model.DockData
+import com.grkj.data.hardware.DockData
 import com.grkj.ui_base.base.BaseViewModel
-import com.grkj.ui_base.business.ModbusBusinessManager
-import com.grkj.ui_base.utils.ble.BleConnectionManager
-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.grkj.ui_base.business.HardwareBusinessManager
+import com.grkj.data.hardware.ble.BleConnectionManager
+import com.grkj.data.hardware.modbus.DeviceConst
+import com.grkj.data.hardware.modbus.DockBean
 import com.sik.sikcore.extension.toJson
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Dispatchers
@@ -56,7 +56,7 @@ class SlotsManageViewModel @Inject constructor(
      * 注册监听
      */
     fun registerStatusListener(statusListener: (DockBean) -> Unit) {
-        ModbusBusinessManager.registerStatusListener(this) {
+        HardwareBusinessManager.registerStatusListener(this) {
             statusListener(it)
         }
     }
@@ -65,7 +65,7 @@ class SlotsManageViewModel @Inject constructor(
      * 取消注册
      */
     fun unregisterStatusListener() {
-        ModbusBusinessManager.unregisterListener(this)
+        HardwareBusinessManager.unregisterListener(this)
     }
 
     /**
@@ -186,7 +186,7 @@ class SlotsManageViewModel @Inject constructor(
     /**
      * 检查钥匙mac
      */
-    fun detectKeyMac(keyBean: DockBean.KeyBean): LiveData<String> {
+    fun detectKeyMac(keyBean: DockData.KeyDock.KeyBean): LiveData<String> {
         return liveData(Dispatchers.IO) {
             val mac = detectNewKeyMac(keyBean)
             emit(mac)
@@ -196,70 +196,56 @@ class SlotsManageViewModel @Inject constructor(
     /**
      * 检测新钥匙mac地址
      */
-    private suspend fun detectNewKeyMac(keyBean: DockBean.KeyBean): String {
+    private suspend fun detectNewKeyMac(keyBean: DockData.KeyDock.KeyBean): String {
         val mac = suspendCancellableCoroutine { cont ->
             val existsKeyMac =
                 hardwareRepository.getAllKeyInfo().mapNotNull { it.macAddress }.toList()
             logger.info("设备检测-打开充电:${keyBean.addr},${keyBean.idx}")
-            ModBusController.controlKeyLockAndCharge(true, keyBean.idx, keyBean.addr) {
-                logger.info("设备检测-开始扫描在线蓝牙Mac")
-                BleConnectionManager.scanOnlineKeyLockMac(existsKeyMac) { mac ->
-                    logger.info(
-                        "设备检测-在线的蓝牙设备:${keyBean.rfid},${mac}"
-                    )
-                    if (isDestroy) {
+            HardwareMode.getCurrentHardwareMode()
+                .controlKeyLockAndCharge(false, keyBean.idx, keyBean.addr) {
+                    logger.info("设备检测-开始扫描在线蓝牙Mac")
+                    BleConnectionManager.scanOnlineKeyLockMac(existsKeyMac) { mac ->
                         logger.info(
-                            "设备检测-界面已销毁"
+                            "设备检测-在线的蓝牙设备:${keyBean.rfid},${mac}"
                         )
-                        return@scanOnlineKeyLockMac
-                    }
-                    if (mac == null) {
+                        if (isDestroy) {
+                            logger.info(
+                                "设备检测-界面已销毁"
+                            )
+                            return@scanOnlineKeyLockMac
+                        }
+                        if (mac == null) {
+                            logger.info(
+                                "设备检测-设备mac空:${keyBean.rfid}"
+                            )
+                            return@scanOnlineKeyLockMac
+                        }
                         logger.info(
-                            "设备检测-设备mac空:${keyBean.rfid}"
+                            "设备检测-没有使用过的mac:${keyBean.rfid},${
+                                mac
+                            }"
                         )
-                        return@scanOnlineKeyLockMac
-                    }
-                    logger.info(
-                        "设备检测-没有使用过的mac:${keyBean.rfid},${
-                            mac
-                        }"
-                    )
-                    keyBean.mac = mac
-                    if (cont.isActive) {
-                        cont.resume(mac)
+                        keyBean.mac = mac
+                        if (cont.isActive) {
+                            cont.resume(mac)
+                        }
                     }
                 }
-            }
         }
         return mac
     }
 
     fun getData(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
-            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 {
-                DockData.KeyDock().apply {
-                    keyData.addAll(it.deviceList.filterIsInstance<DockBean.KeyBean>())
-                }
-            }
-            val keyDatas = keyDock.map { it.keyData }.flatten()
+            val keyDock = HardwareMode.getCurrentHardwareMode().getKeyDockData()
+            val keyDatas = keyDock.flatMap { it.keyData }
             val newKeyDock = DockData.KeyDock()
             newKeyDock.keyData.addAll(keyDatas)
             val newKeyDockList = newKeyDock.keyData.chunked(4).map { subList ->
                 DockData.KeyDock().apply { keyData.addAll(subList) }
             }
-            val lockDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_LOCK }.map {
-                DockData.LockDock().apply {
-                    lockData.addAll(it.deviceList.filterIsInstance<DockBean.LockBean>())
-                }
-            }
-            val portableDock =
-                dockData.filter { it.type == DeviceConst.DOCK_TYPE_PORTABLE }.map {
-                    DockData.PortableDock().apply {
-                        deviceData.addAll(it.deviceList.toList())
-                    }
-                }
+            val lockDock = HardwareMode.getCurrentHardwareMode().getLockDockData()
+            val portableDock = HardwareMode.getCurrentHardwareMode().getPortableDock()
             lastDockSnapshot.clear()
             lastDockSnapshot.addAll(newKeyDockList + portableDock + lockDock)
             emit(true)

+ 29 - 29
app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt

@@ -4,8 +4,13 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.di.LogicManager
+import com.grkj.data.enums.HardwareMode
 import com.grkj.data.enums.JobTicketStatusEnum
 import com.grkj.data.enums.RoleEnum
+import com.grkj.data.hardware.modbus.DeviceConst
+import com.grkj.data.logic.IJobTicketLogic
+import com.grkj.data.logic.IWorkflowLogic
+import com.grkj.data.logic.impl.standard.UserLogic
 import com.grkj.data.model.dos.IsJobTicketStep
 import com.grkj.data.model.dos.WorkflowMode
 import com.grkj.data.model.local.DeviceTakeUpdate
@@ -19,28 +24,23 @@ import com.grkj.data.model.vo.JobTicketGroupDataVo
 import com.grkj.data.model.vo.JobTicketGroupInfoVo
 import com.grkj.data.model.vo.JobUserVo
 import com.grkj.data.model.vo.SysBiometricDataVo
-import com.grkj.data.logic.IJobTicketLogic
-import com.grkj.data.logic.IWorkflowLogic
-import com.grkj.data.logic.impl.standard.UserLogic
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.BleBusinessManager
 import com.grkj.ui_base.business.DataBusiness
-import com.grkj.ui_base.business.ModbusBusinessManager
+import com.grkj.ui_base.business.HardwareBusinessManager
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.event.UiEvent
 import com.grkj.ui_base.utils.extension.tip
-import com.grkj.ui_base.utils.modbus.DeviceConst
-import com.grkj.ui_base.utils.modbus.ModBusController
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.data.BeanUtils
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.lifecycle.HiltViewModel
-import javax.inject.Inject
 import kotlinx.coroutines.Dispatchers
 import java.util.concurrent.atomic.AtomicInteger
+import javax.inject.Inject
 
 /**
  * 作业执行数据
@@ -218,24 +218,24 @@ class JobExecuteViewModel @Inject constructor(
      */
     fun toLock(groupId: Long): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
                     DeviceConst.DEVICE_TYPE_LOCK, ticketId
                 )
             ) {
                 showLoading(CommonUtils.getStr("please_take_out_ready_device_first"))
                 return@liveData
             }
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
                     DeviceConst.DEVICE_TYPE_KEY, ticketId
                 )
             ) {
                 showLoading(CommonUtils.getStr("check_key_and_lock"))
-                val rfid = ModbusBusinessManager.getWaitTakeDeviceByTicketId(
+                val rfid = HardwareBusinessManager.getWaitTakeDeviceByTicketId(
                     DeviceConst.DEVICE_TYPE_KEY, ticketId
                 )?.nfc
                 if (rfid != null) {
-                    val keyMac = ModbusBusinessManager.getKeyMacByRfid(rfid)
-                    ModbusBusinessManager.checkTicketAndSendTicket(keyMac)
+                    val keyMac = HardwareBusinessManager.getKeyMacByRfid(rfid)
+                    HardwareBusinessManager.checkTicketAndSendTicket(keyMac)
                     return@liveData
                 } else {
                     hideLoading()
@@ -265,7 +265,7 @@ class JobExecuteViewModel @Inject constructor(
             if (!verifySuccess) {
                 return@liveData
             }
-            ModbusBusinessManager.checkEquipCount(ticketId, ticketPoints.count {
+            HardwareBusinessManager.checkEquipCount(ticketId, ticketPoints.count {
                 it.groupId == groupId && (it.pointStatus == "0" || (it.pointStatus == "2" && isUnlockFirst))
             }, true) { keyMap, lockMap ->
                 if (lockMap.isEmpty()) {
@@ -296,8 +296,8 @@ class JobExecuteViewModel @Inject constructor(
                         })
                     return@checkEquipCount
                 } else {
-                    ModbusBusinessManager.addDeviceTake(
-                        DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second?.rfid!!
+                    HardwareBusinessManager.addDeviceTake(
+                        DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second!!
                     )
                 }
                 MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
@@ -305,12 +305,12 @@ class JobExecuteViewModel @Inject constructor(
                 val openedLockDockSize = AtomicInteger(0)
                 lockMap.keys.forEach { lockDockAddr ->
                     lockMap[lockDockAddr]?.let { lockList ->
-                        ModBusController.controlLockBuckle(
-                            true, lockDockAddr, lockList.map { it.idx }.toMutableList()
+                        HardwareMode.getCurrentHardwareMode().controlLockBuckle(
+                            true, lockDockAddr as Int?, lockList.map { it.first }.toMutableList()
                         ) {
                             lockList.forEach { lock ->
-                                ModbusBusinessManager.addDeviceTake(
-                                    DeviceConst.DEVICE_TYPE_LOCK, ticketId, lock.rfid
+                                HardwareBusinessManager.addDeviceTake(
+                                    DeviceConst.DEVICE_TYPE_LOCK, ticketId, lock.second
                                 )
                             }
                             openedLockDockSize.addAndGet(1)
@@ -336,24 +336,24 @@ class JobExecuteViewModel @Inject constructor(
      */
     fun toUnLock(groupId: Long): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
                     DeviceConst.DEVICE_TYPE_LOCK, ticketId
                 )
             ) {
                 showLoading(CommonUtils.getStr("please_take_out_ready_device_first"))
                 return@liveData
             }
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
                     DeviceConst.DEVICE_TYPE_KEY, ticketId
                 )
             ) {
                 showLoading(CommonUtils.getStr("check_key_and_lock"))
-                val rfid = ModbusBusinessManager.getWaitTakeDeviceByTicketId(
+                val rfid = HardwareBusinessManager.getWaitTakeDeviceByTicketId(
                     DeviceConst.DEVICE_TYPE_KEY, ticketId
                 )?.nfc
                 if (rfid != null) {
-                    val keyMac = ModbusBusinessManager.getKeyMacByRfid(rfid)
-                    ModbusBusinessManager.checkTicketAndSendTicket(keyMac)
+                    val keyMac = HardwareBusinessManager.getKeyMacByRfid(rfid)
+                    HardwareBusinessManager.checkTicketAndSendTicket(keyMac)
                     return@liveData
                 } else {
                     hideLoading()
@@ -393,7 +393,7 @@ class JobExecuteViewModel @Inject constructor(
                     MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
                     BleBusinessManager.handleUnlockVirtualKeyReturn(ticketId, groupId)
                 } else {
-                    ModbusBusinessManager.checkEquipCount(ticketId, 0, true) { keyMap, _ ->
+                    HardwareBusinessManager.checkEquipCount(ticketId, 0, true) { keyMap, _ ->
                         LoadingEvent.sendLoadingEvent()
                         if (keyMap == null) {
                             TipDialog.show(
@@ -407,13 +407,13 @@ class JobExecuteViewModel @Inject constructor(
                             return@checkEquipCount
                         }
                         MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
-                        ModbusBusinessManager.addDeviceTake(
-                            DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second?.rfid!!
+                        HardwareBusinessManager.addDeviceTake(
+                            DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second!!
                         )
                         val deviceTakeUpdate = DeviceTakeUpdate(
                             DeviceConst.DEVICE_TYPE_KEY,
                             ticketId,
-                            keyMap.second?.rfid ?: "",
+                            keyMap.second ?: "",
                         )
                         BleBusinessManager.handleGiveKey(deviceTakeUpdate)
                     }

+ 1 - 0
data/build.gradle.kts

@@ -61,4 +61,5 @@ dependencies {
     // 可选:给 StAX 一个高性能实现(建议一起加,兼容更好)
     api("com.fasterxml.woodstox:woodstox-core:6.5.1")
     api("org.codehaus.woodstox:stax2-api:4.2.1")
+    api(libs.fastble)
 }

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/config/ISCSConfig.kt → data/src/main/java/com/grkj/data/config/ISCSConfig.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.config
+package com.grkj.data.config
 
 import com.grkj.data.data.MMKVConstants
 import com.sik.sikcore.extension.getMMKVData

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

@@ -65,6 +65,10 @@ object EventConstants {
      * 备份完成推送
      */
     const val EVENT_BACKUP_COMPLETE_CODE: Int = 100_000_012
+    /**
+     * 提示代码
+     */
+    const val EVENT_TOAST_CODE: Int = 100_000_013
 
     //---------------------------作业票------------------------
     const val EVENT_GET_TICKET_STATUS: Int = 100_001_001

+ 20 - 0
data/src/main/java/com/grkj/data/enums/HardwareMode.kt

@@ -1,9 +1,29 @@
 package com.grkj.data.enums
 
+import com.grkj.data.data.MMKVConstants
+import com.grkj.data.hardware.IHardwareHelper
+import com.grkj.data.hardware.can.CanHardwareHelper
+import com.grkj.data.hardware.modbus.ModBusHardwareHelper
+import com.sik.sikcore.extension.getMMKVData
+
 /**
  * 硬件模式
  */
 enum class HardwareMode {
+
     MODBUS, CAN;
 
+    companion object {
+        /**
+         * 根据当前硬件模式获取硬件读写帮助类
+         */
+        fun getCurrentHardwareMode(): IHardwareHelper {
+            val currentHardwareMode =
+                valueOf(MMKVConstants.KEY_HARDWARE_MODE.getMMKVData(MODBUS.name))
+            return when (currentHardwareMode) {
+                MODBUS -> ModBusHardwareHelper()
+                CAN -> CanHardwareHelper()
+            }
+        }
+    }
 }

+ 48 - 0
data/src/main/java/com/grkj/data/hardware/DockData.kt

@@ -0,0 +1,48 @@
+package com.grkj.data.hardware
+
+/**
+ * Dock数据
+ */
+interface DockData {
+    /**
+     * 设备数据
+     */
+    open class DeviceBean {
+        var addr: Int = 0
+        var idx: Int = 0
+        var isExist: Boolean = false
+        var row: Int = 0
+        var type: Int = -1
+        var rfid: String = ""
+        var isReady: Boolean = false
+        var newHardware: Boolean = false
+    }
+
+    /**
+     * 钥匙Dock
+     */
+    class KeyDock : DockData {
+        val keyData: MutableList<KeyBean> = mutableListOf()
+
+        class KeyBean : DeviceBean() {
+            var mac: String = ""
+        }
+    }
+
+    /**
+     * 挂锁Dock
+     */
+    class LockDock : DockData {
+        val lockData: MutableList<LockBean> = mutableListOf()
+
+        class LockBean : DeviceBean() {
+        }
+    }
+
+    /**
+     * 便携Dock
+     */
+    class PortableDock : DockData {
+        val deviceData: MutableList<DeviceBean> = mutableListOf()
+    }
+}

+ 170 - 0
data/src/main/java/com/grkj/data/hardware/IHardwareHelper.kt

@@ -0,0 +1,170 @@
+package com.grkj.data.hardware
+
+import com.grkj.data.model.res.CabinetSlotsRecord
+
+/**
+ * 硬件操作帮助类
+ */
+interface IHardwareHelper {
+    /**
+     * 根据钥匙的RFID获取MAC地址
+     */
+    fun getKeyMacByRfid(rfid: String): String?
+
+    /**
+     * 获取挂锁
+     */
+    fun getLocks(
+        needLockCount: Int,
+        exceptionSlots: MutableList<CabinetSlotsRecord>,
+        exceptionLocks: MutableList<String>
+    ): MutableMap<Any, MutableList<Pair<Int, String>>>
+
+    /**
+     * 获取钥匙
+     */
+    suspend fun getOneKey(
+        exceptionSlots: List<CabinetSlotsRecord>,
+        exceptionKeysRfid: List<String>,
+        exceptionKeysMac: List<String> = mutableListOf()
+    ): Pair<Any, String?>?
+
+    /**
+     * 根据钥匙的MAC地址获取RFID
+     */
+    fun getRfidByKeyMac(keyMac: String): String?
+
+    /**
+     * 根据钥匙的RFID获取位置
+     */
+    fun getSlotPosition(keyNfc: String): String
+
+    /**
+     * 根据挂锁的RFID获取位置
+     */
+    fun getLockSlotPosition(lockNfc: String): String
+
+    /**
+     * 获取已经存在的钥匙MAC
+     */
+    fun getExistsKeyMac(): List<String>
+
+    /**
+     * 控制钥匙仓锁控和充电
+     */
+    fun controlKeyLockAndCharge(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)? = null
+    )
+
+    /**
+     * 获取钥匙数据
+     */
+    fun getKeyDockData(): List<DockData.KeyDock>
+
+    /**
+     * 获取挂锁数据
+     */
+    fun getLockDockData(): List<DockData.LockDock>
+
+    /**
+     * 获取便携柜数据
+     */
+    fun getPortableDock(): List<DockData.PortableDock>
+
+    /**
+     * 控制钥匙仓位
+     */
+    fun controlKeyBuckle(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((res: ByteArray) -> Unit)? = null)
+
+    /**
+     * 控制钥匙仓位根据mac地址
+     */
+    fun controlKeyBuckle(isOpen: Boolean,mac: String,done: ((ByteArray) -> Unit)? = null)
+
+    /**
+     * 控制仓位充电
+     */
+    fun controlKeyCharge(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((res: ByteArray) -> Unit)? = null)
+
+    /**
+     * 根据mac地址开关充电
+     */
+    fun controlKeyCharge(
+        isOpen: Boolean,
+        mac: String,
+        done: ((res: ByteArray) -> Unit)? = null
+    )
+
+    /**
+     * 控制锁仓
+     */
+    fun controlLockBuckle(
+        isOpen: Boolean,
+        slaveAddress: Int?,
+        lockIdxList: Int,
+        done: ((res: ByteArray) -> Unit)? = null)
+    /**
+     * 批量控制锁仓
+     */
+    fun controlLockBuckle(
+        isOpen: Boolean,
+        slaveAddress: Int?,
+        lockIdxList: MutableList<Int>,
+        done: ((res: ByteArray) -> Unit)? = null)
+
+    /**
+     * 读取钥匙的rfid
+     */
+    fun readKeyRfidStr(slaveAddress: Int?, idx: Int, done: ((idx: Int, res: String) -> Unit)? = null)
+
+    /**
+     * 读取挂锁rfid
+     */
+    fun readLockRfidStr(slaveAddress: Int?, lockIdx: Int, done: ((res: String) -> Unit)? = null)
+
+    /**
+     * 打开所有钥匙仓位
+     */
+    fun controlAllKeyBuckleOpen(complete: () -> Unit = {})
+
+    /**
+     * 检查硬件是否连接
+     */
+    fun checkDock(): Boolean
+
+    /**
+     * 暂停读取
+     */
+    fun interruptReadTrashBinStatus(interrupt: Boolean)
+
+    /**
+     * 关闭所有钥匙充电
+     */
+    fun controlAllKeyChargeDown()
+
+    /**
+     * 更新钥匙电量
+     */
+    fun updateKeyPower(power: Int, mac: String)
+
+    /**
+     * 根据mac获取钥匙信息
+     */
+    fun getKeyBeanByMac(mac: String): DockData.KeyDock.KeyBean?
+
+    /**
+     * 更新就绪状态
+     */
+    fun updateKeyReadyStatus(mac: String, isReady: Boolean, from: Int)
+}

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleBean.kt → data/src/main/java/com/grkj/data/hardware/ble/BleBean.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import com.huyuhui.fastble.data.BleDevice
 import java.io.File

+ 11 - 4
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleCmdManager.kt → data/src/main/java/com/grkj/data/hardware/ble/BleCmdManager.kt

@@ -1,8 +1,8 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import android.annotation.SuppressLint
 import android.bluetooth.BluetoothGattCharacteristic
-import com.grkj.ui_base.utils.event.GetTicketStatusEvent
+import com.grkj.data.utils.event.GetTicketStatusEvent
 import com.grkj.shared.utils.extension.crc16
 import com.grkj.shared.utils.extension.toByteArray
 import com.grkj.shared.utils.extension.toHexStrings
@@ -423,11 +423,18 @@ object BleCmdManager {
      * 关机或重启请求
      */
     @SuppressLint("MissingPermission")
-    fun shutdownOrRebootReq(mac: String?, isShutdown: Boolean = true, callback: CustomBleWriteCallback?) {
+    fun shutdownOrRebootReq(
+        mac: String?,
+        isShutdown: Boolean = true,
+        callback: CustomBleWriteCallback?
+    ) {
         BleConnectionManager.getBleDeviceByMac(mac)?.let {
             BleUtil.Companion.instance?.write(
                 it.bleDevice,
-                cmd = assembleData(it, BleConst.REQ_SHUTDOWN_OR_REBOOT+if (isShutdown) 0x02.toByte() else 0x01.toByte()),
+                cmd = assembleData(
+                    it,
+                    BleConst.REQ_SHUTDOWN_OR_REBOOT + if (isShutdown) 0x02.toByte() else 0x01.toByte()
+                ),
                 writeCallback = callback
             )
         }

+ 36 - 32
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt → data/src/main/java/com/grkj/data/hardware/ble/BleConnectionManager.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import android.Manifest
 import android.annotation.SuppressLint
@@ -6,13 +6,11 @@ import android.bluetooth.BluetoothDevice
 import android.bluetooth.BluetoothGatt
 import android.bluetooth.BluetoothGattCharacteristic
 import androidx.annotation.RequiresPermission
+import com.grkj.data.enums.HardwareMode
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.shared.utils.extension.startsWith
 import com.grkj.shared.utils.extension.toHexStrings
-import com.grkj.ui_base.R
-import com.grkj.ui_base.config.ISCSConfig
-import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.data.utils.event.LoadingEvent
-import com.grkj.ui_base.utils.modbus.ModBusController
+import com.grkj.shared.utils.i18n.I18nManager
 import com.huyuhui.fastble.BleManager
 import com.huyuhui.fastble.data.BleDevice
 import com.huyuhui.fastble.exception.BleException
@@ -100,7 +98,8 @@ object BleConnectionManager {
                 //电池电量返回
                 byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> {
                     val power = byteArray[4].toInt()
-                    ModBusController.updateKeyPower(power, bleBean.bleDevice.mac)
+                    HardwareMode.getCurrentHardwareMode()
+                        .updateKeyPower(power, bleBean.bleDevice.mac)
                     logger.info("电量(${bleBean.bleDevice.mac}):${power}")
                     prepareDoneCallBack?.invoke(true, bleBean)
                 }
@@ -213,7 +212,7 @@ object BleConnectionManager {
      */
     private fun checkProcess(mac: String?, hideLoading: Boolean = true): Boolean {
         val canProcess = currentConnectingMac.contains(mac)
-        if (!canProcess && hideLoading) LoadingEvent.sendLoadingEvent(null, false)
+        if (!canProcess && hideLoading) LoadingEvent.Companion.sendLoadingEvent(null, false)
         return canProcess
     }
 
@@ -288,7 +287,7 @@ object BleConnectionManager {
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
         logger.info("蓝牙连接-doScanBle:$mac")
-        if (isNeedLoading) LoadingEvent.sendLoadingEvent("正在扫描设备...", true)
+        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent("正在扫描设备...", true)
         BleUtil.Companion.instance?.scan(object : CustomBleScanCallback() {
             override fun onPrompt(promptStr: String?) {
                 // 蓝牙未启动重试
@@ -302,7 +301,7 @@ object BleConnectionManager {
             override fun onScanStarted(success: Boolean) {
                 logger.info("蓝牙连接-onScanStarted:${success}")
                 if (!success && retryTimes == 0) {
-                    if (isNeedLoading) LoadingEvent.sendLoadingEvent(null, false)
+                    if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(null, false)
                     prepareDoneCallBack?.invoke(false, null)
                 } else if (!success && retryTimes > 0) {
                     BleManager.cancelScan()
@@ -335,7 +334,7 @@ object BleConnectionManager {
 
             override fun onScanFinished(scanResultList: List<BleDevice>) {
                 logger.info("蓝牙连接-onScanFinished: $mac - ${scanResultList?.none { it.mac == mac }}")
-                if (isNeedLoading) LoadingEvent.sendLoadingEvent(null, false)
+                if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(null, false)
                 // 没有扫描到
                 // 没有扫描到
                 if (scanResultList?.none { it.mac == mac } == true) {
@@ -360,15 +359,15 @@ object BleConnectionManager {
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
         logger.info("蓝牙连接-doConnect : ${bleDevice.mac}")
-        if (isNeedLoading) LoadingEvent.sendLoadingEvent(
-            CommonUtils.getStr("ble_connecting"), true
+        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
+            I18nManager.t("ble_connecting"), true
         )
         ThreadUtils.runOnIO {
             BleUtil.Companion.instance?.connectBySelect(
                 bleDevice, object : CustomBleGattCallback() {
                     override fun onPrompt(promptStr: String?) {
                         logger.info(promptStr)
-                        if (isNeedLoading) LoadingEvent.sendLoadingEvent(
+                        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
                             promptStr, false
                         )
                     }
@@ -378,8 +377,8 @@ object BleConnectionManager {
                     }
 
                     override fun onConnectFail(bleDevice: BleDevice?, exception: BleException) {
-                        if (isNeedLoading) LoadingEvent.sendLoadingEvent(
-                            CommonUtils.getStr("ble_connect_fail"), false
+                        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
+                            I18nManager.t("ble_connect_fail"), false
                         )
                         logger.error("蓝牙连接-onConnectFail : ${bleDevice?.mac} - ${exception?.description}")
                         prepareDoneCallBack?.invoke(false, null)
@@ -390,7 +389,7 @@ object BleConnectionManager {
                         gatt: BluetoothGatt?,
                         status: Int
                     ) {
-                        if (isNeedLoading) LoadingEvent.sendLoadingEvent(
+                        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
                             null, false
                         )
                         logger.info("蓝牙连接-onConnectSuccess : ${bleDevice?.mac}")
@@ -418,7 +417,7 @@ object BleConnectionManager {
                         gatt: BluetoothGatt?,
                         status: Int
                     ) {
-                        if (isNeedLoading) LoadingEvent.sendLoadingEvent(
+                        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
                             null, false
                         )
                         logger.info("蓝牙连接-onDisConnected : ${device?.mac} - $isActiveDisConnected")
@@ -433,12 +432,11 @@ object BleConnectionManager {
                         }
                         if (!isActiveDisConnected) {
                             // 测试模式下不重连
-                            if (ISCSConfig.isTestMode) {
-                                return
-                            }
-                            ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
+                            HardwareMode.getCurrentHardwareMode()
+                                .updateKeyReadyStatus(bleDevice.mac, false, 3)
                         } else {
-                            ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
+                            HardwareMode.getCurrentHardwareMode()
+                                .updateKeyReadyStatus(bleDevice.mac, false, 3)
                         }
                     }
 
@@ -489,7 +487,7 @@ object BleConnectionManager {
                 } else {
                     BleSendDispatcher.scheduleDisconnect(bleDevice.mac)
                     BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
-                    ModBusController.getKeyByMac(bleDevice.mac)?.rfid?.let {
+                    HardwareMode.getCurrentHardwareMode().getRfidByKeyMac(bleDevice.mac)?.let {
                         addExceptionKey(it)
                         timeoutCallBack?.invoke(true)
                     }
@@ -600,7 +598,7 @@ object BleConnectionManager {
         isNeedLoading: Boolean = false,
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
-        if (isNeedLoading) LoadingEvent.sendLoadingEvent("开始监听......", true)
+        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent("开始监听......", true)
         bleBean?.let {
             var isIndicateSuccess = false
             BleUtil.Companion.instance?.indicate(
@@ -631,7 +629,7 @@ object BleConnectionManager {
                         characteristic: BluetoothGattCharacteristic?,
                         exception: BleException
                     ) {
-                        if (isNeedLoading) LoadingEvent.sendLoadingEvent(null, false)
+                        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(null, false)
                         logger.error("蓝牙连接-onIndicateFailure : ${bleBean.bleDevice.mac} - ${exception?.description}")
                         ThreadUtils.runOnIODelayed(500) {
                             if (isIndicateSuccess) {
@@ -677,7 +675,7 @@ object BleConnectionManager {
         isNeedLoading: Boolean = false,
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
-        if (isNeedLoading) LoadingEvent.sendLoadingEvent("开始获取token...", true)
+        if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent("开始获取token...", true)
         bleBean?.let {
             BleCmdManager.getToken(it.bleDevice.mac, object : CustomBleWriteCallback() {
                 override fun onWriteSuccess(
@@ -688,7 +686,10 @@ object BleConnectionManager {
                     justWrite: ByteArray,
                     data: ByteArray
                 ) {
-                    if (isNeedLoading) LoadingEvent.sendLoadingEvent("token获取成功", true)
+                    if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
+                        "token获取成功",
+                        true
+                    )
                     logger.info("getToken success : ${bleBean.bleDevice.mac}")
                 }
 
@@ -702,7 +703,10 @@ object BleConnectionManager {
                     data: ByteArray?,
                     isTotalFail: Boolean
                 ) {
-                    if (isNeedLoading) LoadingEvent.sendLoadingEvent("token获取失败", true)
+                    if (isNeedLoading) LoadingEvent.Companion.sendLoadingEvent(
+                        "token获取失败",
+                        true
+                    )
                     logger.error("getToken fail : ${bleBean.bleDevice.mac}")
                     prepareDoneCallBack?.invoke(false, null)
                 }
@@ -724,10 +728,10 @@ object BleConnectionManager {
             // -------- 第二次尝试:先开电,再连 --------
             // 开电,并等待回调
             suspendCoroutine<Unit> { unitCont ->
-                ModBusController.controlKeyCharge(false, mac) {
+                HardwareMode.getCurrentHardwareMode().controlKeyCharge(false, mac) {
                     ThreadUtils.runOnIO {
                         delay(500)
-                        ModBusController.controlKeyCharge(true, mac) {
+                        HardwareMode.getCurrentHardwareMode().controlKeyCharge(true, mac) {
                             unitCont.resume(Unit)
                         }
                     }
@@ -746,7 +750,7 @@ object BleConnectionManager {
                     }
                     isCalled = true
                     // 无论成功或失败,都先把电关掉
-                    ModBusController.controlKeyCharge(false, mac) { }
+                    HardwareMode.getCurrentHardwareMode().controlKeyCharge(false, mac) { }
                     if (cont.isActive) {
                         cont.resume(isDone)
                     }

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConst.kt → data/src/main/java/com/grkj/data/hardware/ble/BleConst.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 /**
  * 指令,均为未加密或解密后的

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleIndicateListener.kt → data/src/main/java/com/grkj/data/hardware/ble/BleIndicateListener.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 interface BleIndicateListener {
     /**

+ 22 - 9
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleQueueDispatcher.kt → data/src/main/java/com/grkj/data/hardware/ble/BleQueueDispatcher.kt

@@ -1,13 +1,17 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import android.Manifest
 import android.annotation.SuppressLint
 import androidx.annotation.RequiresPermission
-import com.grkj.ui_base.utils.ble.BleConnectionManager.deviceList
 import com.huyuhui.fastble.BleManager
 import com.sik.sikcore.extension.toJson
 import com.sik.sikcore.thread.ThreadUtils
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
@@ -72,7 +76,9 @@ abstract class BleQueueDispatcher {
     @Synchronized
     fun submit(mac: String, onResult: (Boolean) -> Unit) {
         logger.info("开始检查钥匙状态:$mac, 连接中:${activeMacs.toJson()}, 已连接:${connectedMacs.toJson()}")
-        if (activeMacs.containsKey(mac) || taskQueue.any { it.first == mac } || connectedMacs.contains(mac)) {
+        if (activeMacs.containsKey(mac) || taskQueue.any { it.first == mac } || connectedMacs.contains(
+                mac
+            )) {
             // 已连接
             if (connectedMacs.contains(mac)) {
                 logger.info("${this::class.java} 检查到钥匙已连接")
@@ -162,10 +168,11 @@ abstract class BleQueueDispatcher {
             synchronized(this@BleQueueDispatcher) {
                 if (connectedMacs.remove(mac)) {
                     ThreadUtils.runOnIO {
-                        val deviceBean = deviceList.find { it.bleDevice.mac == mac }
+                        val deviceBean =
+                            BleConnectionManager.deviceList.find { it.bleDevice.mac == mac }
                         deviceBean?.let {
                             disconnectDeviceByMac(mac)
-                            deviceList.removeIf { it.bleDevice.mac == deviceBean.bleDevice.mac }
+                            BleConnectionManager.deviceList.removeIf { it.bleDevice.mac == deviceBean.bleDevice.mac }
                         }
                         logger.info("当前线程:${Thread.currentThread().name}")
                         clear(mac)
@@ -209,13 +216,19 @@ abstract class BleQueueDispatcher {
     fun isQueued(mac: String): Boolean = taskQueue.any { it.first == mac }
     fun isConnected(mac: String): Boolean = connectedMacs.contains(mac)
     fun canConnect(): Boolean = (activeMacs.size + connectedMacs.size) <= maxConnections
-    fun shouldDisconnect(mac: String): Boolean = isConnecting(mac) || isQueued(mac) || isConnected(mac)
+    fun shouldDisconnect(mac: String): Boolean =
+        isConnecting(mac) || isQueued(mac) || isConnected(mac)
 
     /**
      * 繁忙标记
      */
-    fun busy(mac: String) { busyMacs.add(mac) }
-    fun removeBusy(mac: String) { busyMacs.remove(mac) }
+    fun busy(mac: String) {
+        busyMacs.add(mac)
+    }
+
+    fun removeBusy(mac: String) {
+        busyMacs.remove(mac)
+    }
 
     /**
      * 清除非繁忙设备

+ 3 - 3
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleReturnDispatcher.kt → data/src/main/java/com/grkj/data/hardware/ble/BleReturnDispatcher.kt

@@ -1,7 +1,7 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
-import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.data.utils.event.LoadingEvent
+import com.grkj.shared.utils.i18n.I18nManager
 import com.sik.sikcore.thread.ThreadUtils
 
 object BleReturnDispatcher : BleQueueDispatcher() {
@@ -18,7 +18,7 @@ object BleReturnDispatcher : BleQueueDispatcher() {
      */
     override fun doConnect(mac: String, callback: (Boolean) -> Unit) {
         ThreadUtils.runOnMain {
-            LoadingEvent.sendLoadingEvent(CommonUtils.getStr("loading_msg_return_key_start"))
+            LoadingEvent.sendLoadingEvent(I18nManager.t("loading_msg_return_key_start"))
         }
         ThreadUtils.runOnIO {
             val isConnected = BleConnectionManager.tryConnectWithOptionalCharge(mac, isSend = false)

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleSendDispatcher.kt → data/src/main/java/com/grkj/data/hardware/ble/BleSendDispatcher.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import com.sik.sikcore.thread.ThreadUtils
 

+ 2 - 3
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt → data/src/main/java/com/grkj/data/hardware/ble/BleUtil.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import android.Manifest
 import android.app.Application
@@ -16,7 +16,6 @@ import com.huyuhui.fastble.exception.BleException
 import com.huyuhui.fastble.scan.BleScanRuleConfig
 import com.sik.sikcore.SIKCore
 import com.sik.sikcore.thread.ThreadUtils
-import kotlinx.coroutines.delay
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
@@ -53,7 +52,7 @@ class BleUtil private constructor() {
                     .setScanTimeOut(6_000L)
                     .setDeviceName(BleConst.BLE_LOCAL_NAME)
                     .apply {
-                        setScanSettings(ScanSettings.Builder().apply {
+                        BleScanRuleConfig.Builder().setScanSettings(ScanSettings.Builder().apply {
                             this.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                             this.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
                             this.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/CustomBleGattCallback.kt → data/src/main/java/com/grkj/data/hardware/ble/CustomBleGattCallback.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import com.huyuhui.fastble.callback.BleGattCallback
 

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/CustomBleIndicateCallback.kt → data/src/main/java/com/grkj/data/hardware/ble/CustomBleIndicateCallback.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import com.huyuhui.fastble.callback.BleIndicateCallback
 

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/CustomBleScanCallback.kt → data/src/main/java/com/grkj/data/hardware/ble/CustomBleScanCallback.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import com.huyuhui.fastble.callback.BleScanCallback
 

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/CustomBleWriteCallback.kt → data/src/main/java/com/grkj/data/hardware/ble/CustomBleWriteCallback.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.ble
+package com.grkj.data.hardware.ble
 
 import com.huyuhui.fastble.callback.BleWriteCallback
 

+ 4 - 55
data/src/main/java/com/grkj/data/hardware/can/CanDeviceConst.kt

@@ -4,6 +4,10 @@ package com.grkj.data.hardware.can
  * 硬件常量
  */
 object CanDeviceConst {
+    /**
+     * 未知类型
+     */
+    const val UNKNOWN = -1
     /**
      * 电子钥匙底座
      */
@@ -23,59 +27,4 @@ object CanDeviceConst {
      * 物资柜主控制板
      */
     const val DEVICE_MATERIAL_CABINET_CONTROL_BOARD = 3
-
-    /**
-     * 设备变化,初始化
-     */
-    const val DEVICE_CHANGE_INIT = 1
-
-    /**
-     * 设备变化,钥匙归还
-     */
-    const val DEVICE_CHANGE_KEY_RETURN = 1 shl 1
-
-    /**
-     * 设备变化,钥匙取出
-     */
-    const val DEVICE_CHANGE_KEY_TAKE = 1 shl 2
-
-    /**
-     * 设备变化,上锁
-     */
-    const val DEVICE_CHANGE_LOCKED = 1 shl 3
-
-    /**
-     * 设备变化,解锁
-     */
-    const val DEVICE_CHANGE_UNLOCK = 1 shl 4
-
-    /**
-     * 设备变化,左门打开
-     */
-    const val DEVICE_CHANGE_MATERIAL_LEFT_DOOR_OPEN = 1 shl 5
-
-    /**
-     * 设备变化,右门打开
-     */
-    const val DEVICE_CHANGE_MATERIAL_RIGHT_DOOR_OPEN = 1 shl 6
-
-    /**
-     * 设备变化,左门关闭
-     */
-    const val DEVICE_CHANGE_MATERIAL_LEFT_DOOR_CLOSED = 1 shl 7
-
-    /**
-     * 设备变化,右门关闭
-     */
-    const val DEVICE_CHANGE_MATERIAL_RIGHT_DOOR_CLOSED = 1 shl 8
-
-    /**
-     * 设备变化,锁归还
-     */
-    const val DEVICE_CHANGE_LOCK_RETURN = 1 shl 9
-
-    /**
-     * 设备变化,锁取出
-     */
-    const val DEVICE_CHANGE_LOCK_TAKE = 1 shl 10
 }

+ 186 - 0
data/src/main/java/com/grkj/data/hardware/can/CanHardwareHelper.kt

@@ -0,0 +1,186 @@
+package com.grkj.data.hardware.can
+
+import com.grkj.data.hardware.DockData
+import com.grkj.data.hardware.IHardwareHelper
+import com.grkj.data.hardware.modbus.DeviceConst
+import com.grkj.data.model.res.CabinetSlotsRecord
+import com.grkj.shared.utils.i18n.I18nManager
+
+/**
+ * Can硬件读写帮助类
+ */
+class CanHardwareHelper : IHardwareHelper {
+    override fun getKeyMacByRfid(rfid: String): String? {
+        return CanHelper.getKeyByRfid(rfid)?.mac
+    }
+
+    override fun getLocks(
+        needLockCount: Int,
+        exceptionSlots: MutableList<CabinetSlotsRecord>,
+        exceptionLocks: MutableList<String>
+    ): MutableMap<Any, MutableList<Pair<Int, String>>> {
+        return CanHelper.getLocks(needLockCount, exceptionSlots, exceptionLocks)
+    }
+
+    override fun getRfidByKeyMac(keyMac: String): String? {
+        return CanHelper.getKeyDeviceByMac(keyMac)?.rfid
+    }
+
+    override fun getSlotPosition(keyNfc: String): String {
+        val keyData = CanHelper.getKeyByRfid(keyNfc)
+        return if (keyData == null) I18nManager.t("not_in_slot") else "${keyData.nodeId}-${keyData.id + 1}"
+    }
+
+    override fun getExistsKeyMac(): List<String> {
+        val keyDevices = CanHelper.getDeviceByDeviceType(DeviceConst.DEVICE_TYPE_KEY)
+        return keyDevices.flatMap { it.value }.filterIsInstance<DeviceModel.DeviceKey>()
+            .map { it.mac }
+    }
+
+    override fun getKeyDockData(): List<DockData.KeyDock> {
+        val deviceData = CanHelper.getDeviceByDeviceType(CanDeviceConst.DEVICE_KEY_DOCK)
+        val keyDock = deviceData.map {
+            DockData.KeyDock().apply {
+                keyData.addAll(it.value.filterIsInstance<DeviceModel.DeviceKey>().map {
+                    DockData.KeyDock.KeyBean().apply {
+                        this.addr = it.nodeId
+                        this.idx = it.id
+                        this.row = it.nodeId
+                        this.rfid = it.rfid
+                        this.mac = it.mac
+                        this.isExist = it.isExist
+                        this.type = it.deviceType
+                        this.newHardware = it.newHardware
+                    }
+                })
+            }
+        }
+        return keyDock
+    }
+
+    override fun controlKeyBuckle(
+        isOpen: Boolean,
+        mac: String,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun controlLockBuckle(
+        isOpen: Boolean,
+        slaveAddress: Int?,
+        lockIdxList: MutableList<Int>,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun controlKeyCharge(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun controlAllKeyBuckleOpen(complete: () -> Unit) {
+        TODO("Not yet implemented")
+    }
+
+    override fun interruptReadTrashBinStatus(interrupt: Boolean) {
+
+    }
+
+    override fun controlAllKeyChargeDown() {
+        TODO("Not yet implemented")
+    }
+
+    override fun getKeyBeanByMac(mac: String): DockData.KeyDock.KeyBean? {
+        TODO("Not yet implemented")
+    }
+
+    override fun updateKeyPower(power: Int, mac: String) {
+        TODO("Not yet implemented")
+    }
+
+    override fun controlLockBuckle(
+        isOpen: Boolean,
+        slaveAddress: Int?,
+        lockIdxList: Int,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun readKeyRfidStr(
+        slaveAddress: Int?,
+        idx: Int,
+        done: ((Int, String) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun readLockRfidStr(
+        slaveAddress: Int?,
+        lockIdx: Int,
+        done: ((String) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getPortableDock(): List<DockData.PortableDock> {
+        return listOf()
+    }
+
+    override fun controlKeyBuckle(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getLockDockData(): List<DockData.LockDock> {
+        val deviceData = CanHelper.getDeviceByDeviceType(CanDeviceConst.DEVICE_KEY_DOCK)
+        val lockDock = deviceData.map {
+            DockData.LockDock().apply {
+                lockData.addAll(it.value.filterIsInstance<DeviceModel.CommonDevice>().map {
+                    DockData.LockDock.LockBean().apply {
+                        this.addr = it.nodeId
+                        this.idx = it.id
+                        this.row = it.nodeId
+                        this.rfid = it.rfid
+                        this.isExist = it.isExist
+                        this.type = it.deviceType
+                        this.newHardware = it.newHardware
+                    }
+                })
+            }
+        }
+        return lockDock
+    }
+
+    override fun controlKeyLockAndCharge(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getLockSlotPosition(lockNfc: String): String {
+        val lockData = CanHelper.getLockByRfid(lockNfc)
+        return if (lockData == null) I18nManager.t("not_in_slot") else "${lockData.nodeId}-${lockData.id + 1}"
+    }
+
+    override suspend fun getOneKey(
+        exceptionSlots: List<CabinetSlotsRecord>,
+        exceptionKeysRfid: List<String>,
+        exceptionKeysMac: List<String>
+    ): Pair<Any, String?>? {
+        return CanHelper.getOneKey(exceptionSlots, exceptionKeysRfid, exceptionKeysMac)
+    }
+}

+ 172 - 11
data/src/main/java/com/grkj/data/hardware/can/CanHelper.kt

@@ -1,5 +1,10 @@
 package com.grkj.data.hardware.can
 
+import android.annotation.SuppressLint
+import com.grkj.data.hardware.ble.BleReturnDispatcher
+import com.grkj.data.hardware.ble.BleSendDispatcher
+import com.grkj.data.model.res.CabinetSlotsRecord
+import com.huyuhui.fastble.BleManager
 import com.sik.comm.core.protocol.ProtocolManager
 import com.sik.comm.core.protocol.ProtocolType
 import com.sik.comm.impl_can.CanProtocol
@@ -10,9 +15,12 @@ import com.sik.comm.impl_can.toSdoResponse
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.isActive
 import kotlinx.coroutines.launch
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
 
 /**
  * can总线帮助工具
@@ -59,18 +67,14 @@ object CanHelper {
 
                     CanDeviceConst.DEVICE_KEY_CABINET_CONTROL_BOARD -> {
                         DeviceParseStatus.parseKeyCabinetControlBoardStatus(
-                            nodeId,
-                            index,
-                            statusData
+                            nodeId, index, statusData
                         )
 
                     }
 
                     CanDeviceConst.DEVICE_MATERIAL_CABINET_CONTROL_BOARD -> {
                         DeviceParseStatus.parseMaterialCabinetControlBoardStatus(
-                            nodeId,
-                            index,
-                            statusData
+                            nodeId, index, statusData
                         )
 
                     }
@@ -102,8 +106,16 @@ object CanHelper {
     /**
      * 根据设备类型获取设备
      */
-    fun getDeviceByDeviceType(deviceType: Int): List<DeviceModel> {
+    fun getDeviceByDeviceType(deviceType: Int): Map<Int, List<DeviceModel>> {
         return deviceData.flatMap { it.value }.filter { it.deviceType == deviceType }
+            .groupBy { it.nodeId }
+    }
+
+    /**
+     * 根据节点id获取设备类型
+     */
+    fun getDeviceTypeByNodeId(nodeId: Int): Int {
+        return nodeMap[nodeId] ?: CanDeviceConst.UNKNOWN
     }
 
     /**
@@ -111,11 +123,11 @@ object CanHelper {
      */
     fun updateDeviceData(nodeId: Int, deviceData: List<DeviceModel>) {
         this.deviceData[nodeId] = deviceData
-        if (deviceData.any { it.deviceChange != 0 }) {
+        if (deviceData.any { it.deviceChange }) {
             deviceChangeListeners.forEach {
-                it.value.invoke(deviceData.filter { it.deviceChange != 0 })
+                it.value.invoke(deviceData.filter { it.deviceChange })
             }
-            deviceData.forEach { it.deviceChange = 0 }
+            deviceData.forEach { it.deviceChange = false }
         }
     }
 
@@ -167,7 +179,7 @@ object CanHelper {
     /**
      * 写入到
      */
-    fun writeTo(req: SdoRequest.Write, callback: (SdoResponse.WriteAck) -> Unit) {
+    fun writeTo(req: SdoRequest.Write, callback: (SdoResponse.WriteAck) -> Unit = {}) {
         scope.launch(Dispatchers.IO) {
             runCatching {
                 ProtocolManager.getProtocol(CustomCanConfig.instance.deviceId)
@@ -179,4 +191,153 @@ object CanHelper {
             }
         }
     }
+
+    /**
+     * 根据mac获取钥匙
+     */
+    fun getKeyDeviceByMac(keyMac: String): DeviceModel.DeviceKey? {
+        return deviceData.flatMap { it.value }.filterIsInstance<DeviceModel.DeviceKey>()
+            .find { it.mac == keyMac }
+    }
+
+    /**
+     * 根据rfid获取钥匙
+     */
+    fun getKeyByRfid(rfid: String): DeviceModel.DeviceKey? {
+        return deviceData.flatMap { it.value }.filterIsInstance<DeviceModel.DeviceKey>()
+            .find { it.rfid == rfid }
+    }
+
+    /**
+     * 根据rfid获取挂锁
+     */
+    fun getLockByRfid(lockNfc: String): DeviceModel.CommonDevice? {
+        return deviceData.flatMap { it.value }.filterIsInstance<DeviceModel.CommonDevice>()
+            .find { it.rfid == lockNfc }
+    }
+
+    /**
+     * 获取挂锁
+     */
+    fun getLocks(
+        needLockCount: Int,
+        exceptionSlots: MutableList<CabinetSlotsRecord>,
+        exceptionLocks: MutableList<String>
+    ): MutableMap<Any, MutableList<Pair<Int, String>>> {
+        val map = mutableMapOf<Any, MutableList<Pair<Int, String>>>()
+        logger.info("需要的锁具:${needLockCount}")
+        if (needLockCount == 0) {
+            return map
+        }
+        val lockDockList = deviceData.flatMap { it.value }.filterIsInstance<DeviceModel.DeviceKey>()
+        lockDockList.sortedBy { it.nodeId }
+        var provideCount = 0
+        logger.info("锁具基座列表:${lockDockList}")
+        logger.info("异常锁rfid:${exceptionLocks}")
+        logger.info("异常锁仓位:${exceptionSlots.joinToString(",") { "${it.row},${it.col}" }}")
+        if (provideCount >= needLockCount) return map
+        logger.info("锁具信息:${lockDockList}")
+        val validLocks = lockDockList.filter { it.rfid !in exceptionLocks }.filter { lockBean ->
+            lockBean.isExist && lockBean.id !in exceptionSlots.filter { lockBean.nodeId == it.row?.toInt() }
+                .map { (it.col?.toInt() ?: 1) - 1 }
+        }
+        val toTake = (needLockCount - provideCount).coerceAtMost(validLocks.size)
+        if (toTake > 0) {
+            validLocks.take(toTake).groupBy { it.nodeId }
+                .map { it.key to it.value.map { it.id to it.rfid } }.toMutableList()
+        }
+        logger.info("待取锁:${map}")
+        return map
+    }
+
+    /**
+     * 获取一把钥匙
+     */
+    @SuppressLint("MissingPermission")
+    suspend fun getOneKey(
+        exceptionSlots: List<CabinetSlotsRecord>,
+        exceptionKeysRfid: List<String>,
+        exceptionKeysMac: List<String> = mutableListOf(),
+    ): Pair<Any, String?>? {
+        // 1. 过滤并准备钥匙列表
+        val slotCols = exceptionSlots.mapNotNull { it.col?.toInt() }
+        val noBelongDevice = BleManager.getAllConnectedDevice().filter {
+            !BleSendDispatcher.isConnected(it.mac) && !BleSendDispatcher.isConnecting(it.mac) && !BleReturnDispatcher.isConnected(
+                it.mac
+            ) && !BleReturnDispatcher.isConnecting(it.mac)
+        }
+        logger.info("检查到不属于任何队列的设备:${noBelongDevice.map { it.mac }},立即断开连接让路")
+        noBelongDevice.forEach {
+            BleManager.disconnect(it)
+        }
+        var keyList = deviceData.flatMap { it.value }.filterIsInstance<DeviceModel.DeviceKey>()
+            //RFID不为空,RFID不在异常列表,mac不在异常列表,mac不为空,存在,不在归还连接列表,不在归还连接中列表
+            .filterIndexed { idx, _ -> (idx + 1) !in slotCols }.filter { kb ->
+                kb.rfid !in exceptionKeysRfid && kb.mac !in exceptionKeysMac && kb.isExist && !BleReturnDispatcher.isConnected(
+                    kb.mac
+                ) && !BleReturnDispatcher.isConnecting(kb.mac)
+            }
+
+        logger.info("蓝牙连接-获取到钥匙信息:${keyList}")
+        if (keyList.isEmpty()) {
+            return null
+        }
+        val sendConnectingAndConnected = BleSendDispatcher.getConnectedAndConnecting()
+        //如果已连接和连接中的设备不在钥匙列表中,直接断开连接让路
+        sendConnectingAndConnected.filter { it !in keyList.map { it.mac } }.forEach {
+            BleSendDispatcher.scheduleDisconnect(it)
+        }
+        keyList = keyList.sortedWith(compareByDescending<DeviceModel.DeviceKey> {
+            BleSendDispatcher.isConnected(it.mac) || BleSendDispatcher.isConnecting(
+                it.mac
+            )
+        }    // 主键:在线优先
+            .thenByDescending { it.power }                                                // 三级:电量越高
+        )
+        val connectedKey = keyList.find { BleSendDispatcher.isConnected(it.mac) }
+        if (connectedKey != null) {
+            return connectedKey.nodeId to connectedKey.rfid
+        }
+        val connectingKey = keyList.find { BleSendDispatcher.isConnecting(it.mac) }
+        if (connectingKey != null) {
+            val result = suspendCoroutine { cont ->
+                BleSendDispatcher.submit(connectingKey.mac) { connected ->
+                    if (connected) {
+                        cont.resume(connectingKey.nodeId to connectingKey.rfid)
+                    } else {
+                        cont.resume(null)
+                    }
+                }
+            }
+            if (result != null) {
+                return result
+            }
+        }
+        for (kb in keyList) {
+            val mac = kb.mac
+            val result = suspendCoroutine { cont ->
+                BleSendDispatcher.submit(mac) { connected ->
+                    if (connected) {
+                        logger.info("蓝牙连接完成 :${mac}")
+                        // 找到第一个能连的:从 keyDockList 里拿同 rfid 的 addr
+                        logger.info("蓝牙连接-找到的底座地址 :${kb.nodeId}")
+                        if (cont.context.isActive) {
+                            cont.resume(kb.nodeId to kb.rfid)
+                        }
+                    } else {
+                        if (cont.context.isActive) {
+                            cont.resume(null)
+                        }
+                    }
+                }
+            }
+            if (result != null) {
+                return result
+            }
+        }
+
+        // 一个都没成功
+        logger.error("getOneKey : no key match")
+        return null
+    }
 }

+ 6 - 1
data/src/main/java/com/grkj/data/hardware/can/DeviceModel.kt

@@ -40,10 +40,15 @@ sealed class DeviceModel {
      */
     var isExist: Boolean = false
 
+    /**
+     * 是否就绪
+     */
+    var isReady: Boolean = false
+
     /**
      * 设备变化
      */
-    var deviceChange: Int = 0
+    var deviceChange: Boolean = false
 
 
     /**

+ 15 - 45
data/src/main/java/com/grkj/data/hardware/can/DeviceParseStatus.kt

@@ -16,14 +16,14 @@ object DeviceParseStatus {
                 this.nodeId = nodeId
                 this.deviceType = CanDeviceConst.DEVICE_KEY_DOCK
                 this.id = 0
-                this.deviceChange = CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
+                this.deviceChange = true
             }) as DeviceModel.DeviceKey
         val rightKeyModel: DeviceModel.DeviceKey =
             (deviceModel.getOrNull(1) ?: DeviceModel.DeviceKey().apply {
                 this.nodeId = nodeId
                 this.deviceType = CanDeviceConst.DEVICE_KEY_DOCK
                 this.id = 1
-                this.deviceChange = CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
+                this.deviceChange = true
             }) as DeviceModel.DeviceKey
         when (index) {
             CanCommands.Command.STATUS -> {
@@ -32,19 +32,13 @@ object DeviceParseStatus {
                 val rightKeyData = statusData[1]
                 val leftKeyExists = ((leftKeyData.toInt() shr 0) and 1) == 1
                 if (leftKeyModel.isExist != leftKeyExists) {
-                    leftKeyModel.deviceChange = BitTypeUtils.addType(
-                        leftKeyModel.deviceChange,
-                        if (leftKeyExists) CanDeviceConst.DEVICE_CHANGE_KEY_RETURN else CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
-                    )
+                    leftKeyModel.deviceChange = true
                 }
                 leftKeyModel.isExist = leftKeyExists
                 leftKeyModel.isCharging = ((leftKeyData.toInt() shr 1) and 1) == 1
                 val rightKeyExists = ((rightKeyData.toInt() shr 0) and 1) == 1
                 if (rightKeyModel.isExist != rightKeyExists) {
-                    rightKeyModel.deviceChange = BitTypeUtils.addType(
-                        rightKeyModel.deviceChange,
-                        if (rightKeyExists) CanDeviceConst.DEVICE_CHANGE_KEY_RETURN else CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
-                    )
+                    rightKeyModel.deviceChange = true
                 }
                 rightKeyModel.isExist = rightKeyExists
                 rightKeyModel.isCharging = ((rightKeyData.toInt() shr 1) and 1) == 1
@@ -54,18 +48,12 @@ object DeviceParseStatus {
                 val keyData = statusData[0]
                 val leftKeyLocked = ((keyData.toInt() shr 0) and 1) == 1
                 if (leftKeyModel.locked != leftKeyLocked) {
-                    leftKeyModel.deviceChange = BitTypeUtils.addType(
-                        leftKeyModel.deviceChange,
-                        if (leftKeyLocked) CanDeviceConst.DEVICE_CHANGE_LOCKED else CanDeviceConst.DEVICE_CHANGE_UNLOCK
-                    )
+                    leftKeyModel.deviceChange = true
                 }
                 leftKeyModel.locked = leftKeyLocked
                 val rightKeyLocked = ((keyData.toInt() shr 4) and 1) == 1
                 if (rightKeyModel.locked != rightKeyLocked) {
-                    rightKeyModel.deviceChange = BitTypeUtils.addType(
-                        rightKeyModel.deviceChange,
-                        if (rightKeyLocked) CanDeviceConst.DEVICE_CHANGE_LOCKED else CanDeviceConst.DEVICE_CHANGE_UNLOCK
-                    )
+                    rightKeyModel.deviceChange = true
                 }
                 rightKeyModel.locked = rightKeyLocked
             }
@@ -85,7 +73,7 @@ object DeviceParseStatus {
                     this.nodeId = nodeId
                     this.deviceType = CanDeviceConst.DEVICE_LOCK_DOCK
                     this.id = i + 1
-                    this.deviceChange = CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
+                    this.deviceChange = true
                 })
             }
         }
@@ -94,10 +82,7 @@ object DeviceParseStatus {
                 deviceModel.forEach {
                     val deviceExists = ((statusData[0].toInt() shr (it.id - 1)) and 1) == 1
                     if (it.isExist != deviceExists) {
-                        it.deviceChange = BitTypeUtils.addType(
-                            it.deviceChange,
-                            if (deviceExists) CanDeviceConst.DEVICE_CHANGE_LOCK_RETURN else CanDeviceConst.DEVICE_CHANGE_LOCK_TAKE
-                        )
+                        it.deviceChange = true
                     }
                     it.isExist = deviceExists
                 }
@@ -107,10 +92,7 @@ object DeviceParseStatus {
                 deviceModel.forEach {
                     val deviceLocked = ((statusData[0].toInt() shr (it.id - 1)) and 1) == 1
                     if (it.locked != deviceLocked) {
-                        it.deviceChange = BitTypeUtils.addType(
-                            it.deviceChange,
-                            if (deviceLocked) CanDeviceConst.DEVICE_CHANGE_LOCKED else CanDeviceConst.DEVICE_CHANGE_UNLOCK
-                        )
+                        it.deviceChange = true
                     }
                     it.locked = deviceLocked
                 }
@@ -131,7 +113,7 @@ object DeviceParseStatus {
                     this.nodeId = nodeId
                     this.deviceType = CanDeviceConst.DEVICE_KEY_CABINET_CONTROL_BOARD
                     this.id = i + 1
-                    this.deviceChange = CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
+                    this.deviceChange = true
                 })
             }
         }
@@ -140,10 +122,7 @@ object DeviceParseStatus {
                 deviceModel.forEach {
                     val keyExists = ((statusData[0].toInt() shr (it.id - 1)) and 1) == 1
                     if (it.isExist != keyExists) {
-                        it.deviceChange = BitTypeUtils.addType(
-                            it.deviceChange,
-                            if (keyExists) CanDeviceConst.DEVICE_CHANGE_KEY_RETURN else CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
-                        )
+                        it.deviceChange = true
                     }
                     it.isExist = keyExists
                 }
@@ -153,10 +132,7 @@ object DeviceParseStatus {
                 deviceModel.forEach {
                     val keyLocked = ((statusData[0].toInt() shr (it.id - 1)) and 1) == 1
                     if (it.locked != keyLocked) {
-                        it.deviceChange = BitTypeUtils.addType(
-                            it.deviceChange,
-                            if (keyLocked) CanDeviceConst.DEVICE_CHANGE_LOCKED else CanDeviceConst.DEVICE_CHANGE_UNLOCK
-                        )
+                        it.deviceChange = true
                     }
                     it.locked = ((statusData[0].toInt() shr (it.id - 1)) and 1) == 1
                 }
@@ -176,7 +152,7 @@ object DeviceParseStatus {
                 this.nodeId = nodeId
                 this.deviceType = CanDeviceConst.DEVICE_MATERIAL_CABINET_CONTROL_BOARD
                 this.id = 0
-                this.deviceChange = CanDeviceConst.DEVICE_CHANGE_KEY_TAKE
+                this.deviceChange = true
             })
         }
         when (index) {
@@ -184,18 +160,12 @@ object DeviceParseStatus {
                 deviceModel.filterIsInstance<DeviceModel.MaterialDevice>().forEach {
                     val leftDoorLocked = ((statusData[0].toInt() shr 0) and 1) == 0
                     if (it.leftDoorLocked != leftDoorLocked) {
-                        it.deviceChange = BitTypeUtils.addType(
-                            it.deviceChange,
-                            if (leftDoorLocked) CanDeviceConst.DEVICE_CHANGE_MATERIAL_LEFT_DOOR_OPEN else CanDeviceConst.DEVICE_CHANGE_MATERIAL_LEFT_DOOR_CLOSED
-                        )
+                        it.deviceChange = true
                     }
                     it.leftDoorLocked = leftDoorLocked
                     val rightDoorLocked = ((statusData[0].toInt() shr 4) and 1) == 0
                     if (it.leftDoorLocked != rightDoorLocked) {
-                        it.deviceChange = BitTypeUtils.addType(
-                            it.deviceChange,
-                            if (rightDoorLocked) CanDeviceConst.DEVICE_CHANGE_MATERIAL_RIGHT_DOOR_OPEN else CanDeviceConst.DEVICE_CHANGE_MATERIAL_RIGHT_DOOR_CLOSED
-                        )
+                        it.deviceChange = true
                     }
                     it.rightDoorLocked = rightDoorLocked
                 }

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DeviceConst.kt → data/src/main/java/com/grkj/data/hardware/modbus/DeviceConst.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 object DeviceConst {
 

+ 2 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt → data/src/main/java/com/grkj/data/hardware/modbus/DockBean.kt

@@ -1,9 +1,9 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 import com.google.gson.Gson
 import com.google.gson.reflect.TypeToken
 import com.grkj.data.data.MMKVConstants
-import com.grkj.ui_base.utils.event.SwitchCollectionUpdateEvent
+import com.grkj.data.utils.event.SwitchCollectionUpdateEvent
 import com.sik.sikcore.extension.getMMKVData
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/FrameTask.kt → data/src/main/java/com/grkj/data/hardware/modbus/FrameTask.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 import com.grkj.shared.utils.extension.crc16
 

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/MBFrame.kt → data/src/main/java/com/grkj/data/hardware/modbus/MBFrame.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 import com.grkj.shared.utils.extension.crc16
 

+ 1 - 3
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusCMDHelper.kt → data/src/main/java/com/grkj/data/hardware/modbus/ModBusCMDHelper.kt

@@ -1,6 +1,4 @@
-package com.grkj.ui_base.utils.modbus
-
-import com.grkj.ui_base.utils.modbus.FRAME_TYPE_READ
+package com.grkj.data.hardware.modbus
 
 /**
  * 通信指令帮助工具

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusConstants.kt → data/src/main/java/com/grkj/data/hardware/modbus/ModBusConstants.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 /**
  * modbus 最小发送间隔(150豪秒)

+ 22 - 24
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt → data/src/main/java/com/grkj/data/hardware/modbus/ModBusController.kt

@@ -1,20 +1,18 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 import android.annotation.SuppressLint
+import com.grkj.data.config.ISCSConfig
 import com.grkj.data.di.LogicManager
+import com.grkj.data.hardware.ble.BleReturnDispatcher
+import com.grkj.data.hardware.ble.BleSendDispatcher
 import com.grkj.data.model.res.CabinetSlotsRecord
+import com.grkj.data.utils.event.ModbusInitCompleteEvent
+import com.grkj.data.utils.event.ToastEvent
 import com.grkj.shared.utils.extension.isPureZero
 import com.grkj.shared.utils.extension.removeLeadingZeros
 import com.grkj.shared.utils.extension.toHexStrings
-import com.grkj.ui_base.R
-import com.grkj.ui_base.config.ISCSConfig
-import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.ui_base.utils.ble.BleReturnDispatcher
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
-import com.grkj.ui_base.utils.event.ModbusInitCompleteEvent
-import com.grkj.ui_base.utils.extension.tip
+import com.grkj.shared.utils.i18n.I18nManager
 import com.huyuhui.fastble.BleManager
-import com.kongzue.dialogx.dialogs.PopTip
 import kotlinx.coroutines.isActive
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
@@ -245,8 +243,7 @@ object ModBusController {
                                     controlKeyBuckle(false, key.idx, dockBean.addr)
                                 } else {
                                     if (ISCSConfig.isInit) {
-                                        PopTip.build()
-                                            .tip(CommonUtils.getStr("get_key_info_fail"))
+                                        ToastEvent.sendToastEvent(I18nManager.t("get_key_info_fail"))
                                     }
                                     controlKeyBuckle(true, key.idx, dockBean.addr)
                                 }
@@ -337,7 +334,7 @@ object ModBusController {
     private fun lockBuckleExtraStatus(res: Any) {
         logger.debug("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
         if (res.isEmpty() || res.any { it.isEmpty() }) {
-            var tipStr = CommonUtils.getStr("no_response_board_exists") + " : "
+            var tipStr = I18nManager.t("no_response_board_exists") + " : "
             val addressList = mutableListOf<String>()
 
             modBusManager?.mSlaveAddressList?.forEach { itDock ->
@@ -346,7 +343,7 @@ object ModBusController {
                 }
             }
             tipStr += addressList
-            PopTip.tip(tipStr)
+            ToastEvent.sendToastEvent(tipStr)
         }
         res.forEach { bytes ->
             val dockBean = updateExtraLockStatus(bytes) ?: return@forEach
@@ -371,7 +368,7 @@ object ModBusController {
     fun switchStatus(res: Any, done: () -> Unit) {
         logger.info("开关板:${(res as ByteArray).toHexStrings()}")
         if (res.isEmpty()) {
-            var tipStr = CommonUtils.getStr("no_response_board_exists") + " : "
+            var tipStr = I18nManager.t("no_response_board_exists") + " : "
             val addressList = mutableListOf<String>()
 
             modBusManager?.mSlaveAddressList?.forEach { itDock ->
@@ -380,7 +377,7 @@ object ModBusController {
                 }
             }
             tipStr += addressList
-            PopTip.tip(tipStr)
+            ToastEvent.sendToastEvent(tipStr)
         }
         updateSwitchStatus(res, done)
     }
@@ -391,7 +388,7 @@ object ModBusController {
     private fun lockBuckleStatus(res: Any) {
         logger.info("debug:${(res as List<ByteArray>).map { it.toHexStrings() }}")
         if (res.isEmpty() || res.any { it.isEmpty() }) {
-            var tipStr = CommonUtils.getStr("no_response_board_exists") + " : "
+            var tipStr = I18nManager.t("no_response_board_exists") + " : "
             val addressList = mutableListOf<String>()
 
             modBusManager?.mSlaveAddressList?.forEach { itDock ->
@@ -400,7 +397,7 @@ object ModBusController {
                 }
             }
             tipStr += addressList
-            PopTip.tip(tipStr)
+            ToastEvent.sendToastEvent(tipStr)
         }
 
         res.forEach { bytes ->
@@ -983,7 +980,7 @@ object ModBusController {
         exceptionSlots: List<CabinetSlotsRecord>,
         exceptionKeysRfid: List<String>,
         exceptionKeysMac: List<String> = mutableListOf(),
-    ): Pair<Byte, DockBean.KeyBean?>? {
+    ): Pair<Any, String?>? {
         // 1. 过滤并准备钥匙列表
         val slotCols = exceptionSlots.mapNotNull { it.col?.toInt() }
         val keyDockList =
@@ -1033,7 +1030,7 @@ object ModBusController {
                     it.getKeyList().any { it.rfid == connectedKey.rfid }
                 }?.addr
             if (addr != null) {
-                return addr to connectedKey
+                return addr to connectedKey.rfid
             }
         }
         val connectingKey = keyList.find { BleSendDispatcher.isConnecting(it.mac ?: "") }
@@ -1046,7 +1043,7 @@ object ModBusController {
                                 it.getKeyList().any { it.rfid == connectingKey.rfid }
                             }?.addr
                         if (addr != null) {
-                            cont.resume(addr to connectingKey)
+                            cont.resume(addr to connectingKey.rfid)
                         } else {
                             cont.resume(null)
                         }
@@ -1073,7 +1070,7 @@ object ModBusController {
                         logger.info("蓝牙连接-找到的底座地址 :${addr}")
                         if (addr != null) {
                             if (cont.context.isActive) {
-                                cont.resume(addr to kb)
+                                cont.resume(addr to kb.rfid)
                             }
                         } else {
                             if (cont.context.isActive) {
@@ -1108,8 +1105,8 @@ object ModBusController {
         needLockCount: Int,
         exceptionSlots: MutableList<CabinetSlotsRecord>,
         exceptionLocks: MutableList<String>
-    ): MutableMap<Byte, MutableList<DockBean.LockBean>> {
-        val map = mutableMapOf<Byte, MutableList<DockBean.LockBean>>()
+    ): MutableMap<Any, MutableList<Pair<Int, String>>> {
+        val map = mutableMapOf<Any, MutableList<Pair<Int, String>>>()
         logger.info("需要的锁具:${needLockCount}")
         if (needLockCount == 0) {
             return map
@@ -1132,7 +1129,8 @@ object ModBusController {
                     }
             val toTake = (needLockCount - provideCount).coerceAtMost(validLocks.size)
             if (toTake > 0) {
-                map[lockDockList[lockDockIndex].addr] = validLocks.take(toTake).toMutableList()
+                map[lockDockList[lockDockIndex].addr] =
+                    validLocks.take(toTake).map { it.idx to (it.rfid ?: "") }.toMutableList()
                 provideCount += toTake
             }
         }

+ 260 - 0
data/src/main/java/com/grkj/data/hardware/modbus/ModBusHardwareHelper.kt

@@ -0,0 +1,260 @@
+package com.grkj.data.hardware.modbus
+
+import com.grkj.data.hardware.DockData
+import com.grkj.data.hardware.IHardwareHelper
+import com.grkj.data.model.res.CabinetSlotsRecord
+import com.grkj.shared.utils.i18n.I18nManager
+
+/**
+ * modbus硬件操作帮助类
+ */
+class ModBusHardwareHelper : IHardwareHelper {
+    override fun getKeyMacByRfid(rfid: String): String? {
+        return ModBusController.getKeyByRfid(
+            rfid
+        )?.mac
+    }
+
+    override fun getLocks(
+        needLockCount: Int,
+        exceptionSlots: MutableList<CabinetSlotsRecord>,
+        exceptionLocks: MutableList<String>
+    ): MutableMap<Any, MutableList<Pair<Int, String>>> {
+        return ModBusController.getLocks(needLockCount, exceptionSlots, exceptionLocks)
+    }
+
+    override suspend fun getOneKey(
+        exceptionSlots: List<CabinetSlotsRecord>,
+        exceptionKeysRfid: List<String>,
+        exceptionKeysMac: List<String>
+    ): Pair<Any, String?>? {
+        return ModBusController.getOneKey(exceptionSlots, exceptionKeysRfid, exceptionKeysMac)
+    }
+
+    override fun getRfidByKeyMac(keyMac: String): String? {
+        return ModBusController.getKeyByMac(keyMac)?.rfid
+    }
+
+    override fun getSlotPosition(keyNfc: String): String {
+        val keyData = ModBusController.getKeyByRfid(keyNfc)
+        return if (keyData == null) I18nManager.t("not_in_slot") else "${keyData.row}-${keyData.idx + 1}"
+    }
+
+    override fun getLockSlotPosition(lockNfc: String): String {
+        val lockData = ModBusController.getLockByRfid(lockNfc)
+        return if (lockData == null) I18nManager.t("not_in_slot") else "${lockData.row}-${lockData.idx + 1}"
+    }
+
+    override fun getExistsKeyMac(): List<String> {
+        val dockData =
+            ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+        return dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.flatMap { it.deviceList }
+            .filterIsInstance<DockBean.KeyBean>().map { it.mac ?: "" }
+    }
+
+    override fun controlKeyLockAndCharge(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        ModBusController.controlKeyLockAndCharge(true, idx, slaveAddress?.toByte(), done)
+    }
+
+    override fun getKeyDockData(): List<DockData.KeyDock> {
+        val dockData =
+            ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+        return dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.map {
+            DockData.KeyDock().apply {
+                keyData.addAll(it.deviceList.filterIsInstance<DockBean.KeyBean>().map {
+                    DockData.KeyDock.KeyBean().apply {
+                        this.addr = it.addr.toInt()
+                        this.idx = it.idx
+                        this.row = it.row
+                        this.rfid = it.rfid ?: ""
+                        this.mac = it.mac ?: ""
+                        this.isExist = it.isExist
+                        this.type = it.type
+                        this.newHardware = it.newHardware
+                    }
+                })
+            }
+        }
+    }
+
+    override fun controlAllKeyBuckleOpen(complete: () -> Unit) {
+        ModBusController.controlAllKeyBuckleOpen(complete)
+    }
+
+    override fun checkDock(): Boolean {
+        val dockList = ModBusController.dockList
+        return dockList.size < DockBean.dockConfig.size
+    }
+
+    override fun interruptReadTrashBinStatus(interrupt: Boolean) {
+        ModBusController.interruptReadTrashBinStatus(interrupt)
+    }
+
+    override fun controlAllKeyChargeDown() {
+        ModBusController.controlAllKeyChargeDown()
+    }
+
+    override fun updateKeyPower(power: Int, mac: String) {
+        ModBusController.updateKeyPower(power, mac)
+    }
+
+    override fun controlKeyBuckle(
+        isOpen: Boolean,
+        mac: String,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        ModBusController.controlKeyBuckle(
+            true,
+            mac, done
+        )
+    }
+
+    override fun getKeyBeanByMac(mac: String): DockData.KeyDock.KeyBean? {
+        val keyBean = ModBusController.getKeyByMac(mac)
+        return keyBean?.let {
+            DockData.KeyDock.KeyBean().apply {
+                this.addr = it.addr.toInt()
+                this.idx = it.idx
+                this.row = it.row
+                this.rfid = it.rfid ?: ""
+                this.mac = it.mac ?: ""
+                this.isExist = it.isExist
+                this.type = it.type
+                this.newHardware = it.newHardware
+            }
+        }
+    }
+
+    override fun updateKeyReadyStatus(
+        mac: String,
+        isReady: Boolean,
+        from: Int
+    ) {
+        ModBusController.updateKeyReadyStatus(mac, isReady, from)
+    }
+
+    override fun controlKeyCharge(
+        isOpen: Boolean,
+        mac: String,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        ModBusController.controlKeyCharge(isOpen, mac, done)
+    }
+
+    override fun getLockDockData(): List<DockData.LockDock> {
+        val dockData =
+            ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+        return dockData.filter { it.type == DeviceConst.DOCK_TYPE_LOCK }.map {
+            DockData.LockDock().apply {
+                lockData.addAll(it.deviceList.filterIsInstance<DockBean.LockBean>().map {
+                    DockData.LockDock.LockBean().apply {
+                        this.addr = it.addr.toInt()
+                        this.idx = it.idx
+                        this.row = it.row
+                        this.rfid = it.rfid ?: ""
+                        this.isExist = it.isExist
+                        this.type = it.type
+                        this.newHardware = it.newHardware
+                    }
+                })
+            }
+        }
+    }
+
+    override fun controlKeyBuckle(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        ModBusController.controlKeyBuckle(isOpen, idx, slaveAddress?.toByte(), done)
+    }
+
+    override fun controlLockBuckle(
+        isOpen: Boolean,
+        slaveAddress: Int?,
+        lockIdxList: MutableList<Int>,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        ModBusController.controlLockBuckle(isOpen, slaveAddress?.toByte(), lockIdxList, done)
+    }
+
+    override fun controlKeyCharge(
+        isOpen: Boolean,
+        idx: Int,
+        slaveAddress: Int?,
+        done: ((ByteArray) -> Unit)?
+    ) {
+        ModBusController.controlKeyCharge(
+            !isOpen, idx,
+            slaveAddress?.toByte()
+        )
+    }
+
+    override fun controlLockBuckle(
+        isOpen: Boolean,
+        slaveAddress: Int?,
+        lockIdxList: Int,
+        done: ((ByteArray) -> Unit)?
+    ) {
+
+        ModBusController.controlLockBuckle(
+            isOpen,
+            slaveAddress?.toByte(),
+            lockIdxList,
+        )
+    }
+
+    override fun readKeyRfidStr(
+        slaveAddress: Int?,
+        idx: Int,
+        done: ((Int, String) -> Unit)?
+    ) {
+        ModBusController.readKeyRfidStr(
+            slaveAddress?.toByte(),
+            idx, done
+        )
+    }
+
+    override fun readLockRfidStr(
+        slaveAddress: Int?,
+        lockIdx: Int,
+        done: ((String) -> Unit)?
+    ) {
+        ModBusController.readLockRfidStr(slaveAddress?.toByte(), lockIdx, done)
+    }
+
+    override fun getPortableDock(): List<DockData.PortableDock> {
+        val dockData =
+            ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+        return dockData.filter { it.type == DeviceConst.DOCK_TYPE_PORTABLE }.map {
+            DockData.PortableDock().apply {
+                deviceData.addAll(it.deviceList.mapNotNull {
+                    when (it) {
+                        is DockBean.KeyBean -> DockData.KeyDock.KeyBean().apply {
+                            this.row = it.row
+                            this.rfid = it.rfid ?: ""
+                            this.mac = it.mac ?: ""
+                            this.isExist = it.isExist
+                            this.newHardware = it.newHardware
+                        }
+
+                        is DockBean.LockBean -> DockData.LockDock.LockBean().apply {
+                            this.row = it.row
+                            this.rfid = it.rfid ?: ""
+                            this.isExist = it.isExist
+                            this.newHardware = it.newHardware
+                        }
+
+                        else -> null
+                    }
+                })
+            }
+        }
+    }
+}

+ 11 - 7
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusManager.kt → data/src/main/java/com/grkj/data/hardware/modbus/ModBusManager.kt

@@ -1,14 +1,18 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 import com.google.gson.Gson
 import com.google.gson.reflect.TypeToken
 import com.grkj.data.data.MMKVConstants
 import com.grkj.shared.config.Constants
-import com.grkj.ui_base.utils.Executor
 import com.grkj.shared.utils.extension.toHexStrings
 import com.sik.sikcore.extension.getMMKVData
-import kotlinx.coroutines.*
+import com.sik.sikcore.thread.ThreadUtils
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
@@ -189,25 +193,25 @@ class ModBusManager(
             sendToAll(frame) {
                 if (running) {
                     listener(it)
-                    Executor.delayOnIO({
+                    ThreadUtils.runOnIODelayed(delayMills) {
                         if (running) repeatSendToAll(
                             frame,
                             interrupt,
                             listener,
                             delayMills
                         )
-                    }, delayMills)
+                    }
                 }
             }
         } else {
-            Executor.delayOnIO({
+            ThreadUtils.runOnIODelayed(delayMills) {
                 if (running) repeatSendToAll(
                     frame,
                     interrupt,
                     listener,
                     delayMills
                 )
-            }, delayMills)
+            }
         }
         return this
     }

+ 8 - 15
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/PortManager.kt → data/src/main/java/com/grkj/data/hardware/modbus/PortManager.kt

@@ -1,18 +1,12 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
 import androidx.annotation.WorkerThread
 import com.epton.sdk.SerialPort
 import com.grkj.data.data.MMKVConstants
+import com.grkj.data.utils.event.RestartAppEvent
+import com.grkj.data.utils.event.ToastEvent
 import com.grkj.shared.utils.extension.toHexStrings
-import com.grkj.ui_base.R
-import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.ui_base.utils.event.RestartAppEvent
-import com.grkj.ui_base.utils.extension.tip
-import com.kongzue.dialogx.dialogs.PopTip
-import com.sik.sikcore.SIKCore
+import com.grkj.shared.utils.i18n.I18nManager
 import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.extension.saveMMKVData
 import com.sik.sikcore.extension.toJson
@@ -26,7 +20,6 @@ import java.io.OutputStream
 import java.util.concurrent.Executors
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
-import kotlin.system.exitProcess
 
 /**
  * 串口通信管理器
@@ -142,7 +135,7 @@ class PortManager private constructor(
             } catch (e: Exception) {
                 blocked = false
                 logger.error("异常 : ${e.message}")
-                PopTip.build().tip("串口[${port}, ${bps}]打开失败[${e.javaClass.simpleName}]${e.message}")
+                ToastEvent.sendToastEvent("串口[${port}, ${bps}]打开失败[${e.javaClass.simpleName}]${e.message}")
                 return null
             }
         }
@@ -379,7 +372,7 @@ class PortManager private constructor(
                     // 打开失败,清掉旧配置,提示一下
                     logger.warn("缓存的串口 $savedPort 打开失败,准备重新扫描")
                     MMKVConstants.KEY_PORT_CONFIG.saveMMKVData("")
-                    PopTip.build().tip("主控板串口已变更,正在重新扫描…")
+                    ToastEvent.sendToastEvent("主控板串口已变更,正在重新扫描…")
                 }
             }
 
@@ -389,12 +382,12 @@ class PortManager private constructor(
             if (newPort != null) {
                 // 3. 扫描到就保存,下次直接用
                 MMKVConstants.KEY_PORT_CONFIG.saveMMKVData(newPort)
-                PopTip.build().tip(CommonUtils.getStr("scan_complete_app_restarting"))
+                ToastEvent.sendToastEvent(I18nManager.t("scan_complete_app_restarting"))
                 RestartAppEvent.sendRestartAppEvent()
                 logger.info("扫描到新主控板串口: $newPort")
                 return null
             } else {
-                PopTip.build().tip("未找到从机,请检查硬件连接")
+                ToastEvent.sendToastEvent("未找到从机,请检查硬件连接")
                 return null
             }
         }

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/StatusListener.kt → data/src/main/java/com/grkj/data/hardware/modbus/StatusListener.kt

@@ -1,4 +1,4 @@
-package com.grkj.ui_base.utils.modbus
+package com.grkj.data.hardware.modbus
 
 /**
  * 状态监听器

+ 2 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/event/GetTicketStatusEvent.kt → data/src/main/java/com/grkj/data/utils/event/GetTicketStatusEvent.kt

@@ -1,7 +1,7 @@
-package com.grkj.ui_base.utils.event
+package com.grkj.data.utils.event
 
-import com.grkj.shared.model.EventBean
 import com.grkj.data.data.EventConstants
+import com.grkj.shared.model.EventBean
 import com.grkj.shared.utils.event.EventHelper
 import com.huyuhui.fastble.data.BleDevice
 

+ 2 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/event/ModbusInitCompleteEvent.kt → data/src/main/java/com/grkj/data/utils/event/ModbusInitCompleteEvent.kt

@@ -1,7 +1,7 @@
-package com.grkj.ui_base.utils.event
+package com.grkj.data.utils.event
 
-import com.grkj.shared.model.EventBean
 import com.grkj.data.data.EventConstants
+import com.grkj.shared.model.EventBean
 import com.grkj.shared.utils.event.EventHelper
 
 /**

+ 2 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/event/RestartAppEvent.kt → data/src/main/java/com/grkj/data/utils/event/RestartAppEvent.kt

@@ -1,7 +1,7 @@
-package com.grkj.ui_base.utils.event
+package com.grkj.data.utils.event
 
-import com.grkj.shared.model.EventBean
 import com.grkj.data.data.EventConstants
+import com.grkj.shared.model.EventBean
 import com.grkj.shared.utils.event.EventHelper
 
 /**

+ 2 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/event/SwitchCollectionUpdateEvent.kt → data/src/main/java/com/grkj/data/utils/event/SwitchCollectionUpdateEvent.kt

@@ -1,7 +1,7 @@
-package com.grkj.ui_base.utils.event
+package com.grkj.data.utils.event
 
-import com.grkj.shared.model.EventBean
 import com.grkj.data.data.EventConstants
+import com.grkj.shared.model.EventBean
 import com.grkj.shared.utils.event.EventHelper
 
 /**

+ 28 - 0
data/src/main/java/com/grkj/data/utils/event/ToastEvent.kt

@@ -0,0 +1,28 @@
+package com.grkj.data.utils.event
+
+import com.grkj.data.data.EventConstants
+import com.grkj.shared.model.EventBean
+import com.grkj.shared.utils.event.EventHelper
+
+/**
+ * 弹窗事件
+ */
+class ToastEvent(
+    val msg: String? = null
+) {
+    companion object {
+        /**
+         * 发送加载通知
+         */
+        @JvmStatic
+        fun sendToastEvent(
+            msg: String? = null
+        ) {
+            val toastEventBean = EventBean<ToastEvent>(
+                EventConstants.EVENT_TOAST_CODE,
+                ToastEvent(msg)
+            )
+            EventHelper.sendEvent(toastEventBean)
+        }
+    }
+}

+ 1 - 0
shared/build.gradle.kts

@@ -56,6 +56,7 @@ dependencies {
     api(libs.sik.extension.core)
     api(libs.sik.extension.encrypt)
     api(libs.sik.extension.image)
+    api(libs.sik.extension.android)
     api(libs.sik.comm)
     api("org.mindrot:jbcrypt:0.4")
     implementation("com.machinezoo.sourceafis:sourceafis:3.15.0")

+ 0 - 2
ui-base/build.gradle.kts

@@ -58,9 +58,7 @@ dependencies {
     ksp("com.google.dagger:hilt-android-compiler:2.56.2")
     api(libs.android.autosize)
     api(libs.avi.library)
-    api(libs.sik.extension.android)
     api(libs.dialogx)
-    api(libs.fastble)
     api("androidx.palette:palette-ktx:1.0.0")
     api("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha")
     api("io.github.scwang90:refresh-header-classics:3.0.0-alpha")

+ 9 - 1
ui-base/src/main/java/com/grkj/ui_base/base/BaseActivity.kt

@@ -15,7 +15,7 @@ import com.grkj.shared.model.EventBean
 import com.grkj.data.data.EventConstants
 import com.grkj.data.data.MainDomainData
 import com.grkj.shared.utils.KeyboardUtils
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.dialog.LoadingDialog
 import com.grkj.ui_base.utils.event.JumpViewEvent
 import com.grkj.data.utils.event.LoadingEvent
@@ -133,6 +133,14 @@ abstract class BaseActivity<V : ViewDataBinding> : AppCompatActivity(), CustomAd
                 }
             }
 
+            EventConstants.EVENT_TOAST_CODE -> {
+                (event.data as LoadingEvent).apply {
+                    msg?.let {
+                        showToast(it)
+                    }
+                }
+            }
+
             EventConstants.EVENT_JUMP_TO -> {
                 (event.data as JumpViewEvent).apply {
                     graphMap?.filter { it.value == navGraphId }?.firstNotNullOf {

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/base/BaseFragment.kt

@@ -17,7 +17,7 @@ import androidx.navigation.NavController
 import androidx.navigation.fragment.findNavController
 import com.grkj.shared.model.EventBean
 import com.grkj.shared.utils.KeyboardUtils
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.extension.tip

+ 74 - 82
ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt

@@ -6,8 +6,17 @@ import com.google.gson.Gson
 import com.grkj.data.data.DictConstants
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.di.LogicManager
+import com.grkj.data.enums.HardwareMode
 import com.grkj.data.enums.JobTicketStatusEnum
 import com.grkj.data.enums.RoleEnum
+import com.grkj.data.hardware.ble.BleBean
+import com.grkj.data.hardware.ble.BleCmdManager
+import com.grkj.data.hardware.ble.BleConnectionManager
+import com.grkj.data.hardware.ble.BleConst
+import com.grkj.data.hardware.ble.BleReturnDispatcher
+import com.grkj.data.hardware.ble.BleSendDispatcher
+import com.grkj.data.hardware.ble.CustomBleWriteCallback
+import com.grkj.data.hardware.modbus.DeviceConst
 import com.grkj.data.model.dos.IsJobTicketStep
 import com.grkj.data.model.local.DeviceTakeUpdate
 import com.grkj.data.model.local.UpdateKeyReturn
@@ -16,29 +25,19 @@ import com.grkj.data.model.local.WorkTicketSend
 import com.grkj.data.model.local.WorkTicketSend.LockListBO
 import com.grkj.data.model.req.LockPointUpdateReq
 import com.grkj.data.model.res.TicketDetailRes
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.shared.utils.extension.startsWith
 import com.grkj.shared.utils.i18n.I18nManager
-import com.grkj.ui_base.R
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.Executor
 import com.grkj.ui_base.utils.SPUtils
-import com.grkj.ui_base.utils.ble.BleBean
-import com.grkj.ui_base.utils.ble.BleCmdManager
-import com.grkj.ui_base.utils.ble.BleConnectionManager
-import com.grkj.ui_base.utils.ble.BleConst
-import com.grkj.ui_base.utils.ble.BleReturnDispatcher
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
-import com.grkj.ui_base.utils.ble.CustomBleWriteCallback
 import com.grkj.ui_base.utils.event.CurrentModeEvent
 import com.grkj.ui_base.utils.event.DeviceExceptionEvent
-import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.event.TicketFinishedEvent
 import com.grkj.ui_base.utils.event.UpdateTicketProgressEvent
 import com.grkj.ui_base.utils.extension.serialNo
 import com.grkj.ui_base.utils.extension.tip
-import com.grkj.ui_base.utils.modbus.DeviceConst
-import com.grkj.ui_base.utils.modbus.ModBusController
 import com.huyuhui.fastble.data.BleDevice
 import com.huyuhui.fastble.exception.BleException
 import com.kongzue.dialogx.dialogs.PopTip
@@ -130,7 +129,8 @@ object BleBusinessManager {
                     BleSendDispatcher.scheduleDisconnect(bleBean.bleDevice.mac)
                     logger.info("断开连接发钥匙:${bleBean.bleDevice.mac}")
                     // 打开钥匙卡扣
-                    val keyBean = ModBusController.getKeyByMac(bleBean.bleDevice.mac)
+                    val keyBean =
+                        HardwareMode.getCurrentHardwareMode().getKeyBeanByMac(bleBean.bleDevice.mac)
                     if (keyBean == null) {
                         LoadingEvent.sendLoadingEvent("未找到钥匙信息", true)
                         PopTip.build().tip(CommonUtils.getStr("key_not_exists"))
@@ -138,12 +138,11 @@ object BleBusinessManager {
                         LoadingEvent.sendLoadingEvent(
                             CommonUtils.getStr("take_out_key_tip"), true
                         )
-                        val dock = ModBusController.getDockByKeyMac(bleBean.bleDevice.mac)
                         keyBean.isReady = false
-                        ModBusController.controlKeyBuckle(
-                            true, keyBean.idx, dock?.addr
+                        HardwareMode.getCurrentHardwareMode().controlKeyBuckle(
+                            true, bleBean.bleDevice.mac
                         )
-                        ModBusController.updateKeyReadyStatus(
+                        HardwareMode.getCurrentHardwareMode().updateKeyReadyStatus(
                             bleBean.bleDevice.mac, false, 1
                         )
                         PopTip.build().tip(CommonUtils.getStr("take_out_key"))
@@ -161,7 +160,7 @@ object BleBusinessManager {
             // 待机模式
             2 -> {
                 if (res == 1) {
-                    ModBusController.updateKeyReadyStatus(
+                    HardwareMode.getCurrentHardwareMode().updateKeyReadyStatus(
                         bleBean.bleDevice.mac, true, 2
                     )
                     // 延时再次获取当前状态,触发handleCurrentMode里工作票下发状态检查
@@ -279,11 +278,12 @@ object BleBusinessManager {
                 } else {
                     PopTip.build().tip(CommonUtils.getStr("send_ticket_fail"))
                     logger.error("Send ticket fail")
-                    ModBusController.getKeyByMac(bleBean.bleDevice.mac)?.let { itKey ->
-                        ModbusBusinessManager.removeDeviceTake(
-                            DeviceConst.DEVICE_TYPE_KEY, itKey.rfid
-                        )
-                    }
+                    HardwareMode.getCurrentHardwareMode().getRfidByKeyMac(bleBean.bleDevice.mac)
+                        ?.let {
+                            HardwareBusinessManager.removeDeviceTake(
+                                DeviceConst.DEVICE_TYPE_KEY, it
+                            )
+                        }
                 }
             }
         }
@@ -375,12 +375,13 @@ object BleBusinessManager {
             // 待机模式
             0x02.toByte() -> {
                 // 根据情况看是否需要下发工作票
-                ModBusController.getKeyByMac(currentModeEvent.bleBean.bleDevice.mac)?.let { key ->
+                HardwareMode.getCurrentHardwareMode()
+                    .getRfidByKeyMac(currentModeEvent.bleBean.bleDevice.mac)?.let { rfid ->
                     // 判断是否有待取的钥匙
-                    val updateBo = ModbusBusinessManager.getWaitTakeDeviceByRfid(
-                        DeviceConst.DEVICE_TYPE_KEY, key.rfid.toString()
+                    val updateBo = HardwareBusinessManager.getWaitTakeDeviceByRfid(
+                        DeviceConst.DEVICE_TYPE_KEY, rfid
                     )
-                    if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+                    if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
                             DeviceConst.DEVICE_TYPE_LOCK, updateBo?.ticketId
                         )
                     ) {
@@ -403,12 +404,10 @@ object BleBusinessManager {
                             }
                         }
                     } ?: let {
-                        ModBusController.updateKeyReadyStatus(
-                            currentModeEvent.bleBean.bleDevice.mac, true, 4
-                        )
-                        ModBusController.controlKeyBuckle(
-                            false, currentModeEvent.bleBean.bleDevice.mac
-                        )
+                        HardwareMode.getCurrentHardwareMode()
+                            .updateKeyReadyStatus(currentModeEvent.bleBean.bleDevice.mac, true, 4)
+                        HardwareMode.getCurrentHardwareMode()
+                            .controlKeyBuckle(false, currentModeEvent.bleBean.bleDevice.mac)
                         LoadingEvent.sendLoadingEvent()
                         ThreadUtils.runOnIO {
                             BleReturnDispatcher.scheduleDisconnect(currentModeEvent.bleBean.bleDevice.mac)
@@ -416,12 +415,10 @@ object BleBusinessManager {
                         }
                     }
                 } ?: let {
-                    ModBusController.updateKeyReadyStatus(
-                        currentModeEvent.bleBean.bleDevice.mac, true, 4
-                    )
-                    ModBusController.controlKeyBuckle(
-                        false, currentModeEvent.bleBean.bleDevice.mac
-                    )
+                    HardwareMode.getCurrentHardwareMode()
+                        .updateKeyReadyStatus(currentModeEvent.bleBean.bleDevice.mac, true, 4)
+                    HardwareMode.getCurrentHardwareMode()
+                        .controlKeyBuckle(false, currentModeEvent.bleBean.bleDevice.mac)
                     LoadingEvent.sendLoadingEvent()
                     ThreadUtils.runOnIO {
                         BleReturnDispatcher.scheduleDisconnect(currentModeEvent.bleBean.bleDevice.mac)
@@ -447,12 +444,10 @@ object BleBusinessManager {
             val jobTicketData =
                 LogicManager.jobTicketLogic.getJobTicketDataByTicketId(itBO.ticketId)
             if (jobTicketData == null) {
-                ModBusController.updateKeyReadyStatus(
-                    currentModeEvent.bleBean.bleDevice.mac, true, 4
-                )
-                ModBusController.controlKeyBuckle(
-                    false, currentModeEvent.bleBean.bleDevice.mac
-                )
+                HardwareMode.getCurrentHardwareMode()
+                    .updateKeyReadyStatus(currentModeEvent.bleBean.bleDevice.mac, true, 4)
+                HardwareMode.getCurrentHardwareMode()
+                    .controlKeyBuckle(false, currentModeEvent.bleBean.bleDevice.mac)
                 LoadingEvent.sendLoadingEvent()
                 logger.info("作业票数据为空")
                 return@runOnIO
@@ -628,7 +623,7 @@ object BleBusinessManager {
                 if (finishedStatus.first) {
                     Executor.delayOnIO(500) {
                         handleKeyReturn(bleDevice, workTicketGet, finishedStatus.second)
-                        ModbusBusinessManager.checkTicketAndSendTicket(bleDevice.mac)
+                        HardwareBusinessManager.checkTicketAndSendTicket(bleDevice.mac)
                     }
                 } else {
                     // 当前策略:作业票未完成禁止归还钥匙
@@ -650,11 +645,8 @@ object BleBusinessManager {
                             BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
                             logger.info("断开连接归还取消:${bleDevice.mac}")
                             // 打开卡扣,防止初始化的时候选择不处理钥匙导致无法使用
-                            val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
-                            val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac }
-                            keyBean?.let {
-                                ModBusController.controlKeyBuckle(true, keyBean.idx, dock.addr)
-                            }
+                            HardwareMode.getCurrentHardwareMode()
+                                .controlKeyBuckle(true, bleDevice.mac)
                         })
                 }
             }
@@ -737,16 +729,12 @@ object BleBusinessManager {
         ticketFinished: Boolean,
         forceReturn: Boolean = false
     ) {
-        val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
-        val keyBean = dock?.getKeyList()?.find { it.mac == bleDevice.mac }
-        keyBean?.let {
-            ModBusController.controlKeyBuckle(false, keyBean.idx, dock.addr)
-        }
+        HardwareMode.getCurrentHardwareMode().controlKeyBuckle(false, bleDevice.mac)
         if (ticketFinished && !forceReturn) {
             switchReadyMode(bleDevice)
         } else {
             // 上报隔离点状态
-            val keyNfc = ModBusController.getKeyByMac(bleDevice.mac)?.rfid
+            val keyNfc = HardwareMode.getCurrentHardwareMode().getRfidByKeyMac(bleDevice.mac)
             workTicketGet?.data?.forEach { data ->
                 val updateList = mutableListOf<LockPointUpdateReq>()
                 data.dataList?.filter { it.closed == 1 && it.status == it.target }
@@ -856,7 +844,7 @@ object BleBusinessManager {
                                     logger.info("刷新界面:${it}")
                                     UpdateTicketProgressEvent.sendUpdateTicketProgressEvent(it)
                                 }
-                                ModbusBusinessManager.removeDeviceTake(
+                                HardwareBusinessManager.removeDeviceTake(
                                     DeviceConst.DEVICE_TYPE_KEY, keyNfc
                                 )
                                 // 确认归还,切换为待机模式
@@ -878,14 +866,8 @@ object BleBusinessManager {
                                         )
                                     }
                                 } else {
-                                    val dock = ModBusController.getDockByKeyMac(bleDevice.mac)
-                                    val keyBean =
-                                        dock?.getKeyList()?.find { it.mac == bleDevice.mac }
-                                    keyBean?.let {
-                                        ModBusController.controlKeyBuckle(
-                                            true, keyBean.idx, dock.addr
-                                        )
-                                    }
+                                    HardwareMode.getCurrentHardwareMode()
+                                        .controlKeyBuckle(true, bleDevice.mac)
                                 }
                             }
                             TipDialog.show(
@@ -955,29 +937,25 @@ object BleBusinessManager {
      * 分配钥匙
      */
     fun handleGiveKey(deviceTakeUpdateBO: DeviceTakeUpdate) {
-        logger.info(
-            "取完锁开始发钥匙1:${
-                ModBusController.getKeyByRfid(deviceTakeUpdateBO.nfc).toJson()
-            }"
-        )
         logger.info("取完锁开始发钥匙2:${BleConnectionManager.deviceList.toJson()}")
-        BleConnectionManager.getBleDeviceByMac(ModBusController.getKeyByRfid(deviceTakeUpdateBO.nfc)?.mac)
+        BleConnectionManager.getBleDeviceByMac(
+            HardwareMode.getCurrentHardwareMode().getKeyMacByRfid(deviceTakeUpdateBO.nfc)
+        )
             ?.let {
                 BleConnectionManager.getCurrentStatus(
                     2, BleConnectionManager.getBleDeviceByMac(
-                        ModBusController.getKeyByRfid(
-                            deviceTakeUpdateBO.nfc
-                        )?.mac
+                        HardwareMode.getCurrentHardwareMode()
+                            .getKeyMacByRfid(deviceTakeUpdateBO.nfc)
                     )!!.bleDevice
                 ) {
                     if (!it) {
                         return@getCurrentStatus
                     }
                     logger.warn("handleGiveKey timeout")
-                    ModbusBusinessManager.removeDeviceTake(
+                    HardwareBusinessManager.removeDeviceTake(
                         DeviceConst.DEVICE_TYPE_KEY, deviceTakeUpdateBO.nfc
                     )
-                    ModbusBusinessManager.checkEquipCount(
+                    HardwareBusinessManager.checkEquipCount(
                         deviceTakeUpdateBO.ticketId,
                         0,
                         true
@@ -991,16 +969,16 @@ object BleBusinessManager {
                                     )
                                 })
                         } else {
-                            ModbusBusinessManager.addDeviceTake(
+                            HardwareBusinessManager.addDeviceTake(
                                 DeviceConst.DEVICE_TYPE_KEY,
                                 deviceTakeUpdateBO.ticketId,
-                                keyPair.second?.rfid!!
+                                keyPair.second
                             )
                             handleGiveKey(
                                 DeviceTakeUpdate(
                                     DeviceConst.DEVICE_TYPE_KEY,
                                     deviceTakeUpdateBO.ticketId,
-                                    keyPair.second?.rfid!!
+                                    keyPair.second ?: ""
                                 )
                             )
                         }
@@ -1035,11 +1013,25 @@ object BleBusinessManager {
             val keyStatusList = keyStatus.await()
             val slotTypeList = slotType.await()
             withContext(Dispatchers.Default) {
-                ModBusController.getOneKey(
+                HardwareMode.getCurrentHardwareMode().getOneKey(
                     slotsPage?.records?.filter {
-                        it.slotType == slotTypeList.find { d -> I18nManager.t(d.dictLabel) == I18nManager.t("key") }?.dictValue && it.status == slotStatusList.find { d -> d.dictLabel == I18nManager.t("abnormal") }?.dictValue
+                        it.slotType == slotTypeList.find { d ->
+                            I18nManager.t(d.dictLabel) == I18nManager.t(
+                                "key"
+                            )
+                        }?.dictValue && it.status == slotStatusList.find { d ->
+                            d.dictLabel == I18nManager.t(
+                                "abnormal"
+                            )
+                        }?.dictValue
                     }?.toMutableList() ?: mutableListOf(),
-                    (keyPage?.records?.filter { it.exStatus == keyStatusList.find { d -> I18nManager.t(d.dictLabel) == I18nManager.t("abnormal") }?.dictValue }
+                    (keyPage?.records?.filter {
+                        it.exStatus == keyStatusList.find { d ->
+                            I18nManager.t(
+                                d.dictLabel
+                            ) == I18nManager.t("abnormal")
+                        }?.dictValue
+                    }
                         ?.map { it.keyNfc ?: "" }?.toMutableList() ?: mutableListOf()),
                     exceptKeyMac
                 )

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/business/DataBusiness.kt

@@ -9,7 +9,7 @@ import com.grkj.data.model.res.CabinetSlotsRes
 import com.grkj.data.model.res.KeyPageRes
 import com.grkj.data.model.res.LockPageRes
 import com.grkj.ui_base.business.BleBusinessManager.connectExistsKey
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
+import com.grkj.data.hardware.ble.BleSendDispatcher
 import kotlinx.coroutines.suspendCancellableCoroutine
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory

+ 362 - 121
ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt → ui-base/src/main/java/com/grkj/ui_base/business/HardwareBusinessManager.kt

@@ -1,43 +1,50 @@
 package com.grkj.ui_base.business
 
+import android.annotation.SuppressLint
+import com.grkj.data.config.ISCSConfig
+import com.grkj.data.data.DictConstants
+import com.grkj.data.data.MMKVConstants
+import com.grkj.data.data.MainDomainData
 import com.grkj.data.di.LogicManager
+import com.grkj.data.enums.HardwareMode
+import com.grkj.data.hardware.ble.BleConnectionManager
+import com.grkj.data.hardware.ble.BleSendDispatcher
+import com.grkj.data.hardware.can.CanCommands
+import com.grkj.data.hardware.can.CanDeviceConst
+import com.grkj.data.hardware.can.CanHelper
+import com.grkj.data.hardware.can.DeviceModel
+import com.grkj.data.hardware.modbus.DeviceConst
+import com.grkj.data.hardware.modbus.DockBean
+import com.grkj.data.hardware.modbus.ModBusController
 import com.grkj.data.model.local.DeviceTakeUpdate
 import com.grkj.data.model.req.LockTakeUpdateReq
-import com.grkj.ui_base.R
-import com.grkj.data.data.DictConstants
-import com.grkj.data.data.MainDomainData
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.utils.event.LoadingEvent
+import com.grkj.shared.utils.extension.removeLeadingZeros
+import com.grkj.shared.utils.extension.toHexStrings
+import com.grkj.shared.utils.i18n.I18nManager
+import com.grkj.ui_base.listeners.CanDeviceListener
 import com.grkj.ui_base.listeners.DeviceListener
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.Executor
 import com.grkj.ui_base.utils.SPUtils
-import com.grkj.ui_base.utils.ble.BleConnectionManager
 import com.grkj.ui_base.utils.event.DeviceTakeUpdateEvent
-import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.event.UpdateTicketProgressEvent
-import com.grkj.shared.utils.extension.removeLeadingZeros
 import com.grkj.ui_base.utils.extension.serialNo
-import com.grkj.shared.utils.extension.toHexStrings
-import com.grkj.shared.utils.i18n.I18nManager
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
 import com.grkj.ui_base.utils.extension.tip
-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.SIKCore
+import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.thread.ThreadUtils
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
 import kotlinx.coroutines.withContext
 import org.slf4j.LoggerFactory
-import kotlin.plus
 
 /**
  * 硬件业务管理
  */
-object ModbusBusinessManager {
-    private val logger = LoggerFactory.getLogger(ModbusBusinessManager::class.java)
+object HardwareBusinessManager {
+    private val logger = LoggerFactory.getLogger(HardwareBusinessManager::class.java)
 
     // 设备待取列表(需要报给后台的列表,等实际取完再上报)
     @JvmStatic
@@ -45,6 +52,8 @@ object ModbusBusinessManager {
 
     private val listeners = ArrayList<DeviceListener>()
 
+    private val canListeners = ArrayList<CanDeviceListener>()
+
     private var initListener: (() -> Unit)? = null
 
     /**
@@ -54,6 +63,13 @@ object ModbusBusinessManager {
         listeners.add(DeviceListener(key, listener))
     }
 
+    /**
+     * 注册状态监听
+     */
+    fun registerCanStatusListener(key: Any, listener: (List<DeviceModel>) -> Unit) {
+        canListeners.add(CanDeviceListener(key, listener))
+    }
+
     /**
      * 取消注册状态监听
      */
@@ -66,6 +82,18 @@ object ModbusBusinessManager {
         }
     }
 
+    /**
+     * 取消注册状态监听
+     */
+    fun unregisterCanListener(key: Any) {
+        val it = canListeners.iterator()
+        while (it.hasNext()) {
+            if (it.next().key == key) {
+                it.remove()
+            }
+        }
+    }
+
     /**
      * 注册初始化监听
      */
@@ -115,7 +143,7 @@ object ModbusBusinessManager {
      * 根据作业票获取是否有指定设备未取
      */
     fun hasAnyDeviceWaitTakeByTicketId(deviceType: Int, ticketId: Long?): Boolean {
-        return ModbusBusinessManager.mDeviceTakeList.any { it.deviceType == deviceType && it.ticketId == ticketId }
+        return mDeviceTakeList.any { it.deviceType == deviceType && it.ticketId == ticketId }
     }
 
     /**
@@ -144,11 +172,11 @@ object ModbusBusinessManager {
                                 logger.info("钥匙取出,移除设备取出信息:${info.nfc}")
                                 removeDeviceTake(DeviceConst.DEVICE_TYPE_KEY, info.nfc)
                                 logger.info("设备取出信息:${mDeviceTakeList}")
-                                ModBusController.getKeyByRfid(
-                                    info.nfc
-                                )?.mac?.let {
-                                    BleConnectionManager.unregisterConnectListener(it)
-                                }
+                                HardwareMode.getCurrentHardwareMode().getKeyMacByRfid(info.nfc)
+                                    ?.let {
+                                        BleConnectionManager.unregisterConnectListener(it)
+                                    }
+
                             } else {
                                 logger.info("更新钥匙取出异常")
                             }
@@ -169,8 +197,7 @@ object ModbusBusinessManager {
                             Executor.runOnMain {
                                 if (isSuccess == false) {
                                     logger.error("Lock take report fail")
-                                    PopTip.build()
-                                        .tip(CommonUtils.getStr("lock_take_report_fail"))
+                                    PopTip.build().tip(CommonUtils.getStr("lock_take_report_fail"))
                                     SPUtils.saveTicketTakeLockException(info.ticketId)
                                     mDeviceTakeList.removeIf { it.deviceType == DeviceConst.DEVICE_TYPE_LOCK && it.nfc == info.nfc }
                                     mDeviceTakeList.removeIf { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.ticketId == info.ticketId }
@@ -217,11 +244,12 @@ object ModbusBusinessManager {
 
 
     // 3. 重写 checkEquipCount
+    @SuppressLint("MissingPermission")
     fun checkEquipCount(
         ticketId: Long,
         needLockCount: Int,
         isNeedKey: Boolean,
-        callBack: (Pair<Byte, DockBean.KeyBean?>?, MutableMap<Byte, MutableList<DockBean.LockBean>>) -> Unit
+        callBack: (Pair<Any, String?>?, MutableMap<Any, MutableList<Pair<Int, String>>>) -> Unit
     ) {
         // 你可以改成接收 CoroutineScope 或者直接在全局 Scope 启动
         ThreadUtils.runOnIO {
@@ -232,14 +260,10 @@ object ModbusBusinessManager {
                 val locksPage = DataBusiness.getLocksPage()
 
                 // —— 并行加载字典(或按需串行也行) ——
-                val lockStatus =
-                    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 keyStatus =
-                    async { DataBusiness.fetchDict(DictConstants.KEY_KEY_STATUS) }
+                val lockStatus = 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 keyStatus = async { DataBusiness.fetchDict(DictConstants.KEY_KEY_STATUS) }
 
                 // 等待字典加载完成
                 val lockStatusList = lockStatus.await()
@@ -250,27 +274,27 @@ object ModbusBusinessManager {
                 // —— 在 Default 线程做计算密集操作 ——
                 val lockMap = withContext(Dispatchers.Default) {
                     logger.info("获取锁具数量:${needLockCount}")
-                    ModBusController.getLocks(
-                        needLockCount,
-                        slotsPage?.records?.filter {
-                            it.slotType == slotTypeList.find { d -> I18nManager.t(d.dictLabel) == I18nManager.t("lock") }?.dictValue && it.status == slotStatusList.find { d ->
+                    HardwareMode.getCurrentHardwareMode()
+                        .getLocks(needLockCount, slotsPage?.records?.filter {
+                            it.slotType == slotTypeList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "lock"
+                                )
+                            }?.dictValue && it.status == slotStatusList.find { d ->
                                 I18nManager.t(d.dictLabel) == I18nManager.t(
                                     "abnormal"
                                 )
                             }?.dictValue
-                        }?.toMutableList() ?: mutableListOf(),
-                        (locksPage?.records?.filter {
+                        }?.toMutableList() ?: mutableListOf(), (locksPage?.records?.filter {
                             it.exStatus == lockStatusList.find { d ->
                                 I18nManager.t(d.dictLabel) == I18nManager.t(
                                     "abnormal"
                                 )
                             }?.dictValue
-                        }
-                            ?.map { it.lockNfc ?: "" }?.toMutableList() ?: mutableListOf()).apply {
+                        }?.map { it.lockNfc ?: "" }?.toMutableList() ?: mutableListOf()).apply {
                             addAll(mDeviceTakeList.filter { it.deviceType == DeviceConst.DEVICE_TYPE_LOCK && it.ticketId != ticketId }
                                 .map { it.nfc })
-                        }
-                    )
+                        })
                 }
 
                 val actualLockCount = lockMap.values.sumBy { it.size }
@@ -284,35 +308,30 @@ object ModbusBusinessManager {
                 }
 
                 // —— 如果需钥匙,再请求并计算 ——
-                var keyPair: Pair<Byte, DockBean.KeyBean?>? = null
+                var keyPair: Pair<Any, String?>? = null
                 if (isNeedKey) {
                     val keyPage = DataBusiness.getKeyPage()
                     keyPair = withContext(Dispatchers.Default) {
-                        ModBusController.getOneKey(
-                            slotsPage?.records?.filter {
-                                it.slotType == slotTypeList.find { d ->
-                                    I18nManager.t(d.dictLabel) == I18nManager.t(
-                                        "key"
-                                    )
-                                }?.dictValue && it.status == slotStatusList.find { d ->
-                                    I18nManager.t(d.dictLabel) == I18nManager.t(
-                                        "abnormal"
-                                    )
-                                }?.dictValue
-                            }?.toMutableList() ?: mutableListOf(),
-                            (keyPage?.records?.filter {
-                                it.exStatus == keyStatusList.find { d ->
-                                    I18nManager.t(d.dictLabel) == I18nManager.t(
-                                        "abnormal"
-                                    )
-                                }?.dictValue
-                            }
-                                ?.map { it.keyNfc ?: "" }?.toMutableList()
-                                ?: mutableListOf()).apply {
-                                addAll(mDeviceTakeList.filter { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.ticketId != ticketId }
-                                    .map { it.nfc })
-                            }
-                        )
+                        HardwareMode.getCurrentHardwareMode().getOneKey(slotsPage?.records?.filter {
+                            it.slotType == slotTypeList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "key"
+                                )
+                            }?.dictValue && it.status == slotStatusList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "abnormal"
+                                )
+                            }?.dictValue
+                        }?.toMutableList() ?: mutableListOf(), (keyPage?.records?.filter {
+                            it.exStatus == keyStatusList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "abnormal"
+                                )
+                            }?.dictValue
+                        }?.map { it.keyNfc ?: "" }?.toMutableList() ?: mutableListOf()).apply {
+                            addAll(mDeviceTakeList.filter { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.ticketId != ticketId }
+                                .map { it.nfc })
+                        })
                     }
                     if (keyPair == null) {
                         PopTip.build().tip(CommonUtils.getStr("no_available_key"))
@@ -320,7 +339,6 @@ object ModbusBusinessManager {
                 }
                 // —— 全部计算完毕,在主线程一次性回调 ——
                 callBack(keyPair, lockMap)
-
             } catch (e: Exception) {
                 // 根据需求处理异常,或把异常信息也通过 callback 返回
                 LoadingEvent.sendLoadingEvent()
@@ -338,7 +356,52 @@ object ModbusBusinessManager {
      * 4、蓝牙连接
      * 5、蓝牙数据通讯
      */
-    private fun deviceStatusHandle(res: Any) {
+    private fun canDeviceStatusHandle(res: List<DeviceModel>) {
+        logger.debug("硬件状态:{}", res)
+        if (MainDomainData.userInfo == null || res.isEmpty()) {
+            return@canDeviceStatusHandle
+        }
+        val deviceType = CanHelper.getDeviceTypeByNodeId(res[0].nodeId)
+        when (deviceType) {
+            CanDeviceConst.DEVICE_KEY_DOCK -> {
+                res.filterIsInstance<DeviceModel.DeviceKey>().forEach {
+                    canDeviceKeyHandler(it)
+                }
+            }
+
+            CanDeviceConst.DEVICE_LOCK_DOCK -> {
+                res.filterIsInstance<DeviceModel.CommonDevice>().forEach {
+                    canDeviceLockHandler(it)
+                }
+            }
+
+            CanDeviceConst.DEVICE_KEY_CABINET_CONTROL_BOARD -> {
+                // TODO 钥匙柜主控板
+            }
+
+            CanDeviceConst.DEVICE_MATERIAL_CABINET_CONTROL_BOARD -> {
+                // TODO 物资柜主控板
+            }
+        }
+        Executor.delayOnMain(200) {
+            canListeners.forEach { it.callBack(res) }
+        }
+        Executor.delayOnMain(200) {
+            if (!ISCSConfig.isInit) {
+                initListener?.invoke()
+            }
+        }
+    }
+
+    /**
+     * 硬件状态
+     * 1、检测到有钥匙
+     * 2、上锁
+     * 3、开启充电
+     * 4、蓝牙连接
+     * 5、蓝牙数据通讯
+     */
+    private fun modbusDeviceStatusHandle(res: Any) {
         logger.debug("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
         if (res.isEmpty() || res.any { it.isEmpty() }) {
             var tipStr = CommonUtils.getStr("no_response_board_exists") + " : "
@@ -426,8 +489,7 @@ object ModbusBusinessManager {
      * 设备挂锁处理
      */
     private fun deviceLockHandler(
-        dockBean: DockBean,
-        lockBean: DockBean.LockBean
+        dockBean: DockBean, lockBean: DockBean.LockBean
     ) {
         if (lockBean.isExist) {
             ModBusController.readLockRfid(dockBean.addr, lockBean.idx) { res ->
@@ -435,18 +497,15 @@ object ModbusBusinessManager {
                     logger.error("Lock rfid error")
                     return@readLockRfid
                 }
-                val rfid =
-                    res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                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 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()
@@ -460,10 +519,7 @@ object ModbusBusinessManager {
                                         "abnormal"
                                     )
                                 }?.dictValue
-                            }
-                                ?.map { it.lockNfc }?.toMutableList()
-                                ?: mutableListOf())
-                        ) {
+                            }?.map { it.lockNfc }?.toMutableList() ?: mutableListOf())) {
                             PopTip.build().tip(CommonUtils.getStr("lock_exception_tag"))
                         } else if (slotsPage?.records?.filter {
                                 it.slotType == slotTypeList.find { d ->
@@ -490,8 +546,7 @@ object ModbusBusinessManager {
                                         if (itRst.isNotEmpty()) {
                                             // 上报锁具信息
                                             LogicManager.jobTicketLogic.updateLockReturn(
-                                                rfid,
-                                                SIKCore.getApplication().serialNo()
+                                                rfid, SIKCore.getApplication().serialNo()
                                             ) {}
                                         }
                                     }
@@ -507,18 +562,206 @@ object ModbusBusinessManager {
         } else {
             logger.info("挂锁取出-:${lockBean.rfid}")
             handleDeviceTake(
-                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_LOCK, lockBean.rfid),
-                lockBean.rfid
+                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_LOCK, lockBean.rfid), lockBean.rfid
+            )
+        }
+    }
+
+    /**
+     * 设备挂锁处理
+     * Can设备
+     */
+    private fun canDeviceLockHandler(lockBean: DeviceModel.CommonDevice) {
+        if (!lockBean.deviceChange) {
+            return
+        }
+        if (lockBean.isExist) {
+            val req = CanCommands.forDevice(lockBean.nodeId).getSlotRfid_1to5(lockBean.id)
+            CanHelper.readFrom(req) { res ->
+                val rfidData = res?.payload ?: byteArrayOf()
+                if (rfidData.size < 11) {
+                    logger.error("Lock rfid error")
+                    return@readFrom
+                }
+                val rfid = rfidData.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                lockBean.rfid = 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() }
+                    val lockStatus = lockStatusReq.await()
+                    val slotsPage = slotsPageReq.await()
+                    val slotStatusList = slotStatus.await()
+                    val slotTypeList = slotType.await()
+                    LogicManager.hardwareLogic.getIsLockPage { lockData ->
+                        //锁rfid未异常正常请求锁数据,关锁
+                        if (rfid in (lockData?.records?.filter {
+                                it.exStatus == lockStatus.find {
+                                    I18nManager.t(it.dictLabel) == I18nManager.t(
+                                        "abnormal"
+                                    )
+                                }?.dictValue
+                            }?.map { it.lockNfc }?.toMutableList() ?: mutableListOf())) {
+                            PopTip.build().tip(CommonUtils.getStr("lock_exception_tag"))
+                        } else if (slotsPage?.records?.filter {
+                                it.slotType == slotTypeList.find { d ->
+                                    I18nManager.t(d.dictLabel) == I18nManager.t(
+                                        "lock"
+                                    )
+                                }?.dictValue && it.status == slotStatusList.find { d ->
+                                    I18nManager.t(d.dictLabel) == I18nManager.t(
+                                        "abnormal"
+                                    )
+                                }?.dictValue
+                            }
+                                ?.find { it.row?.toInt() == lockBean.nodeId && lockBean.id == it.col?.toInt() } != null) {
+                            PopTip.build().tip(CommonUtils.getStr("slot_exception_tag"))
+                        } else {
+                            logger.info("挂锁归还:${lockBean.rfid}")
+                            LogicManager.hardwareLogic.getLockInfo(rfid) {
+                                logger.info("挂锁信息:${it}")
+                                if (it != null && it.lockNfc?.isNotEmpty() == true) {
+                                    // TODO 考虑快速拿取
+                                    val req = CanCommands.forDevice(lockBean.nodeId)
+                                        .controlOne_1to5(lockBean.id, true)
+                                    CanHelper.writeTo(req) { itRst ->
+                                        // 上报锁具信息
+                                        LogicManager.jobTicketLogic.updateLockReturn(
+                                            rfid, SIKCore.getApplication().serialNo()
+                                        ) {}
+                                    }
+                                }
+                                Executor.delayOnMain(200) {
+                                    canListeners.forEach { it.callBack(listOf(lockBean)) }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            logger.info("挂锁取出-:${lockBean.rfid}")
+            handleDeviceTake(
+                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_LOCK, lockBean.rfid), lockBean.rfid
             )
         }
     }
 
+    /**
+     * 钥匙设备处理
+     * Can设备
+     */
+    private fun canDeviceKeyHandler(keyBean: DeviceModel.DeviceKey) {
+        if (!keyBean.deviceChange) {
+            return
+        }
+        logger.info("钥匙状态变化DeviceKeyHandler:${keyBean}")
+        if (keyBean.isExist) {
+            // 放回钥匙,读取rfid
+            val req = CanCommands.forDevice(keyBean.nodeId).let {
+                if (keyBean.id == 0) {
+                    it.getLeftRfid()
+                } else {
+                    it.getRightRfid()
+                }
+            }
+            CanHelper.readFrom(req) { res ->
+                val rfidData = res?.payload ?: byteArrayOf()
+                if (ISCSConfig.isInit) {
+                    CanHelper.writeTo(
+                        CanCommands.forDevice(keyBean.nodeId)
+                            .setCharge(keyBean.id == 0, keyBean.id == 1)
+                    )
+                }
+                if (rfidData.size < 11) {
+                    logger.error("Key rfid error")
+                    return@readFrom
+                }
+                val rfid = rfidData.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                logger.info("读取到的rfid:${rfid}")
+                keyBean.rfid = rfid
+                logger.info("更新rfid完成:${keyBean}")
+                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() }
+                    val keyStatus = keyStatusReq.await()
+                    val 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 {
+                                I18nManager.t(it.dictLabel) == I18nManager.t(
+                                    "abnormal"
+                                )
+                            }?.dictValue
+                        }?.map { it.keyNfc }?.toMutableList() ?: mutableListOf())) {
+                        PopTip.build().tip(
+                            CommonUtils.getStr("key_exception_tag")
+                        )
+                    } else if (slotsPage?.records?.filter {
+                            it.slotType == slotTypeList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "key"
+                                )
+                            }?.dictValue && it.status == slotStatusList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "abnormal"
+                                )
+                            }?.dictValue
+                        }
+                            ?.find { it.row?.toInt() == keyBean.nodeId && it.col?.toInt() == (keyBean.nodeId + (keyBean.id) * 2 + 1) } != null) {
+                        PopTip.build().tip(
+                            CommonUtils.getStr("slot_exception_tag")
+                        )
+                    } else {
+                        // 放回钥匙,上锁
+                        val req = CanCommands.forDevice(keyBean.nodeId).controlLatch(keyBean.id, 1)
+                        CanHelper.writeTo(req) {
+                            LogicManager.hardwareLogic.getKeyInfo(rfid) {
+                                logger.info("钥匙:${rfid},${it}")
+                                if (it != null && !it.macAddress.isNullOrEmpty()) {
+                                    keyBean.mac = it.macAddress!!
+                                } else {
+                                    logger.error("Get key info fail : $rfid")
+                                    if (ISCSConfig.isInit) {
+                                        PopTip.build().tip(CommonUtils.getStr("get_key_info_fail"))
+                                    }
+
+                                    val req = CanCommands.forDevice(keyBean.nodeId)
+                                        .controlLatch(keyBean.id, 0)
+                                    CanHelper.writeTo(req)
+                                }
+                                Executor.delayOnMain(200) {
+                                    canListeners.forEach { it.callBack(listOf(keyBean)) }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else if (!keyBean.isCharging) {//增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
+            handleDeviceTake(
+                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid), keyBean.rfid
+            )
+            Executor.delayOnMain(200) {
+                canListeners.forEach { it.callBack(listOf(keyBean)) }
+            }
+        }
+    }
+
     /**
      * 钥匙设备处理
      */
     private fun deviceKeyHandler(
-        dockBean: DockBean,
-        keyBean: DockBean.KeyBean
+        dockBean: DockBean, keyBean: DockBean.KeyBean
     ) {
         logger.info("钥匙状态变化DeviceKeyHandler:${keyBean}")
         if (keyBean.isExist) {
@@ -535,18 +778,15 @@ object ModbusBusinessManager {
                     logger.error("Key rfid error")
                     return@readKeyRfid
                 }
-                val rfid =
-                    res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
                 logger.info("读取到的rfid:${rfid}")
                 ModBusController.updateKeyRfid(
                     dockBean.addr, keyBean.idx, rfid
                 )
                 logger.info("更新rfid完成:${keyBean}")
                 ThreadUtils.runOnIO {
-                    val slotStatus =
-                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_STATUS) }
-                    val slotType =
-                        async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_TYPE) }
+                    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) }
@@ -563,15 +803,16 @@ object ModbusBusinessManager {
                                     "abnormal"
                                 )
                             }?.dictValue
-                        }
-                            ?.map { it.keyNfc }?.toMutableList()
-                            ?: mutableListOf())
-                    ) {
+                        }?.map { it.keyNfc }?.toMutableList() ?: mutableListOf())) {
                         PopTip.build().tip(
                             CommonUtils.getStr("key_exception_tag")
                         )
                     } else if (slotsPage?.records?.filter {
-                            it.slotType == slotTypeList.find { d -> I18nManager.t(d.dictLabel) == I18nManager.t("key") }?.dictValue && it.status == slotStatusList.find { d ->
+                            it.slotType == slotTypeList.find { d ->
+                                I18nManager.t(d.dictLabel) == I18nManager.t(
+                                    "key"
+                                )
+                            }?.dictValue && it.status == slotStatusList.find { d ->
                                 I18nManager.t(d.dictLabel) == I18nManager.t(
                                     "abnormal"
                                 )
@@ -590,9 +831,7 @@ object ModbusBusinessManager {
                                 logger.info("钥匙:${rfid},${it}")
                                 if (it != null && !it.macAddress.isNullOrEmpty()) {
                                     ModBusController.updateKeyMac(
-                                        dockBean.addr,
-                                        keyBean.idx,
-                                        it.macAddress!!
+                                        dockBean.addr, keyBean.idx, it.macAddress!!
                                     )
                                     ModBusController.updateKeyReadyStatus(
                                         it.macAddress!!, false, 5
@@ -616,8 +855,7 @@ object ModbusBusinessManager {
             }
         } else if (!keyBean.isCharging) {//增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
             handleDeviceTake(
-                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid),
-                keyBean.rfid
+                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid), keyBean.rfid
             )
             Executor.delayOnMain(200) {
                 listeners.forEach { it.callBack(dockBean) }
@@ -629,9 +867,16 @@ object ModbusBusinessManager {
      * 总的监听,做预处理,其余的所有监听均使用本监听处理后的数据,只允许调用一次
      */
     fun registerMainListener() {
-        ModBusController.registerStatusListener(this) { res ->
-            deviceStatusHandle(res)
+        if (MMKVConstants.KEY_HARDWARE_MODE.getMMKVData(HardwareMode.MODBUS.name) == HardwareMode.MODBUS.name) {
+            ModBusController.registerStatusListener(this) { res ->
+                modbusDeviceStatusHandle(res)
+            }
+        } else {
+            CanHelper.addDeviceChangeListener(this) { res ->
+                canDeviceStatusHandle(res)
+            }
         }
+
     }
 
     /**
@@ -639,9 +884,9 @@ object ModbusBusinessManager {
      */
     fun checkTicketAndSendTicket(keyMac: String) {
         logger.info("开始检查是否存在作业票")
-        val keyBean = ModBusController.getKeyByMac(keyMac)
+        val keyRfid = HardwareMode.getCurrentHardwareMode().getRfidByKeyMac(keyMac)
         logger.info("待发设备:${mDeviceTakeList}")
-        mDeviceTakeList.find { it.nfc == keyBean?.rfid }?.let { itKey ->
+        mDeviceTakeList.find { it.nfc == keyRfid }?.let { itKey ->
             logger.info("存在作业票,下发作业票")
             BleBusinessManager.handleGiveKey(itKey)
         }
@@ -651,35 +896,31 @@ object ModbusBusinessManager {
      * 根据rfid获取mac地址
      */
     fun getKeyMacByRfid(rfid: String): String {
-        return ModBusController.getKeyByRfid(rfid)?.mac ?: ""
+        return HardwareMode.getCurrentHardwareMode().getKeyMacByRfid(rfid) ?: ""
     }
 
     /**
      * 获取钥匙仓位位置
      */
     fun getKeySlotPosition(keyNfc: String): String {
-        val keyData = ModBusController.getKeyByRfid(keyNfc)
-        return if (keyData == null) CommonUtils.getStr("not_in_slot")
-            .toString() else "${keyData.row}-${keyData.idx + 1}"
+        val slotPosition = HardwareMode.getCurrentHardwareMode().getSlotPosition(keyNfc)
+        return slotPosition
     }
 
     /**
      * 获取挂锁仓位位置
      */
     fun getLockSlotPosition(lockNfc: String): String {
-        val lockData = ModBusController.getLockByRfid(lockNfc)
-        return if (lockData == null) CommonUtils.getStr("not_in_slot")
-            .toString() else "${lockData.row}-${lockData.idx + 1}"
+        val slotPosition = HardwareMode.getCurrentHardwareMode().getLockSlotPosition(lockNfc)
+        return slotPosition
     }
 
     /**
      * 获取存在的钥匙
      */
-    fun getExistsKey(): List<DockBean.KeyBean> {
-        val dockData =
-            ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
-        return dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.flatMap { it.deviceList }
-            .filterIsInstance<DockBean.KeyBean>()
+    fun getExistsKeyMac(): List<String?> {
+        val macs = HardwareMode.getCurrentHardwareMode().getExistsKeyMac()
+        return macs
     }
 
     /**

+ 7 - 0
ui-base/src/main/java/com/grkj/ui_base/listeners/CanDeviceListener.kt

@@ -0,0 +1,7 @@
+package com.grkj.ui_base.listeners
+
+import com.grkj.data.hardware.can.DeviceModel
+
+class CanDeviceListener(
+    val key: Any, val callBack: (List<DeviceModel>) -> Unit
+)

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/listeners/DeviceListener.kt

@@ -1,6 +1,6 @@
 package com.grkj.ui_base.listeners
 
-import com.grkj.ui_base.utils.modbus.DockBean
+import com.grkj.data.hardware.modbus.DockBean
 
 // Modbus数据页面监听
 class DeviceListener(

+ 6 - 5
ui-base/src/main/java/com/grkj/ui_base/service/CheckKeyInfoTask.kt

@@ -1,8 +1,8 @@
 package com.grkj.ui_base.service
 
 import android.annotation.SuppressLint
-import com.grkj.ui_base.business.ModbusBusinessManager
-import com.grkj.ui_base.utils.ble.BleSendDispatcher
+import com.grkj.ui_base.business.HardwareBusinessManager
+import com.grkj.data.hardware.ble.BleSendDispatcher
 import com.sik.cronjob.annotations.CronJob
 import kotlinx.coroutines.*
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -74,9 +74,10 @@ class CheckKeyInfoTask {
         logger.info("开始检查钥匙信息")
         awaitLogin()
 
-        for (bean in ModbusBusinessManager.getExistsKey()) {
-            val mac = bean.mac ?: continue
-            handleSingleMac(mac) // 串行执行
+        for (mac in HardwareBusinessManager.getExistsKeyMac()) {
+            mac?.let {
+                handleSingleMac(mac) // 串行执行
+            } ?: continue
         }
 
         logger.info("检查钥匙信息结束")

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

@@ -3,7 +3,7 @@ package com.grkj.ui_base.utils.event
 import com.grkj.shared.model.EventBean
 import com.grkj.data.data.EventConstants
 import com.grkj.shared.utils.event.EventHelper
-import com.grkj.ui_base.utils.ble.BleBean
+import com.grkj.data.hardware.ble.BleBean
 
 /**
  * 当前模式处理事件

+ 1 - 2
ui-base/src/main/java/com/grkj/ui_base/widget/CustomNavBar.kt

@@ -23,11 +23,10 @@ import androidx.annotation.MenuRes
 import androidx.appcompat.view.menu.MenuBuilder
 import androidx.core.view.isEmpty
 import com.grkj.ui_base.R
-import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.data.config.ISCSConfig
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.sik.sikcore.extension.setDebouncedClickListener
 import me.jessyan.autosize.AutoSize
-import me.jessyan.autosize.AutoSizeConfig
 import me.jessyan.autosize.utils.AutoSizeUtils
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory

+ 3 - 4
ui-base/src/main/java/com/grkj/ui_base/widget/CustomSwitchStationLayer.kt

@@ -9,11 +9,10 @@ import android.graphics.PointF
 import android.os.SystemClock
 import android.view.MotionEvent
 import android.view.ViewConfiguration
-import androidx.core.content.ContextCompat
 import com.grkj.ui_base.R
-import com.grkj.ui_base.business.ModbusBusinessManager
+import com.grkj.ui_base.business.HardwareBusinessManager
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.ui_base.utils.modbus.DockBean
+import com.grkj.data.hardware.modbus.DockBean
 import com.onlylemi.mapview.library.MapView
 import com.onlylemi.mapview.library.layer.MapBaseLayer
 import com.sik.sikcore.SIKCore
@@ -457,7 +456,7 @@ class CustomSwitchStationLayer @JvmOverloads constructor(
                 canvas.concat(currentMatrix)
 
                 val points = synchronized(dataLock) { stationList.toList() }
-                val switches = runCatching { ModbusBusinessManager.getSwitchData() }.getOrNull()
+                val switches = runCatching { HardwareBusinessManager.getSwitchData() }.getOrNull()
                 for (p in points) {
                     val c = centerOf(p)