前端使用低功耗蓝牙BLE开发的坑(分包操作之分包接收)

4,019 阅读4分钟

最近用uniapp开发微信小程序的一个项目中用到了低功耗蓝牙,但是其中收包 ,发包的时候不能超过20字节,所以就需要我们来进行分包操作了 以下是对分包接收的一些处理,分包发送操作请看 分包操作之分包发送

项目地址

github.com/menglin1997…

接收蓝牙设备传过来的数据,并进行分包接收处理

说明: 我项目中的数据结构中05是帧头, FE是帧尾,所以需要判断接收到的这个数据是否是05开头,FE结尾, 我是将接收到的数据保存到了缓存中 image.png

思路: 根据协议中的帧头帧尾和数据长度来进行处理 符合条件的就可以接收处理 不符合条件的就丢掉

    1. 如果开头结尾和帧头帧尾一致并且长度一致就保留(说明长度完整)
    1. 如果帧头对 帧尾不对 则为前边部分
    1. 如果帧头不对 帧尾不对 则为中间部分
    1. 如果帧头不对 帧尾对 则为最后一部分

根据以上四个步骤基本可以得到一串正常的数据,但是此时还有一个很重要的步骤 需要根据接收到的数据的长度判断一下实际的长度,因为很有可能接收到的帧头帧尾之间还有一个帧尾,此时需要我们把进行截取操作得到我们真正想要的数据

以下是我项目中处理分包接收数据的全部代码:

// 11 监听notify功能
var packData = '' // 分包操作
var first = '' // 开始部分
var center = '' // 中间拼接部分
var last = '' // 结尾部分
var len = 0 // 包的长度
// var flag = true // flag判断是否进行了分包操作 如果分包需要清空开始部分 中间部分 结尾部分
export function	watchNotify(isHeart) {
	// ArrayBuffer转16进度字符串示例
	function ab2hex(buffer) {
		const hexArr = Array.prototype.map.call(
			new Uint8Array(buffer),
			function (bit) {
				return ('00' + bit.toString(16)).slice(-2)
			}
		)
		return hexArr.join('')
	}
	
	return new Promise((resolve, reject) => { 
		uni.onBLECharacteristicValueChange(function (res) {
			console.log(res)
			// 监听帧头帧尾
			var resCode1 = ab2hex(res.value)
			var resCode = resCode1.toUpperCase()
			console.log(resCode, '收到的')
		
			// 1. 如果开头结尾和帧头帧尾一致并且长度一致就保留(说明长度完整)
			if (resCode.substring(resCode.length - 2, resCode.length) == 'FE' && resCode.substring(0, 2) == '05') {
				let lenTo10 = parseInt(resCode.substring(2,resCode.length - 2).length)/2
				// 1.1找出内容16进制
				let lengthTo16 = lenTo10.toString(16) + ''
				// 2.1 对16进制进行大小写转换并且补零操作
				lengthTo16 = lengthTo16.length == 1 ? '0' +  lengthTo16.toUpperCase() : lengthTo16.toUpperCase()
				let length1 = resCode.substring(2,4)
				console.log(lengthTo16, length1)
				if (lengthTo16 == length1) {
					 if (resCode.substring(8,12) == 'F020') {
					 	uni.setStorageSync('RESCODE', resCode)
					 	console.log(resCode, 'F020')
					 } else {
					 	uni.setStorageSync('RESPARAMS', resCode)
					 }
				}
				
			} else if (resCode.substring(resCode.length - 2, resCode.length) != 'FE' && resCode.substring(0, 2) == '05') { 
				// 2. 如果帧头对 帧尾不对 则为前边部分
				first = resCode
				
				console.log(first, '这个是开头部分first')
			} else if (resCode.substring(resCode.length - 2, resCode.length) != 'FE' && resCode.substring(0, 2) != '05') { 
				// 3. 如果帧头不对 帧尾不对 则为中间部分
				center = center + resCode
				console.log(center, '中间部分center')
			} else if (resCode.substring(resCode.length - 2, resCode.length) == 'FE' && resCode.substring(0, 2) != '05') {
				// 4. 如果帧头不对 帧尾对 则为最后一部分
				last = resCode
				console.log(last, '最后一部分last')
				
				// 得到实际内容
				
				var content = first + center + last
				console.log(content, '实际的内容')
				// 4.1找出内容16进制
				var resLen = (content.length - 4) / 2 // 减去4是剪掉帧头和帧尾,除以2是为了得到字节
				console.log(resLen, '实际的长度10进制')
				var lenTo16 = resLen.toString(16) + ''
				// 4.2 对16进制进行大小写转换并且补零操作
				lenTo16 = lenTo16.length == 1 ? '0' +  lenTo16.toUpperCase() : lenTo16.toUpperCase()
				console.log(lenTo16, 'lenTo16')
				// 得到包的长度
				len = content.substring(2,4)
				console.log(len, 'len')
				// 判断是否得到长度和实际长度相等
				if (lenTo16 == len) {
					if (content.substring(8,12) == 'F020') {
						uni.setStorageSync('RESCODE', content)
						console.log(content, 'F020')
					} else {
						uni.setStorageSync('RESPARAMS', content)
						console.log(content, '!F020')
					}
				} else {
					// 如果不相等, 找一下字符串中间有没有FE  然后再进行长度 帧头帧尾判断
				
					// 1.截取帧尾的FE 求出帧尾之前是否有FE
					let substrFE = content.substring(0, content.length - 2)
					console.log(substrFE, 'substrFE')
					// 2.判断是否还有FE
					// 2.1 转换为两个字符一起的数组
					let hasFEArr = strToArr(substrFE, 2)
					 // 2.2 找出是否有FE 并确定位置
					let hasFE = hasFEArr.indexOf('FE')

					console.log(hasFEArr, 'hasFEArr')
					console.log(hasFE, 'hasFE')
					// 如果有FE,截取到FE之处 判断帧头帧尾长度
					if (hasFE != -1) {
						// 将最后的数据保存到这个数组里面
						let lastConArr = []
						// 得到05-FE的内容
						hasFEArr.forEach((item, index) => {
							if (index <= hasFE) {
								lastConArr.push(item)
							}
						})
						console.log(lastConArr, 'lastConArr')
						// 判断是否是05开头FE结尾
						console.log(lastConArr[lastConArr.length - 1], 'lastConArr[lastConArr.length - 1]')
						console.log(lastConArr[0], 'lastConArr[0]')
						if (lastConArr[0] == '05' && lastConArr[lastConArr.length - 1] == 'FE') {
							// 判断得到的长度与实际长度
							let getLen = lastConArr[1]
							console.log(getLen, 'getLen')
							// 实际长度 并且转换为十六进制字符串
							let resLen = (lastConArr.length - 2).toString(16) + ''
							console.log(resLen, 'resLen1')
							// 实际长度补零操作
							resLen = resLen.length == 1 ? '0' + resLen : resLen,
							console.log(resLen, 'resLen2')
							// 判断得到的长度与实际长度相等之后才是实际的结果
							if (getLen == resLen.toUpperCase()) {
								// 数组转换为字符串
								let lastStr = lastConArr.join('')
								console.log(lastStr, 'lastStr')
								if (lastStr.substring(8,12) == 'F020') {
									uni.setStorageSync('RESCODE', lastStr)
									console.log(lastStr, 'F020')
								} else {
									uni.setStorageSync('RESPARAMS', lastStr)
									console.log('!f')
								}
							}
						}
					}
				}
				// 清空内容和收到的数据
				first = '' // 开始部分
				center = '' // 中间拼接部分
				last = '' // 结尾部分
				len = 0 // 包的长度
				
			}
		})
	})
	
}

大家好,我是[张小翼],欢迎关注我的公众号(前端zml),一起学习交流

前端zml.png