communication.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. const settingsService = require('../../store/settings-store.js')
  2. const themeService = require('../../store/theme-store.js')
  3. const transport = require('../../transport/ble-core.js')
  4. const manualRtuService = require('../../features/manual-rtu/service.js')
  5. const {
  6. createPageToast
  7. } = require('../../utils/page-toast.js')
  8. const communicationService = require('../../features/communication/service.js')
  9. const {
  10. LOG_MODE_OPTIONS,
  11. STORAGE_ACCESS_AREA_OPTIONS,
  12. STORAGE_ACCESS_COMMAND_OPTIONS,
  13. decorateLogs,
  14. getLogModeToggleText,
  15. getManualStatePayload,
  16. getNextLogMode,
  17. getNextSerialMode,
  18. getProtocolModeState,
  19. normalizeStorageAccessState,
  20. normalizeSerialState
  21. } = require('../../features/communication/view-model.js')
  22. const INITIAL_SERIAL_STATE = normalizeSerialState({
  23. serialInputText: '',
  24. serialMode: 'hex'
  25. })
  26. Page({
  27. data: {
  28. ...themeService.getState(),
  29. ...settingsService.getState(),
  30. ...getProtocolModeState(settingsService.getState()),
  31. ...transport.getState(),
  32. ...manualRtuService.getState(),
  33. logs: decorateLogs(transport.getState().logs, 'hex'),
  34. logMode: 'hex',
  35. logModeToggleText: getLogModeToggleText('hex'),
  36. logModeOptions: LOG_MODE_OPTIONS,
  37. storageAccessAreaOptions: STORAGE_ACCESS_AREA_OPTIONS,
  38. storageAccessCommandOptions: STORAGE_ACCESS_COMMAND_OPTIONS,
  39. ...normalizeStorageAccessState({
  40. storageAccessAreaIndex: 3,
  41. storageAccessAddress: '0000',
  42. storageAccessCommandIndex: 0,
  43. storageAccessDataText: '',
  44. storageAccessLength: '0004'
  45. }),
  46. serialTitleText: '串口发送',
  47. ...INITIAL_SERIAL_STATE,
  48. toastText: '',
  49. toastType: ''
  50. },
  51. onLoad() {
  52. this.pageToast = createPageToast(this, this.data)
  53. this.lastSyncedSlaveAddress = ''
  54. transport.init()
  55. settingsService.init()
  56. themeService.init()
  57. const settingsState = settingsService.getState()
  58. manualRtuService.setProtocolInput({
  59. slaveAddress: settingsState.modbusSlaveAddress
  60. })
  61. this.lastSyncedSlaveAddress = settingsState.modbusSlaveAddress
  62. this.unsubscribeTheme = themeService.subscribe((themeState) => {
  63. this.setData(themeState)
  64. })
  65. this.unsubscribeSettings = settingsService.subscribe((settingsState) => {
  66. this.setData({
  67. ...settingsState,
  68. ...getProtocolModeState(settingsState)
  69. })
  70. if (settingsState.modbusSlaveAddress !== this.lastSyncedSlaveAddress) {
  71. this.lastSyncedSlaveAddress = settingsState.modbusSlaveAddress
  72. manualRtuService.setProtocolInput({
  73. slaveAddress: settingsState.modbusSlaveAddress
  74. })
  75. }
  76. })
  77. this.unsubscribeTransport = transport.subscribe((transportState) => {
  78. this.setData({
  79. ...transportState,
  80. logs: decorateLogs(transportState.logs, this.data.logMode)
  81. })
  82. })
  83. this.unsubscribeManualRtu = manualRtuService.subscribe((manualState) => {
  84. this.setData(getManualStatePayload(manualState))
  85. })
  86. },
  87. onShow() {
  88. if (this.pageToast) {
  89. this.pageToast.setActive(true)
  90. }
  91. },
  92. onHide() {
  93. if (this.pageToast) {
  94. this.pageToast.setActive(false)
  95. }
  96. },
  97. onUnload() {
  98. if (this.pageToast) {
  99. this.pageToast.destroy()
  100. this.pageToast = null
  101. }
  102. if (this.unsubscribeTheme) {
  103. this.unsubscribeTheme()
  104. this.unsubscribeTheme = null
  105. }
  106. if (this.unsubscribeSettings) {
  107. this.unsubscribeSettings()
  108. this.unsubscribeSettings = null
  109. }
  110. if (this.unsubscribeTransport) {
  111. this.unsubscribeTransport()
  112. this.unsubscribeTransport = null
  113. }
  114. if (this.unsubscribeManualRtu) {
  115. this.unsubscribeManualRtu()
  116. this.unsubscribeManualRtu = null
  117. }
  118. },
  119. noop() {},
  120. switchSerialMode() {
  121. this.setData(normalizeSerialState(this.data, {
  122. serialMode: getNextSerialMode(this.data.serialMode)
  123. }))
  124. },
  125. switchLogMode(event) {
  126. const requestedMode = event && event.currentTarget && event.currentTarget.dataset
  127. ? event.currentTarget.dataset.mode
  128. : ''
  129. const mode = requestedMode || getNextLogMode(this.data.logMode)
  130. this.setData({
  131. logMode: mode,
  132. logModeToggleText: getLogModeToggleText(mode),
  133. logs: decorateLogs(transport.getState().logs, mode)
  134. })
  135. },
  136. clearCommunicationLogs() {
  137. transport.clearLogs()
  138. },
  139. onSerialInput(event) {
  140. this.setData(normalizeSerialState(this.data, {
  141. serialInputText: event.detail.value
  142. }))
  143. },
  144. clearSerialInput() {
  145. this.setData(normalizeSerialState(this.data, {
  146. serialInputText: ''
  147. }))
  148. },
  149. async sendSerialFrame() {
  150. try {
  151. const result = await communicationService.sendSerialFrame(this.data)
  152. if (!result.ok) {
  153. this.setData({
  154. serialErrorText: result.errorText || '发送失败'
  155. })
  156. return
  157. }
  158. if (this.pageToast) this.pageToast.show('已发送')
  159. this.setData({
  160. ...(result.serialState || {}),
  161. serialErrorText: '',
  162. serialPreviewHex: result.previewHex || '',
  163. serialPreviewLengthText: `${(result.bytes || []).length} bytes`
  164. })
  165. } catch (error) {
  166. this.setData({
  167. serialErrorText: error.message || '发送失败'
  168. })
  169. }
  170. },
  171. onProtocolCommandChange(event) {
  172. manualRtuService.setCommandIndex(Number(event.detail.value))
  173. },
  174. onProtocolInput(event) {
  175. const field = event.currentTarget.dataset.field
  176. if (!field) return
  177. manualRtuService.setProtocolInput({
  178. [field]: event.detail.value
  179. })
  180. },
  181. onProtocolCoilChange(event) {
  182. manualRtuService.setProtocolInput({
  183. coilEnabled: !!event.detail.value
  184. })
  185. },
  186. openProtocolMultipleDialog() {
  187. manualRtuService.openProtocolMultipleDialog()
  188. },
  189. closeProtocolMultipleDialog() {
  190. manualRtuService.closeProtocolMultipleDialog()
  191. },
  192. toggleProtocolMultipleExpanded() {
  193. manualRtuService.toggleProtocolMultipleExpanded()
  194. },
  195. onProtocolMultipleQuantityChange(event) {
  196. manualRtuService.setProtocolMultipleQuantity(event.detail.value)
  197. },
  198. onProtocolMultipleValueInput(event) {
  199. const index = Number(event.currentTarget.dataset.index)
  200. manualRtuService.setProtocolMultipleValue(index, event.detail.value)
  201. },
  202. onProtocolMultipleTypeChange(event) {
  203. const index = Number(event.currentTarget.dataset.index)
  204. manualRtuService.setProtocolMultipleType(index, Number(event.detail.value))
  205. },
  206. onProtocolMultipleTextLengthInput(event) {
  207. const index = Number(event.currentTarget.dataset.index)
  208. manualRtuService.setProtocolMultipleTextLength(index, event.detail.value)
  209. },
  210. async sendProtocolFrame(event) {
  211. const source = event && event.currentTarget && event.currentTarget.dataset
  212. ? event.currentTarget.dataset.source
  213. : ''
  214. if (this.data.protocolMultipleDialog && this.data.protocolMultipleDialog.visible && source !== 'dialog') {
  215. if (this.pageToast) this.pageToast.show('请在多值窗口内发送', 'error')
  216. return
  217. }
  218. if (!this.data.connectedDevice) {
  219. if (this.pageToast) this.pageToast.show('请先连接蓝牙设备', 'error')
  220. return
  221. }
  222. const response = await manualRtuService.sendGeneratedFrame()
  223. if (response && this.pageToast) {
  224. this.pageToast.show(response === true ? '已发送' : '已收到回复')
  225. } else if (this.pageToast) {
  226. const manualState = manualRtuService.getState()
  227. this.pageToast.show(manualState.protocolStatusText || '发送失败或超时未回复', 'error')
  228. }
  229. },
  230. switchStorageAccessCommandMode(event) {
  231. const storageAccessCommandIndex = Number(event.currentTarget.dataset.index)
  232. const nextState = normalizeStorageAccessState(this.data, {
  233. storageAccessCommandIndex
  234. })
  235. this.setData(nextState)
  236. },
  237. onStorageAccessInput(event) {
  238. const field = event.currentTarget.dataset.field
  239. if (!field) return
  240. const changed = {
  241. [field]: event.detail.value
  242. }
  243. const nextState = normalizeStorageAccessState(this.data, changed)
  244. this.setData(nextState)
  245. },
  246. onStorageAccessAreaChange(event) {
  247. const storageAccessAreaIndex = Number(event.detail.value)
  248. const nextState = normalizeStorageAccessState(this.data, {
  249. storageAccessAreaIndex
  250. })
  251. this.setData(nextState)
  252. },
  253. async sendStorageAccessProtocolFrame() {
  254. try {
  255. const command = STORAGE_ACCESS_COMMAND_OPTIONS[Number(this.data.storageAccessCommandIndex) || 0] || STORAGE_ACCESS_COMMAND_OPTIONS[0]
  256. const result = await communicationService.executeStorageAccessProtocol(this.data)
  257. if (!result.ok) {
  258. this.setData({
  259. storageAccessErrorText: result.errorText || '操作失败'
  260. })
  261. return
  262. }
  263. if (command.key === 'sync') {
  264. this.setData({
  265. storageAccessErrorText: '',
  266. storageAccessSyncInfoText: result.syncInfoText || this.data.storageAccessSyncInfoText
  267. })
  268. if (this.pageToast) {
  269. const codeInfoAddressText = result.codeInfoAddressText || '0000'
  270. const codeInfoByteLengthText = result.codeInfoByteLengthText || '0000'
  271. this.pageToast.show(`同步完成 codeInfo 0x${codeInfoAddressText} / 0x${codeInfoByteLengthText}`)
  272. }
  273. return
  274. }
  275. if (command.key === 'read') {
  276. this.setData({
  277. storageAccessErrorText: '',
  278. storageAccessPreviewHexText: result.previewHex || ''
  279. })
  280. if (this.pageToast) this.pageToast.show(`读取完成 ${(result.bytes || []).length} bytes`)
  281. return
  282. }
  283. this.setData({
  284. storageAccessErrorText: ''
  285. })
  286. if (this.pageToast) this.pageToast.show('写入完成')
  287. } catch (error) {
  288. this.setData({
  289. storageAccessErrorText: error.message || '操作失败'
  290. })
  291. }
  292. }
  293. })