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