API介绍
1、ArrayBuffer:用来表示通用的、固定长度的原始二进制数据缓冲区。它不能直接读写,只能通过视图(TypedArray 视图和 DataView 视图)来读写,视图的作用是以指定格式解读二进制数据。
2、TypedArray:一个 TypedArray 对象描述了底层二进制数据缓冲区的类数组视图
3、DataView :DataView 视图是一个可以从二进制 ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序(endianness)问题。
4、getUint8() 方法从 DataView相对于起始位置偏移 n 个字节处开始,获取一个无符号的 8-bit 整数 (一个字节)
5、getUint16() 方法从 DataView 相对于起始位置偏移 n 个字节处开始,获取一个 16-bit 数 (无符号短整型,2 个字节)
6、getUint32() 方法从 DataView 相对于起始位置偏移 n 个字节处开始,获取一个 32-bit 数 (无符号长整型,4 个字节)
7、setInt8() 从 DataView 起始位置以 byte 为计数的指定偏移量 (byteOffset) 处储存一个 8-bit 数 (一个字节)
8、setUint16() 从 DataView 起始位置以 byte 为计数的指定偏移量 (byteOffset) 处储存一个 16-bit 数 (无符号短整型)
9、setUint32() 从 DataView 起始位置以 byte 为计数的指定偏移量 (byteOffset) 处储存一个 32-bit 数 (无符号长整型)
10、Blob :对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
项目使用场景示例
开发小程序蓝牙传输项目中,接收数据和发送数据的处理。
1、10进制转16进制转二进制数据处理
2、解析二进制数据流为16进制/10进制
1、$command_tobuffer, // 将字符转化为buffer
/**
* 命令帧
* @typedef {object} json
* @property {Hex} head
* @property {Hex} end
* @property {Number} length
* @property {Hex} command
* @property {String|Number} code
* @returns ArrayBuffer
*/
function $command_tobuffer({ head = 0x55, end = 0x16, length, command, body, type='default' }) {
const byteOffset = 3; // 帧头 + 帧长度 + 命令
const buffer = new ArrayBuffer(byteOffset + length + 1); // byteOffset - 1 + length + 校验值 + 帧尾
const dataView = new DataView(buffer);
dataView.setUint8(0, head); // 帧头
dataView.setUint8(1, '0x' + length.toString(16)); // 帧长
dataView.setUint8(2, command); // 命令字
// 主体信息
if(type==='default'){
string2HexFromDataView({
dataView,
string: body,
byteOffset
});
} else {
number2HexForDataView({
dataView,
number: body,
byteOffset
});
}
const checkCodeIdx = length + 2;
const sign = checkSum(dataView, 2, checkCodeIdx);
// console.log('sum', sign);
dataView.setUint8(checkCodeIdx, '0x' + sign); // 检验码
dataView.setUint8(checkCodeIdx + 1, end); // 帧尾
return {buffer, checkSum:sign};
}
/**
* 字符串转16进制
* @typedef {object} json
* @property {DataView} dataView
* @property {String} string
* @property {Number} byteOffset
*/
function string2HexFromDataView({ dataView, string, byteOffset = 0 }) {
for (let i = 0; i < string.length; i++) {
const idx = i + byteOffset;
// console.log(string[i].charCodeAt(0).toString(16))
dataView.setUint8(idx, '0x' + string[i].charCodeAt(0).toString(16))
}
}
/**
* 数值(10进制)转16进制buffer 为了容 时间戳
*/
function number2HexForDataView({ dataView, number, byteOffset = 0 }) {
const hex = number.toString(16);
for (let i = 0; i < hex.length; i+=2) {
const idx = i / 2 + byteOffset;
dataView.setUint8(idx, '0x' + hex.substr(i, 2))
}
}
/**
* 检验和
* @param {DataView} dataView
* @param {Number} start
* @param {Number} end
* @returns Hex
*/
function checkSum(dataView, start, end) {
let sum = 0;
for (let i = start; i <= end; i++) {
const view = dataView.getUint8(i);
sum += view;
}
// console.log('ss', sum)
// return (('0x' + sum.toString(16)) & 0xFF).toString(16); // 与运算取8位
const resHex = (('0x' + sum.toString(16)) & 0xFF).toString(16);
return resHex.length === 1? 0+''+ resHex: resHex;
}
一个完整的传输帧包括如:帧头+帧长度+帧命令+帧内容+和校验+帧尾;
例如 dataView.setUint8(0, head) :dataView视图设置0的位置是由16进制标识0x开头的4位字符。以此类推最终拼接成一个完整的ArrayBuffer通过蓝牙传输出去。