control-service.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. const {
  2. controlState
  3. } = require('./motor-control-data')
  4. const {
  5. parseHexInteger
  6. } = require('./base-utils')
  7. const transport = require('./ble-transport')
  8. const bootloaderService = require('./bootloader-service')
  9. const settingsService = require('./settings-service')
  10. const modbusAccess = require('./modbus-access')
  11. const motorControlProtocol = require('./motor-control-protocol')
  12. let state = {
  13. ...controlState.createInitialState(),
  14. ...bootloaderService.getState()
  15. }
  16. let autoReadTimer = null
  17. let unsubscribeSettings = null
  18. let unsubscribeTransport = null
  19. const subscribers = []
  20. function getState() {
  21. return {
  22. ...state
  23. }
  24. }
  25. function notify() {
  26. const nextState = getState()
  27. subscribers.slice().forEach((subscriber) => {
  28. subscriber(nextState)
  29. })
  30. }
  31. function setState(changedData) {
  32. state = {
  33. ...state,
  34. ...changedData
  35. }
  36. notify()
  37. }
  38. function applySettingsState(settings) {
  39. const autoReadInterval = controlState.clampNumber(
  40. settings.statusPollInterval,
  41. controlState.AUTO_READ_MIN_INTERVAL,
  42. controlState.AUTO_READ_MAX_INTERVAL,
  43. state.autoReadInterval
  44. )
  45. const userStatusCount = controlState.getUserStatusCount(settings.userStatusCount)
  46. setState({
  47. autoReadInterval,
  48. userStatusCount
  49. })
  50. if (state.autoReadStatus) {
  51. scheduleAutoReadStatus(autoReadInterval)
  52. }
  53. }
  54. function subscribe(subscriber) {
  55. if (typeof subscriber !== 'function') return () => {}
  56. subscribers.push(subscriber)
  57. subscriber(getState())
  58. return () => {
  59. const index = subscribers.indexOf(subscriber)
  60. if (index >= 0) subscribers.splice(index, 1)
  61. }
  62. }
  63. function init() {
  64. transport.init()
  65. bootloaderService.init()
  66. settingsService.init()
  67. if (!unsubscribeSettings) {
  68. unsubscribeSettings = settingsService.subscribe(applySettingsState)
  69. }
  70. if (unsubscribeTransport) return
  71. unsubscribeTransport = transport.subscribe((transportState) => {
  72. const nextState = controlState.applyTransportState(state, transportState)
  73. if (nextState.autoReadStatus === false) {
  74. stopAutoReadStatus()
  75. }
  76. setState(nextState)
  77. })
  78. bootloaderService.subscribe((bootloaderState) => {
  79. setState(bootloaderState)
  80. })
  81. }
  82. function syncSharedInputs() {
  83. controlState.setSharedInputValues(state.motorParameterInputRegisters)
  84. }
  85. function applyControlReadValues(coilValues) {
  86. setState(controlState.applyControlReadValues(state, coilValues))
  87. }
  88. function applyMotorReadWords(words, startAddress = controlState.MOTOR_PARAM_START_ADDRESS) {
  89. const registerWordCache = controlState.getRegisterWordCache(startAddress, words)
  90. const motorState = controlState.applyMotorParameterReadValues(state, registerWordCache)
  91. const nextState = {
  92. ...state,
  93. ...motorState
  94. }
  95. setState({
  96. ...motorState,
  97. ...controlState.applySpeedCommandReadValue(nextState, registerWordCache[0x68])
  98. })
  99. }
  100. function applyDriverReadWords(words) {
  101. const changedState = controlState.applyDriverParameterReadValues(state, words)
  102. if (changedState.chipModel) {
  103. bootloaderService.setChipModel(changedState.chipModel)
  104. }
  105. setState(changedState)
  106. }
  107. function applyStatusReadWords(words, startAddress = controlState.STATUS_START_ADDRESS) {
  108. setState(controlState.applyStatusReadValues(words, startAddress))
  109. }
  110. function updateMotorParameterInput(index, value) {
  111. setState(controlState.applyMotorParameterInput(state, index, value))
  112. }
  113. function updateMotorParameterBlur(index, value) {
  114. setState(controlState.applyMotorParameterBlur(state, index, value))
  115. }
  116. function updateSpeedCommandInput(value) {
  117. setState(controlState.applySpeedCommandInput(state, value))
  118. }
  119. function updateSpeedCommandBlur(value) {
  120. setState(controlState.applySpeedCommandBlur(state, value))
  121. sendSpeedCommand()
  122. }
  123. function getSpeedCommandWriteWord() {
  124. const writeValue = Number(state.speedCommand.writeValue)
  125. if (!Number.isFinite(writeValue)) return null
  126. const word = Math.round(writeValue)
  127. return word >= 0 && word <= 0xFFFF ? word : null
  128. }
  129. async function sendSpeedCommand() {
  130. const slaveAddress = modbusAccess.getSharedSlaveAddress()
  131. if (slaveAddress === null) return false
  132. const writeWord = getSpeedCommandWriteWord()
  133. if (writeWord === null) {
  134. transport.showCommandAlert('转速命令错误', '请检查转速命令输入值')
  135. return false
  136. }
  137. const address = parseHexInteger(state.speedCommand.address)
  138. const response = await modbusAccess.writeSingleRegister(
  139. slaveAddress,
  140. address,
  141. writeWord,
  142. '转速命令',
  143. 'speed-command-write'
  144. )
  145. if (response) {
  146. setState({
  147. ...controlState.clearSpeedCommandDirty(state),
  148. systemTip: '转速命令已下发'
  149. })
  150. return true
  151. }
  152. return false
  153. }
  154. async function sendControlCommand(key) {
  155. const button = state.controlButtons
  156. .concat(state.controlActionButtons || [])
  157. .find((item) => item.key === key)
  158. if (!button) return
  159. const response = await motorControlProtocol.writeControlButton(
  160. button,
  161. {
  162. kind: 'control-write'
  163. }
  164. )
  165. if (response) {
  166. setState(controlState.applyControlSuccess(state, button))
  167. }
  168. }
  169. async function readControlStatus() {
  170. const slaveAddress = modbusAccess.getSharedSlaveAddress()
  171. if (slaveAddress === null) return false
  172. const startAddress = 0x00
  173. const quantity = 3
  174. const coilValues = await modbusAccess.readBitValues(
  175. slaveAddress,
  176. 0x01,
  177. startAddress,
  178. quantity,
  179. '控制状态读取',
  180. 'control-status-read'
  181. )
  182. if (!coilValues) return false
  183. setState({
  184. ...controlState.applyControlReadValues(state, coilValues),
  185. systemTip: '控制状态读取完成'
  186. })
  187. return true
  188. }
  189. async function readMotorParameters() {
  190. if (state.isReadingMotor) return
  191. const slaveAddress = modbusAccess.getSharedSlaveAddress()
  192. if (slaveAddress === null) return
  193. setState({
  194. errorText: '',
  195. isReadingMotor: true,
  196. systemTip: ''
  197. })
  198. try {
  199. const words = await modbusAccess.readRegisterWords(
  200. slaveAddress,
  201. 0x03,
  202. controlState.MOTOR_PARAM_START_ADDRESS,
  203. controlState.MOTOR_PARAM_WORD_COUNT,
  204. '电机参数读取',
  205. 'motor-main-read',
  206. { showModal: true }
  207. )
  208. if (!words) return
  209. const registerWordCache = controlState.getRegisterWordCache(controlState.MOTOR_PARAM_START_ADDRESS, words)
  210. setState({
  211. ...controlState.applyMotorParameterReadValues(state, registerWordCache),
  212. systemTip: '电机参数读取完成'
  213. })
  214. } finally {
  215. setState({
  216. isReadingMotor: false
  217. })
  218. }
  219. }
  220. async function writeMotorParameters() {
  221. if (state.isWritingMotor) return
  222. const slaveAddress = modbusAccess.getSharedSlaveAddress()
  223. if (slaveAddress === null) return
  224. const mainWrite = controlState.buildMotorMainWriteValues(state)
  225. if (!mainWrite.values) {
  226. transport.showCommandAlert('参数错误', mainWrite.errorText)
  227. return
  228. }
  229. setState({
  230. errorText: '',
  231. isWritingMotor: true,
  232. systemTip: ''
  233. })
  234. try {
  235. const mainResponse = await modbusAccess.writeMultipleRegisters(
  236. slaveAddress,
  237. controlState.MOTOR_PARAM_START_ADDRESS,
  238. mainWrite.values,
  239. '电机参数写入',
  240. 'motor-main-write'
  241. )
  242. if (!mainResponse) return
  243. setState({
  244. ...controlState.clearMotorParameterDirty(state),
  245. systemTip: '电机参数写入完成'
  246. })
  247. } finally {
  248. setState({
  249. isWritingMotor: false
  250. })
  251. }
  252. }
  253. async function readDriverParameters() {
  254. if (state.isReadingDriver) return
  255. const slaveAddress = modbusAccess.getSharedSlaveAddress()
  256. if (slaveAddress === null) return
  257. setState({
  258. errorText: '',
  259. isReadingDriver: true,
  260. systemTip: ''
  261. })
  262. try {
  263. const words = await modbusAccess.readRegisterWords(
  264. slaveAddress,
  265. 0x04,
  266. controlState.DRIVER_PARAM_START_ADDRESS,
  267. controlState.DRIVER_PARAM_WORD_COUNT,
  268. '驱动器参数读取',
  269. 'driver-read',
  270. { showModal: true }
  271. )
  272. if (words) {
  273. const changedState = controlState.applyDriverParameterReadValues(state, words)
  274. if (changedState.chipModel) {
  275. bootloaderService.setChipModel(changedState.chipModel)
  276. }
  277. setState({
  278. ...changedState,
  279. systemTip: '驱动器参数读取完成'
  280. })
  281. }
  282. } finally {
  283. setState({
  284. isReadingDriver: false
  285. })
  286. }
  287. }
  288. function chooseFirmwareFile(source) {
  289. return bootloaderService.chooseFirmwareFile(source)
  290. }
  291. function startFirmwareUpgrade() {
  292. stopAutoReadStatus()
  293. setState({
  294. autoReadStatus: false
  295. })
  296. return bootloaderService.startUpgrade()
  297. }
  298. function readProgramChecksum() {
  299. return bootloaderService.readProgramChecksum()
  300. }
  301. function handshakeBootloader() {
  302. return bootloaderService.sendHandshakeKeepAlive()
  303. }
  304. function exitBootloader() {
  305. return bootloaderService.exitBootloader()
  306. }
  307. function setAutoReadStatus(autoReadStatus) {
  308. setState({
  309. autoReadStatus
  310. })
  311. if (autoReadStatus) {
  312. scheduleAutoReadStatus(0)
  313. return
  314. }
  315. stopAutoReadStatus()
  316. }
  317. async function readStatus(options = {}) {
  318. if (options.auto && !state.connectedDevice) return false
  319. const slaveAddress = modbusAccess.getSharedSlaveAddress()
  320. if (slaveAddress === null) return false
  321. const words = await modbusAccess.readRegisterWords(
  322. slaveAddress,
  323. 0x04,
  324. controlState.STATUS_START_ADDRESS,
  325. controlState.getStatusWordCount(state.userStatusCount),
  326. '状态读取',
  327. 'status-read',
  328. { showModal: !options.auto }
  329. )
  330. if (words) {
  331. setState({
  332. ...controlState.applyStatusReadValues(words, controlState.STATUS_START_ADDRESS),
  333. systemTip: options.auto ? '' : '状态读取完成'
  334. })
  335. }
  336. return words
  337. }
  338. function scheduleAutoReadStatus(delay) {
  339. stopAutoReadStatus()
  340. autoReadTimer = setTimeout(async () => {
  341. if (!state.autoReadStatus) return
  342. await readStatus({
  343. auto: true
  344. })
  345. scheduleAutoReadStatus(state.autoReadInterval)
  346. }, delay)
  347. }
  348. function stopAutoReadStatus() {
  349. if (!autoReadTimer) return
  350. clearTimeout(autoReadTimer)
  351. autoReadTimer = null
  352. }
  353. module.exports = {
  354. getState,
  355. init,
  356. applyControlReadValues,
  357. applyDriverReadWords,
  358. applyMotorReadWords,
  359. applyStatusReadWords,
  360. exitBootloader,
  361. handshakeBootloader,
  362. readControlStatus,
  363. readDriverParameters,
  364. readMotorParameters,
  365. readProgramChecksum,
  366. readStatus,
  367. sendControlCommand,
  368. setAutoReadStatus,
  369. chooseFirmwareFile,
  370. startFirmwareUpgrade,
  371. subscribe,
  372. syncSharedInputs,
  373. updateMotorParameterBlur,
  374. updateMotorParameterInput,
  375. updateSpeedCommandBlur,
  376. updateSpeedCommandInput,
  377. writeMotorParameters
  378. }