UNPKG

@iot9x.com/ipc-utils

Version:

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

208 lines (207 loc) 9.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Util = void 0; const constant_1 = require("./constant"); const crc_1 = require("crc"); const hex_1 = require("./hex"); class Util { /** * 获取CRC校验结果 * @param cmdHex 十六进制命令 * @param crcOrder CRC顺序 * @returns CRC校验结果 */ static getCRC(cmdHex, crcOrder) { const data = new Int8Array(cmdHex .replaceAll(' ', '') .match(/\w{2}/g) .map((item) => parseInt(item, 16))); // 默认为小写,大端模式,例如:0aac const crcHLHex = (0, crc_1.crc16modbus)(data).toString(16).padStart(4, '0'); return crcOrder === constant_1.CRCOrder.HL ? crcHLHex : crcHLHex.match(/\w{2}/g).reverse().join(''); } /** * 生成LRC校验码 * @param hexStr 校验运算的十六进制字符串 * @returns LRC校验码 */ static getLRC(hexStr) { const sum = hexStr .match(/\w/g) // * 去除非十六进制字符,主要是空格、下划线这样的分隔符 .join('') .match(/\w{2}/g) .reduce((sum, byteHex) => sum + parseInt(byteHex, 16), 0); const result = (~sum + 1) & 0xff; return result.toString(16).padStart(2, '0'); } /** * 十六进制字符串分隔符处理 * @param hexStr 十六进制字符串 * @param separator 分隔符 * @param oldSeparator 原始(旧)分隔符 * @returns 处理结果 */ static hexSeparator(hexStr, separator, oldSeparator) { return hexStr .replaceAll(oldSeparator !== null && oldSeparator !== void 0 ? oldSeparator : ' ', '') .match(/\w{2}/g) .join(separator); } /** * 根据数据类型获取寄存器数量 * @param dataType 数据类型 * @returns 寄存器数量 */ static getRegisterCountByDataType(dataType) { // * 字符串类型处理 if (dataType > 20 && dataType <= 40) return dataType - 20; // * 预置类型处理 const map = [0, 1, 1, 2, 2, 4, 4, 2, 4]; return map[dataType]; } /** * 根据数据类型解析数据值 * @description 仅限保持寄存器和输入寄存器值解析使用 * @param hexStr 十六进制字符串值 * @param dataType 数据类型 * @param i16Encode 16位整型编码(有符号+无符号) * @param i32Encode 32位整型编码(有符号+无符号) * @param f32Encode 32位浮点型编码(FLOAT) * @param i64Encode 64位整型编码(有符号+无符号) * @param f64Encode 64位浮点型编码(Double) * @returns 解析值 */ static getValueByDataType(hexStr, dataType, i16Encode = constant_1.I16Encode.AB, i32Encode = constant_1.I32Encode.ABCD, f32Encode = constant_1.F32Encode.ABCD, i64Encode = constant_1.I64Encode.ABCDEFGH, f64Encode = constant_1.F64Encode.ABCDEFGH) { // * 字符串类型处理 if (dataType > 20 && dataType <= 40) { let result = ''; for (const byte of hexStr.match(/\w{2}/g)) { result += String.fromCharCode(parseInt(byte, 16)); } return result; } switch (dataType) { case constant_1.ModbusDataType.Coil: // ! 无此状态,不应该走到这里 return 0; case constant_1.ModbusDataType.I16: // * 16位有符号整数 return hex_1.Hex.toInt16(hexStr, i16Encode); case constant_1.ModbusDataType.U16: // * 16位无符号整数 return hex_1.Hex.toUInt16(hexStr, i16Encode); case constant_1.ModbusDataType.I32: // * 32位有符号整数 return hex_1.Hex.toInt32(hexStr, i32Encode); case constant_1.ModbusDataType.U32: // * 32位无符号整数 return hex_1.Hex.toUInt32(hexStr, i32Encode); case constant_1.ModbusDataType.I64: // * 64位有符号整数 return hex_1.Hex.toInt64(hexStr, i64Encode); case constant_1.ModbusDataType.U64: // * 64位无符号整数 return hex_1.Hex.toUInt64(hexStr, i64Encode); case constant_1.ModbusDataType.FLOAT: // * Float类型 return hex_1.Hex.toFloat(hexStr, f32Encode); case constant_1.ModbusDataType.DOUBLE: // * Double类型 return hex_1.Hex.toDouble(hexStr, f64Encode); default: throw new Error('未知数据类型' + dataType); } } /** * 将数值编码成十六进制字符串 * @description 注意返回的字符串是**小写格式**!!! * @param data 数据值 * @param dataType 数据类型 * @param i16Encode 16位整型编码(有符号+无符号) * @param i32Encode 32位整型编码(有符号+无符号) * @param f32Encode 32位浮点型编码(FLOAT) * @param i64Encode 64位整型编码(有符号+无符号) * @param f64Encode 64位浮点型编码(Double) * @returns 十六进制字符串,**小写格式**!!! */ static dataEncode(data, dataType, i16Encode = constant_1.I16Encode.AB, i32Encode = constant_1.I32Encode.ABCD, f32Encode = constant_1.F32Encode.ABCD, i64Encode = constant_1.I64Encode.ABCDEFGH, f64Encode = constant_1.F64Encode.ABCDEFGH) { // * 字符串类型处理 if (dataType > 20 && dataType <= 40) { if (typeof data !== 'string') throw new Error('数据值和数据类型格式不匹配'); return data .split('') .map((char) => char.charCodeAt(0).toString(16).padStart(2, '0')) .join(''); } switch (dataType) { case constant_1.ModbusDataType.Coil: // ! 无此状态,不应该走到这里 return ''; case constant_1.ModbusDataType.I16: // * 16位有符号整数 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromInt16(data, i16Encode); case constant_1.ModbusDataType.U16: // * 16位无符号整数 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromUInt16(data, i16Encode); case constant_1.ModbusDataType.I32: // * 32位有符号整数 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromInt32(data, i32Encode); case constant_1.ModbusDataType.U32: // * 32位无符号整数 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromUInt32(data, i32Encode); case constant_1.ModbusDataType.I64: // * 64位有符号整数 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromInt64(data, i64Encode); case constant_1.ModbusDataType.U64: // * 64位无符号整数 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromUInt64(data, i64Encode); case constant_1.ModbusDataType.FLOAT: // * 32位浮点型 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromFloat(data, f32Encode); case constant_1.ModbusDataType.DOUBLE: // * 64位浮点型 if (typeof data !== 'number') throw new Error('数据值和数据类型格式不匹配'); return hex_1.Hex.fromDouble(data, f64Encode); default: throw new Error('未知数据类型' + dataType); } } /** * Modbus PDU数据转成Modbus ASCII数据 * @param pduHex Modbus PDU数据(十六进制字符串格式) * @param slaveId 从机地址 * @param disableLinefeed 取消结尾的回车换行符(\r\n) * @returns Modbus ASCII格式数据 */ static pdu2ascii(pduHex, slaveId, disableLinefeed = false) { const hexStr = slaveId.toString(16).padStart(2, '0') + pduHex; return ':' + hexStr + Util.getLRC(hexStr) + (disableLinefeed ? '' : '\r\n'); } /** * 检查返回错误码和错误信息 * @param functionalCode 操作功能码 * @param resCodeHex 返回功能码 * @param errorCodeHex 错误码 * @returns 错误信息 */ static checkResCode(functionalCode, resCodeHex, errorCodeHex) { if (parseInt(resCodeHex, 16) - parseInt(functionalCode, 16) !== 0x80) return; const errorMap = { ['01']: '非法功能', ['02']: '非法数据地址', ['03']: '非法数据值', ['04']: '从站设备故障', ['05']: '确认', ['06']: '未知错误码06', ['07']: '从属设备忙', ['08']: '存储奇偶性差错', ['09']: '未知错误码09', ['0A']: '不可用网关路径', ['0B']: '网关目标设备响应失败', }; const errorKey = errorCodeHex.toUpperCase(); const errorReason = errorMap[errorKey]; return errorReason ? errorReason : '未知错误码' + errorKey; } } exports.Util = Util;