100 lines
2.9 KiB
JavaScript
100 lines
2.9 KiB
JavaScript
/**
|
|
* 统一等待 UUID_STATE 通知。
|
|
*
|
|
* @param {object} ble createBleCore 实例
|
|
* @param {object} options 等待配置
|
|
* @param {number[]} options.allowedCodes 允许通过的状态码;为空则接收任意状态码
|
|
* @param {boolean} options.rejectOnUnexpected 收到非 allowedCodes 状态码时是否立刻失败
|
|
* @param {number} options.timeout 超时时间(ms)
|
|
* @param {string} options.timeoutMessage 超时提示
|
|
* @param {string} options.unexpectedMessage 非预期状态提示前缀
|
|
* @param {number[]} options.refreshOnCodes 收到这些中间态状态码时重置超时计时器
|
|
* @param {number} options.refreshTimeout 重置后的窗口时长(ms),未传则回退到 timeout
|
|
*
|
|
* 中间态刷新机制:设备连接 WiFi 时会先发 STATE=4(连接中) 再发最终态,
|
|
* 若总超时短于真实 DHCP 时长会误判超时。收到 refreshOnCodes 内的中间态时
|
|
* 重置倒计时,最多延长至 refreshTimeout 指定的单次窗口时长。
|
|
*/
|
|
export function waitForProtocolState(ble, options = {}) {
|
|
const {
|
|
allowedCodes = [],
|
|
rejectOnUnexpected = false,
|
|
timeout = 6000,
|
|
timeoutMessage = '等待 UUID_STATE 超时',
|
|
unexpectedMessage = '收到非预期 UUID_STATE 状态码',
|
|
refreshOnCodes = [],
|
|
refreshTimeout = timeout
|
|
} = options
|
|
|
|
return new Promise((resolve, reject) => {
|
|
let timer = null
|
|
let off = null
|
|
try {
|
|
console.debug('[BLE][STATEWAIT]', 'start', {
|
|
allowed: allowedCodes.join(',') || 'ANY',
|
|
timeout,
|
|
refreshOn: refreshOnCodes.join(',') || 'NONE'
|
|
})
|
|
} catch (e) {
|
|
}
|
|
|
|
const finish = (callback) => {
|
|
if (timer) {
|
|
clearTimeout(timer)
|
|
}
|
|
|
|
if (off) {
|
|
off()
|
|
}
|
|
|
|
callback()
|
|
}
|
|
|
|
const armTimer = (duration) => {
|
|
if (timer) {
|
|
clearTimeout(timer)
|
|
}
|
|
timer = setTimeout(() => {
|
|
try {
|
|
console.debug('[BLE][STATEWAIT]', 'timeout')
|
|
} catch (e) {
|
|
}
|
|
finish(() => reject(new Error(timeoutMessage)))
|
|
}, duration)
|
|
}
|
|
|
|
armTimer(timeout)
|
|
|
|
off = ble.on('protocol:state', (payload) => {
|
|
const stateCode = Number(payload?.stateCode)
|
|
|
|
if (!allowedCodes.length || allowedCodes.includes(stateCode)) {
|
|
try {
|
|
console.debug('[BLE][STATEWAIT]', 'accept', stateCode)
|
|
} catch (e) {
|
|
}
|
|
finish(() => resolve(payload))
|
|
return
|
|
}
|
|
|
|
// 命中中间态刷新:重置超时窗口,继续等待后续最终态
|
|
if (refreshOnCodes.length && refreshOnCodes.includes(stateCode)) {
|
|
try {
|
|
console.debug('[BLE][STATEWAIT]', 'refresh', stateCode)
|
|
} catch (e) {
|
|
}
|
|
armTimer(refreshTimeout)
|
|
return
|
|
}
|
|
|
|
if (rejectOnUnexpected) {
|
|
try {
|
|
console.debug('[BLE][STATEWAIT]', 'reject', stateCode)
|
|
} catch (e) {
|
|
}
|
|
finish(() => reject(new Error(`${unexpectedMessage}: ${stateCode}`)))
|
|
}
|
|
})
|
|
})
|
|
}
|