/** * 十六进制工具函数 */ /** * 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} 字节数组 */ 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} 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, };