fastbee/yack-mini/miniprogram/utils/hex.js
2026-09-27 14:46:05 +08:00

155 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 十六进制工具函数
*/
/**
* ArrayBuffer 转十六进制字符串
* @param {ArrayBuffer} buffer - ArrayBuffer 数据
* @returns {string} 十六进制字符串(大写)
*/
function arrayBufferToHex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function (byte) {
return ('0' + byte.toString(16)).slice(-2);
}
);
return hexArr.join('').toUpperCase();
}
/**
* 十六进制字符串转 ArrayBuffer
* @param {string} hex - 十六进制字符串
* @returns {ArrayBuffer} ArrayBuffer 数据
*/
function hexToArrayBuffer(hex) {
// 去除空格和换行
hex = hex.replace(/\s+/g, '');
// 确保长度为偶数
if (hex.length % 2 !== 0) {
hex = '0' + hex;
}
const length = hex.length / 2;
const buffer = new ArrayBuffer(length);
const dataView = new DataView(buffer);
for (let i = 0; i < length; i++) {
const byte = parseInt(hex.substr(i * 2, 2), 16);
dataView.setUint8(i, byte);
}
return buffer;
}
/**
* 十六进制字符串转字节数组
* @param {string} hex - 十六进制字符串
* @returns {Array<number>} 字节数组
*/
function hexToBytes(hex) {
hex = hex.replace(/\s+/g, '');
const bytes = [];
for (let i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
/**
* 字节数组转十六进制字符串
* @param {Array<number>} bytes - 字节数组
* @returns {string} 十六进制字符串
*/
function bytesToHex(bytes) {
return bytes
.map(b => ('0' + b.toString(16)).slice(-2))
.join('')
.toUpperCase();
}
/**
* 十六进制字符串转 ASCII 显示文本(收发区「Hex」取消勾选时的视图)
* 不可打印字节显示为「·」
* @param {string} hex - 十六进制字符串
* @returns {string} ASCII 文本
*/
function asciiOfHex(hex) {
if (!hex) return '';
const bytes = hexToBytes(hex);
let out = '';
for (let i = 0; i < bytes.length; i++) {
const b = bytes[i];
out += (b >= 0x20 && b <= 0x7e) ? String.fromCharCode(b) : '·';
}
return out;
}
/**
* ASCII 文本转十六进制字符串(收发区「Hex」取消勾选时按文本发送)
* 含超出 Latin-1 的字符(如中文)时返回 null
* @param {string} text - ASCII 文本
* @returns {string|null} 十六进制字符串;非法字符返回 null
*/
function asciiTextToHex(text) {
if (!text) return '';
const bytes = [];
for (let i = 0; i < text.length; i++) {
const code = text.charCodeAt(i);
if (code > 0xFF) return null;
bytes.push(code);
}
return bytesToHex(bytes);
}
/**
* CRC16 校验(Modbus RTU)
* @param {string} hex - 十六进制字符串(不含 CRC)
* @returns {string} CRC16 校验码(4位十六进制)
*/
function crc16(hex) {
const bytes = hexToBytes(hex);
let crc = 0xFFFF;
for (let i = 0; i < bytes.length; i++) {
crc ^= bytes[i];
for (let j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
// 返回低位在前,高位在后
const low = (crc & 0xFF).toString(16).padStart(2, '0');
const high = ((crc >> 8) & 0xFF).toString(16).padStart(2, '0');
return (low + high).toUpperCase();
}
/**
* 验证 CRC16 校验码
* @param {string} hex - 完整的十六进制字符串(含 CRC)
* @returns {boolean} 校验是否通过
*/
function verifyCrc16(hex) {
if (hex.length < 4) return false;
const data = hex.slice(0, -4);
const crc = hex.slice(-4);
return crc16(data) === crc;
}
module.exports = {
arrayBufferToHex,
hexToArrayBuffer,
hexToBytes,
bytesToHex,
asciiOfHex,
asciiTextToHex,
crc16,
verifyCrc16,
};