@iot9x.com/ipc-utils
Version:
九星云、九星小程序、九星配置工具所共用的库方法
155 lines (154 loc) • 6.76 kB
JavaScript
;
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;