1
0

sync-service.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. const {
  2. buildReadFrame,
  3. getMaxReadQuantity
  4. } = require('./modbus-rtu')
  5. const controlState = require('./control-page-state')
  6. const controlService = require('./control-service')
  7. const paramsPageState = require('./params-page-state')
  8. const transport = require('./ble-transport')
  9. const {
  10. notifyPageToast
  11. } = require('./page-toast')
  12. const {
  13. addCoilReadValues,
  14. addWordReadValues
  15. } = require('./register-value-utils')
  16. const readValues = {
  17. coils: {},
  18. words: {}
  19. }
  20. let paramsSnapshot = paramsPageState.createInitialState()
  21. let paramsSnapshotVersion = 0
  22. const READ_STEPS = [
  23. {
  24. address: 0x00,
  25. functionCode: 0x01,
  26. label: '同步线圈 00-10',
  27. quantity: 17,
  28. onResponse(response, step) {
  29. addCoilReadValues(readValues, step.address, step.quantity, response)
  30. controlService.applyControlReadValues(readValues.coils)
  31. }
  32. },
  33. {
  34. address: 0x30,
  35. functionCode: 0x03,
  36. label: '同步估算器参数 30-4A',
  37. quantity: 27,
  38. onResponse(response, step) {
  39. addWordReadValues(readValues, step.address, response)
  40. }
  41. },
  42. {
  43. address: 0x60,
  44. functionCode: 0x03,
  45. label: '同步参数配置 60-8D',
  46. quantity: 46,
  47. onResponse(response, step) {
  48. addWordReadValues(readValues, step.address, response)
  49. controlService.applyMotorReadWords(response.words || [], step.address)
  50. }
  51. },
  52. {
  53. address: controlState.DRIVER_PARAM_START_ADDRESS,
  54. functionCode: 0x04,
  55. label: '同步驱动器硬件参数 A0-B3',
  56. quantity: controlState.DRIVER_PARAM_WORD_COUNT,
  57. onResponse(response, step) {
  58. addWordReadValues(readValues, step.address, response)
  59. controlService.applyDriverReadWords(response.words || [])
  60. }
  61. },
  62. {
  63. address: controlState.STATUS_START_ADDRESS,
  64. functionCode: 0x04,
  65. label: '同步状态 C0-DC',
  66. quantity: controlState.STATUS_WORD_COUNT,
  67. onResponse(response, step) {
  68. addWordReadValues(readValues, step.address, response)
  69. controlService.applyStatusReadWords(response.words || [], step.address)
  70. }
  71. }
  72. ]
  73. function splitReadStep(step) {
  74. const maxQuantity = getMaxReadQuantity(step.functionCode)
  75. if (!maxQuantity || step.quantity <= maxQuantity) return [step]
  76. const chunks = []
  77. let offset = 0
  78. while (offset < step.quantity) {
  79. const quantity = Math.min(step.quantity - offset, maxQuantity)
  80. const address = step.address + offset
  81. chunks.push({
  82. ...step,
  83. address,
  84. label: `${step.label} ${address.toString(16).toUpperCase()}-${(address + quantity - 1).toString(16).toUpperCase()}`,
  85. quantity
  86. })
  87. offset += quantity
  88. }
  89. return chunks
  90. }
  91. let syncing = false
  92. const subscribers = []
  93. function getState() {
  94. return {
  95. isSyncing: syncing,
  96. syncVersion: paramsSnapshotVersion
  97. }
  98. }
  99. function notify() {
  100. const state = getState()
  101. subscribers.slice().forEach((subscriber) => {
  102. subscriber(state)
  103. })
  104. }
  105. function setSyncing(value) {
  106. syncing = !!value
  107. notify()
  108. }
  109. transport.subscribe((transportState) => {
  110. if (!transportState.connectedDevice && syncing) {
  111. setSyncing(false)
  112. }
  113. })
  114. function subscribe(subscriber) {
  115. if (typeof subscriber !== 'function') return () => {}
  116. subscribers.push(subscriber)
  117. subscriber(getState())
  118. return () => {
  119. const index = subscribers.indexOf(subscriber)
  120. if (index >= 0) subscribers.splice(index, 1)
  121. }
  122. }
  123. function getSharedSlaveAddress() {
  124. try {
  125. return transport.getSlaveAddress()
  126. } catch (error) {
  127. transport.showCommandAlert('从机地址错误', error.message)
  128. return null
  129. }
  130. }
  131. function resetReadValues() {
  132. readValues.coils = {}
  133. readValues.words = {}
  134. }
  135. function getParamsSnapshot() {
  136. return {
  137. ...paramsSnapshot,
  138. syncVersion: paramsSnapshotVersion
  139. }
  140. }
  141. async function syncAllRegisters() {
  142. if (syncing) return false
  143. const transportState = transport.getState()
  144. if (!transportState.connectedDevice) return false
  145. const slaveAddress = getSharedSlaveAddress()
  146. if (slaveAddress === null) return false
  147. setSyncing(true)
  148. resetReadValues()
  149. try {
  150. for (const step of READ_STEPS) {
  151. for (const chunk of splitReadStep(step)) {
  152. const response = await transport.sendManagedFrame(
  153. buildReadFrame(slaveAddress, chunk.functionCode, chunk.address, chunk.quantity),
  154. chunk.label,
  155. {
  156. address: chunk.address,
  157. functionCode: chunk.functionCode,
  158. kind: 'sync-read',
  159. quantity: chunk.quantity,
  160. slaveAddress
  161. }
  162. )
  163. if (!response) return false
  164. if (typeof chunk.onResponse === 'function') {
  165. chunk.onResponse(response, chunk)
  166. }
  167. }
  168. }
  169. paramsSnapshot = paramsPageState.applyReadValues(paramsSnapshot, readValues)
  170. paramsSnapshotVersion += 1
  171. notify()
  172. notifyPageToast('同步完成')
  173. return true
  174. } finally {
  175. setSyncing(false)
  176. }
  177. }
  178. module.exports = {
  179. getParamsSnapshot,
  180. getState,
  181. subscribe,
  182. syncAllRegisters
  183. }