UNPKG

@iot9x.com/ipc-utils

Version:

九星云、九星小程序、九星配置工具所共用的库方法

155 lines (154 loc) 6.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Util = void 0; const constant_1 = require("./constant"); class Util { /** * 获取唤醒前缀十六进制字符串 * @param wakeUpCode 唤醒码 * @param wakeUpLength 唤醒长度 * @returns 唤醒前缀十六进制字符串 */ static getWakeUpHex(wakeUpCode, wakeUpLength) { if (!wakeUpCode || !wakeUpCode.length || !wakeUpLength) return ''; return wakeUpCode.repeat(wakeUpLength); } /** * 生成校验码 * @param hexStr 校验运算的十六进制字符串 * @returns 校验码 */ static getCS(hexStr) { const sum = hexStr .match(/\w/g) // * 去除非十六进制字符,主要是空格、下划线这样的分隔符 .join('') .match(/\w{2}/g) .reduce((sum, byteHex) => sum + parseInt(byteHex, 16), 0); return (sum % 256).toString(16).padStart(2, '0'); } /** * 将十六进制字符串格式转换成Uint8Array格式 * @param hexStr 十六进制字符串 * @returns Uint8Array格式内容 */ static hexToUint8Array(hexStr) { return new Uint8Array(hexStr .match(/\w/g) .join('') .match(/\w{2}/g) .map((byteHex) => parseInt(byteHex, 16))); } /** * 将Uint8Array数据转换成十六进制字符串 * @param data Uint8Array数据 * @param separator 十六进制分隔符 * @returns 转换后的十六进制字符串 */ static uint8ArrayToHexStr(data, options) { const buf = []; for (const byte of data) { const hex = (options === null || options === void 0 ? void 0 : options.upperCase) ? byte.toString(16).toUpperCase().padStart(2, '0') : byte.toString(16).padStart(2, '0'); buf.push(hex); } return buf.join((options === null || options === void 0 ? void 0 : options.separator) || ''); } /** * BCD解码 * @param bcdStr 原始BCD字符串,小端模式 * @param format BCD编码格式 * @returns 解码信息 */ static bcdDecode(bcdStr, format) { if (!bcdStr || !bcdStr.length) throw new Error('BCD码不可为空'); if (bcdStr.length % 2) throw new Error('BCD码长度不合法'); if (/^[X.]+$/g.test(format) && bcdStr.length !== format.replaceAll('.', '').length) throw new Error('BCD码与format格式不相符'); bcdStr = bcdStr.match(/\w{2}/g).reverse().join(''); // BCD码反转 // ! 1. format中只有X和.表示数字。 // ! 2. format最后一位是H,表示HEX。 // ! 3. 剩下为string格式。 // ! 这里没有考虑DI的解析,不要用这个方法解析DI if (/^[X.]+$/g.test(format)) { const bcdCharList = bcdStr.split(''); const numberStr = format.split('').reduce((sum, char) => (char === 'X' ? sum + bcdCharList.shift() : sum + char), ''); return Number(numberStr); } else if (format.charAt(format.length - 1) === 'H') { return parseInt(bcdStr, 16); } else { return bcdStr; } } /** * 从站返回数据解包 * @param data 从站返回的原始数据包 * @param wakeUpCode 唤醒码 * @param controlCode 下发指令的控制码 * @returns 解包结果 */ static unpacking(data, wakeUpCode, controlCode) { if (wakeUpCode && wakeUpCode.length) while (data[0] === parseInt(wakeUpCode, 16)) data = data.slice(1); // * 删除数据帧前面的唤醒码 if (data.length < 13) throw new Error('数据帧长度过短'); // * 删除唤醒码后,如果不考虑数据域,那么数据帧最少应该剩下13字节。 if (data[data.length - 1] !== parseInt(constant_1.FRAME_SUFFIX, 16)) throw new Error('帧结束符不正确'); data = data.slice(0, data.length - 1); // * 删除帧结束符 const csHex = Util.getCS(Util.uint8ArrayToHexStr(data.slice(0, data.length - 1))); if (data[data.length - 1] !== parseInt(csHex, 16)) throw new Error('CS校验错误'); data = data.slice(0, data.length - 1); // * 删除CS校验 if (data[0] !== parseInt(constant_1.FRAME_PREFIX, 16)) throw new Error('帧起始符不正确'); data = data.slice(1); // * 删除帧起始符 const meterType = data[0]; // * 仪表类型 const address = Util.uint8ArrayToHexStr(data.slice(1, 8).reverse()).replace(/\b(0+)/gi, ''); const controlCodeRes = data[8]; if (controlCodeRes === controlCode + 0x80) { // 正常应答 const dataLength = data[9]; // 数据长度 if (dataLength !== data.slice(10).length) throw new Error('数据长度校验错误'); const dataIdentifier = parseInt(Util.uint8ArrayToHexStr(data.slice(10, 12)), 16); // 数据标识 const dataPayload = data.slice(12); // 数据内容 return { meterType, address, dataLength, dataIdentifier, dataPayload }; } else if (controlCodeRes === controlCode + 0xc0) { // 异常应答 const dataLength = data[9]; // 数据长度 if (dataLength !== 0x03) throw new Error('异常应答数据长度不为3'); const statusValue = Util.uint8ArrayToHexStr(data.slice(10, 12), { upperCase: true }); const status = Util.resolveStatus(data[10]); throw { address, controlCode: controlCodeRes, status, statusValue }; // ! 异常返回通过错误的方式进行处理 } else { throw new Error(`无法判断返回控制码0x${controlCodeRes.toString(16).toUpperCase().padStart(2, '0')},请求控制码为0x${controlCode .toString(16) .toUpperCase() .padStart(2, '0')}`); } } /** * 解析状态内容 * @param statusCode 状态的第一个字节值 * @returns 2004版状态格式 */ static resolveStatus(statusCode) { return { valve: parseInt(statusCode.toString(2).slice(-2), 2), voltage: (statusCode & 4) === 4 ? constant_1.CJT188VoltageStatus.UnderVoltage : constant_1.CJT188VoltageStatus.Normal, D3: (statusCode & 8) === 8 ? 1 : 0, D4: (statusCode & 16) === 16 ? 1 : 0, D5: (statusCode & 32) === 32 ? 1 : 0, D6: (statusCode & 64) === 64 ? 1 : 0, D7: (statusCode & 128) === 128 ? 1 : 0, }; } } exports.Util = Util;