transport.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. const transport = require('../../transport/ble-core.js')
  2. const {
  3. alignBootloaderBuffer,
  4. getBootloaderExpectedLength,
  5. parseBootloaderResponse
  6. } = require('../../protocols/bootloader/index.js')
  7. const RESPONSE_TIMEOUT_MS = 3000
  8. let activeResponseWaiter = null
  9. function abortActiveResponseWaiter(message) {
  10. if (!activeResponseWaiter) return false
  11. const waiter = activeResponseWaiter
  12. activeResponseWaiter = null
  13. waiter.abort(new Error(message || '蓝牙已断开'))
  14. return true
  15. }
  16. function waitForResponse(kind, timeout, options = {}) {
  17. const expectedLength = getBootloaderExpectedLength(kind)
  18. const buffer = []
  19. return new Promise((resolve, reject) => {
  20. let settled = false
  21. let timer = null
  22. let unsubscribe = () => {}
  23. const waiter = {
  24. abort: (error) => {
  25. cleanup()
  26. reject(error)
  27. }
  28. }
  29. abortActiveResponseWaiter('新的 BootLoader 响应等待已开始')
  30. activeResponseWaiter = waiter
  31. unsubscribe = transport.subscribeRawResponse((bytes) => {
  32. buffer.push.apply(buffer, bytes)
  33. alignBootloaderBuffer(buffer)
  34. if (buffer.length < expectedLength) return
  35. const frame = buffer.slice(0, expectedLength)
  36. try {
  37. const response = parseBootloaderResponse(frame, kind)
  38. cleanup()
  39. resolve(response)
  40. } catch (error) {
  41. if (options.ignoreInvalid) {
  42. buffer.shift()
  43. return
  44. }
  45. cleanup()
  46. reject(error)
  47. }
  48. })
  49. timer = setTimeout(() => {
  50. cleanup()
  51. reject(new Error(`${kind} 响应超时`))
  52. }, timeout || RESPONSE_TIMEOUT_MS)
  53. function cleanup() {
  54. if (settled) return
  55. settled = true
  56. clearTimeout(timer)
  57. if (activeResponseWaiter === waiter) {
  58. activeResponseWaiter = null
  59. }
  60. unsubscribe()
  61. }
  62. })
  63. }
  64. async function sendRawFrame(frame, label) {
  65. return transport.sendRawFrameExact(frame, label)
  66. }
  67. async function sendFrame(frame, label, kind, timeout) {
  68. const responsePromise = kind ? waitForResponse(kind, timeout) : null
  69. const sent = await sendRawFrame(frame, label)
  70. if (!sent) {
  71. if (responsePromise) {
  72. responsePromise.catch(() => {})
  73. abortActiveResponseWaiter(`${label}发送失败`)
  74. }
  75. throw new Error(`${label}发送失败`)
  76. }
  77. return responsePromise ? responsePromise : true
  78. }
  79. module.exports = {
  80. RESPONSE_TIMEOUT_MS,
  81. abortActiveResponseWaiter,
  82. sendFrame,
  83. sendRawFrame,
  84. waitForResponse
  85. }