UNPKG

@iot9x.com/ipc-utils

Version:

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

902 lines (901 loc) 47.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AD02_BLE = void 0; const protocol_1 = require("../../protocol"); const constant_1 = require("./constant"); const util_1 = require("./util"); /** JX-AD02 BLE蓝牙协议 */ class AD02_BLE { //#region 硬件版本 /** * 读取硬件版本指令 * @returns 可直接下发的蓝牙通信指令 */ static readHardwareVersionCMD() { const lengthHex = util_1.Util.getLengthHex(); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.ReadHardwareVersion); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.ReadHardwareVersion, sumCheckHex); } /** * 解析硬件版本 * @param data 读取硬件版本蓝牙返回数据帧 * @returns 硬件版本(ASCII字符串) */ static resolveHardwareVersion(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.ReadHardwareVersion); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是硬件版本的ASCII编码 return util_1.Util.hexStrToASCII(util_1.Util.uint8ArrayToHexStr(payload)); } //#endregion //#region 软件版本 /** * 读取软件版本指令 * @returns 可直接下发的蓝牙通信指令 */ static readSoftwareVersionCMD() { const lengthHex = util_1.Util.getLengthHex(); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.ReadSoftwareVersion); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.ReadSoftwareVersion, sumCheckHex); } /** * 解析软件版本 * @param data 读取硬件版本蓝牙返回数据帧 * @returns 软件版本(ASCII字符串) */ static resolveSoftwareVersion(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.ReadSoftwareVersion); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是软件版本的ASCII编码 return util_1.Util.hexStrToASCII(util_1.Util.uint8ArrayToHexStr(payload)); } //#endregion //#region 协议版本 /** * 读取协议版本指令 * @returns 可直接下发的蓝牙通信指令 */ static readProtocolVersionCMD() { const lengthHex = util_1.Util.getLengthHex(); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.ReadProtocolVersion); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.ReadProtocolVersion, sumCheckHex); } /** * 解析协议版本 * @param data 读取协议版本蓝牙返回数据帧 * @returns 协议版本(ASCII字符串) */ static resolveProtocolVersion(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.ReadProtocolVersion); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是软件版本的ASCII编码 return util_1.Util.hexStrToASCII(util_1.Util.uint8ArrayToHexStr(payload)); } //#endregion //#region 密码校验 /** * 获取密码校验指令 * @param password 密码(ASCII字符) * @returns 可直接下发的蓝牙通信指令 */ static passwordCheckCMD(password) { if (password.length !== 4) throw new Error('密码长度不正确'); const payloadHex = util_1.Util.asciiToHexStr(password); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.PasswordCheck, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.PasswordCheck, sumCheckHex, payloadHex); } /** * 密码验证蓝牙返回内容解析 * @param data 密码验证蓝牙返回数据帧 * @returns 密码验证结果 */ static resolvePasswordCheck(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.PasswordCheck); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是密码校验结果的ASCII编码 const result = util_1.Util.hexStrToASCII(util_1.Util.uint8ArrayToHexStr(payload)); if (result === 'OK') return true; if (result === 'Er') return false; throw new Error('未知验证结果:' + result); } //#endregion //#region 密码设置 /** * 获取设置密码指令 * @param password 密码(ASCII字符) * @returns 可直接下发的蓝牙通信指令 */ static setPasswordCMD(password) { if (password.length !== 4) throw new Error('密码长度不正确'); const payloadHex = util_1.Util.asciiToHexStr(password); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.PasswordSet, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.PasswordSet, sumCheckHex, payloadHex); } /** * 设置密码蓝牙返回内容解析 * @param data 设置密码蓝牙返回数据帧 * @returns 密码设置结果 */ static resolveSetPassword(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.PasswordSet); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是密码设置结果的ASCII编码 const result = util_1.Util.hexStrToASCII(util_1.Util.uint8ArrayToHexStr(payload)); if (result === 'OK') return true; if (result === 'Er') return false; throw new Error('未知设置结果:' + result); } //#endregion //#region 输入(AI)相关 /** * 获取模拟量输入(AI)类型(量程)指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @returns 可直接下发的蓝牙通信指令 */ static readAITypeCMD(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataType(parseInt(`2${channel}00`, 16), protocol_1.ModbusDataType.U16); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取模拟量输入(AI)类型(量程)蓝牙返回内容解析 * @param data 读取AI类型(量程)蓝牙返回数据帧 * @returns AI量程类型,0——电压(0-10V);1——电流(0-24mA) */ static resolveAIType(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI量程的 Modbus PDU 格式数据 return protocol_1.ModbusPDU.resolveHoldResByDataType(util_1.Util.uint8ArrayToHexStr(payload), protocol_1.ModbusDataType.U16); } /** * 获取写入AI量程/类型指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param type AI量程类型,0——电压(0-10V);1——电流(0-24mA) * @returns 可直接下发的蓝牙通信指令 */ static writeAITypeCMD(channel, type) { const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(parseInt(`2${channel}00`, 16), [[type, protocol_1.ModbusDataType.U16]]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 设置AI量程返回内容解析 * @param data 设置AI量程蓝牙返回数据帧 * @param channel AI通道。0——AI1;1——AI2 * @returns 写入结果 */ static resolveWriteAITypeRes(data, channel) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是设置AI量程返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === parseInt(`2${channel}00`, 16) && count === 1; } /** * 获取模拟量输入测量值指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @returns 可直接下发的蓝牙通信指令 */ static readAICMD(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataType(parseInt(`F1${channel}5`, 16), protocol_1.ModbusDataType.U16); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取模拟量输入测量值蓝牙返回内容解析 * @param data 读取AI测量值蓝牙返回数据帧 * @returns AI测量值,电压0~10000,电流0~24000 */ static resolveAI(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI测量值的 Modbus PDU 格式数据 return protocol_1.ModbusPDU.resolveHoldResByDataType(util_1.Util.uint8ArrayToHexStr(payload), protocol_1.ModbusDataType.U16); } /** * 获取模拟量输入运算后的值指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @returns 可直接下发的蓝牙通信指令 */ static readUserAICMD(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataType(parseInt(`F1${channel}6`, 16), protocol_1.ModbusDataType.FLOAT); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取模拟量输入运算值蓝牙返回内容解析 * @param data 读取AI运算值蓝牙返回数据帧 * @returns AI运算值,浮点数 */ static resolveUserAI(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI运算值的 Modbus PDU 格式数据 return protocol_1.ModbusPDU.resolveHoldResByDataType(util_1.Util.uint8ArrayToHexStr(payload), protocol_1.ModbusDataType.FLOAT); } /** * 获取模拟量输入(AI)用户自定义运算指令 * @description 由于双层四则运算的运算符和运算值在寄存器排列上连续,所以这里一次读取。 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @returns 可直接下发的蓝牙通信指令 */ static readAICalculate(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(parseInt(`2${channel}10`, 16), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.I16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.I16, ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取模拟量输入(AI)用户自定义运算返回内容解析 * @param data 读取模拟量输入运算蓝牙返回数据帧 * @returns 模拟量双层四则运算内容 */ static resolveAICalculate(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是双层四则运算的 Modbus PDU 格式数据 const [operator1, value1, operator2, value2] = protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.I16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.I16, ]); return { operator1, value1, operator2, value2 }; } /** * 获取写入用户自定义运算公式配置指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param formula 运算公式内容 * @returns 可直接下发的蓝牙通信指令 */ static writeAICalculateCMD(channel, formula) { if (!Number.isInteger(formula.value1) || !Number.isInteger(formula.value2)) throw new Error('运算数必须为整数'); const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(parseInt(`2${channel}10`, 16), [ [formula.operator1, protocol_1.ModbusDataType.U16], [formula.value1, protocol_1.ModbusDataType.I16], [formula.operator2, protocol_1.ModbusDataType.U16], [formula.value2, protocol_1.ModbusDataType.I16], ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 设置AI运算公式返回内容解析 * @param data 设置AI运算公式蓝牙返回数据帧 * @param channel AI通道。0——AI1;1——AI2 * @returns 写入结果 */ static resolveWriteAICalculateRes(data, channel) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是写入AI运算公式返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === parseInt(`2${channel}10`, 16) && count === 4; } /** * 获取AI校准配置指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param type 通道类型,2——电压;3——电流 * @returns 可直接下发的蓝牙通信指令 */ static readAICalibrateCMD(channel, type) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(parseInt(`2${channel}${type}0`, 16), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取AI校准配置返回内容解析 * @param data 读取AI校准配置蓝牙返回数据帧 * @returns 4个校准点数据的元组类型 */ static resolveAICalibrate(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI校验配置的 Modbus PDU 格式数据 return protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, ]); } /** * 设置AI校准指令 * @deprecated 请使用下面的V2版方法 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param type 通道类型,2——电压;3——电流 * @param valueList 校准值列表 * @returns 可直接下发的蓝牙通信指令 */ static calibrateAICMD(channel, type, valueList) { for (const value of valueList) { if (!Number.isInteger(value)) throw new Error('校准值必须为整数'); } const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(parseInt(`2${channel}${type}0`, 16), valueList.map((value) => [value, protocol_1.ModbusDataType.U16])); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * AI校准返回内容解析 * @deprecated 请使用下面的V2版方法 * @param data AI校准蓝牙返回数据帧 * @param channel AI通道。0——AI1;1——AI2 * @param type 通道类型,2——电压;3——电流 * @returns 校准结果 */ static resolveCalibrateAIRes(data, channel, type) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI校准返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === parseInt(`2${channel}${type}0`, 16) && count === 4; } /** * 设置AI校准指令—V2版 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param type 通道类型,2——电压;3——电流 * @param point 校准点 * @param value 校准值 * @returns 可直接下发的蓝牙通信指令 */ static calibrateAICMD_V2(channel, type, point, value) { if (!Number.isInteger(value)) throw new Error('校准值必须为整数'); const payloadHex = protocol_1.ModbusPDU.writeHoldByDataTypeCMD(parseInt(`2${channel}${type}${point - 1}`, 16), value, protocol_1.ModbusDataType.U16); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * AI校准返回内容解析—V2版 * @param data 下发AI校准指令蓝牙返回数据帧 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param type 通道类型,2——电压;3——电流 * @param point 校准点 * @param value 校准值 * @returns AI校准结果 */ static resolveCalibrateAIRes_V2(data, channel, type, point, value) { if (!Number.isInteger(value)) throw new Error('校准值必须为整数'); util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是下发AI校准指令返回结果的 Modbus PDU 格式数据 try { return protocol_1.ModbusPDU.resolveWriteHoldByDataTypeRes(util_1.Util.uint8ArrayToHexStr(payload), parseInt(`2${channel}${type}${point - 1}`, 16), value, protocol_1.ModbusDataType.U16); } catch (error) { if (error.message === '未知错误码FF') throw new Error('无权限'); // 支持自定义无权限错误 throw error; } } /** * 读取AI自动上报配置指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @returns 可直接下发的蓝牙通信指令 */ static readAIUploadCMD(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(parseInt(`2${channel}40`, 16), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.I16, protocol_1.ModbusDataType.I16, ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取AI上报配置返回内容解析 * @param data 获取AI上报配置蓝牙返回数据帧 * @returns AI上报配置 */ static resolveAIUpload(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI上报的 Modbus PDU 格式数据 const [typeValue, minChangeValue, timerValue, minZoneValue, maxZoneValue] = protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.I16, protocol_1.ModbusDataType.I16, ]); const typeList = []; if ((typeValue & constant_1.AD02_AIUploadType.Change) === constant_1.AD02_AIUploadType.Change) typeList.push(constant_1.AD02_AIUploadType.Change); if ((typeValue & constant_1.AD02_AIUploadType.Timer) === constant_1.AD02_AIUploadType.Timer) typeList.push(constant_1.AD02_AIUploadType.Timer); if ((typeValue & constant_1.AD02_AIUploadType.LessZone) === constant_1.AD02_AIUploadType.LessZone) typeList.push(constant_1.AD02_AIUploadType.LessZone); if ((typeValue & constant_1.AD02_AIUploadType.InZone) === constant_1.AD02_AIUploadType.InZone) typeList.push(constant_1.AD02_AIUploadType.InZone); if ((typeValue & constant_1.AD02_AIUploadType.MoreZone) === constant_1.AD02_AIUploadType.MoreZone) typeList.push(constant_1.AD02_AIUploadType.MoreZone); return { typeList, minChangeValue, timerValue, minZoneValue, maxZoneValue }; } /** * 获取设置AI上报配置指令 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @param typeList 上报类型列表 * @param minChangeValue 变化最小值,UInt16格式 * @param timerValue 定时时间,单位:秒,UInt16格式 * @param minZoneValue 区间下限值,Int16格式 * @param maxZoneValue 区间上限值,Int16格式 * @returns 可直接下发的蓝牙通信指令 */ static setAIUploadCMD(channel, typeList, minChangeValue, timerValue, minZoneValue, maxZoneValue) { if (!Number.isInteger(minChangeValue) || minChangeValue < 0) throw new Error('变化最小值格式不正确'); if (!Number.isInteger(timerValue) || timerValue < 0) throw new Error('定时时间格式不正确'); if (!Number.isInteger(minZoneValue)) throw new Error('区间下限值格式不正确'); if (!Number.isInteger(maxZoneValue)) throw new Error('区间上限值格式不正确'); const typeValue = typeList.reduce((a, b) => a + b, 0); const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(parseInt(`2${channel}40`, 16), [ [typeValue, protocol_1.ModbusDataType.U16], [minChangeValue, protocol_1.ModbusDataType.U16], [timerValue, protocol_1.ModbusDataType.U16], [minZoneValue, protocol_1.ModbusDataType.I16], [maxZoneValue, protocol_1.ModbusDataType.I16], ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 配置AI上报返回内容解析 * @param data 配置AI上报蓝牙返回数据帧 * @param channel 模拟量输入通道。0——AI1;1——AI2 * @returns 上报配置设置结果 */ static resolveAIUploadRes(data, channel) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AI校准返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === parseInt(`2${channel}40`, 16) && count === 5; } //#endregion //#region 输出(AO)相关 /** * 获取模拟量输出(AO)的值指令 * @description 由于两个AO输出的值寄存器排列连续,所以这里**一次读取两个值**。 * @returns 可直接下发的蓝牙通信指令 */ static readAOCMD() { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(0, [protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取模拟量输出(AO)的值返回内容解析 * @param data 读取AO数据蓝牙返回数据帧 * @returns AO值,元组格式,单位为毫伏 */ static resolveAO(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AO值的 Modbus PDU 格式数据 return protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16]); } /** * 获取控制模拟量输出(AO)的指令 * @description 由于两个AO输出的值寄存器排列连续,所以这里**一次写入两个值**。 * @param ao1 AO1的控制值,单位:**毫伏**,合法范围为:`0-10000` * @param ao2 AO2的控制值,单位:**毫伏**,合法范围为:`0-10000` * @returns 可直接下发的蓝牙通信指令 */ static writeAOCMD(ao1, ao2) { if (ao1 < 0 || ao1 > 10000) throw new Error('AO1超范围'); if (ao2 < 0 || ao2 > 10000) throw new Error('AO2超范围'); if (!Number.isInteger(ao1)) throw new Error('AO1非正整数'); if (!Number.isInteger(ao2)) throw new Error('AO2非正整数'); const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(0, [ [ao1, protocol_1.ModbusDataType.U16], [ao2, protocol_1.ModbusDataType.U16], ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 写入控制AO值返回内容解析 * @param data 写入控制AO值蓝牙返回数据帧 * @returns 写入控制结果 */ static resolveWriteAORes(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是写入AO值返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === 0 && count === 2; } /** * 读取AO上电初始值指令 * @param channel 模拟量输出通道。0——AO1;1——AO2 * @returns 可直接下发的蓝牙通信指令 */ static readAOInitCMD(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(parseInt(`3${channel}01`, 16), [protocol_1.ModbusDataType.U16]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 读取AO上电初始值返回内容解析 * @param data 读取AO上电初始值蓝牙返回数据帧 * @returns AO上电初始值,单位:毫伏,UInt16格式 */ static resolveAOInit(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AO上电初始值的 Modbus PDU 格式数据 return protocol_1.ModbusPDU.resolveHoldResByDataType(util_1.Util.uint8ArrayToHexStr(payload), protocol_1.ModbusDataType.U16); } /** * 获取设置AO上电初始值指令 * @param channel AO通道。0——AO1;1——AO2 * @param initValue 上电初始值,单位:毫伏,范围:0-10000 * @returns 可直接下发的蓝牙通信指令 */ static writeAOInitCMD(channel, initValue) { if (initValue < 0 || initValue > 10000) throw new Error('AO初始值超范围'); if (!Number.isInteger(initValue)) throw new Error('AO初始值非正整数'); const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(parseInt(`3${channel}01`, 16), [[initValue, protocol_1.ModbusDataType.U16]]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 设置AO上电初始值返回内容解析 * @param data 写入AO上电初始值值蓝牙返回数据帧 * @param channel AO通道。0——AO1;1——AO2 * @returns 写入控制结果 */ static resolveWriteAOInitRes(data, channel) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是写入AO上电初始值返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === parseInt(`3${channel}01`, 16) && count === 1; } /** * 读取AO周期输出配置指令 * @param channel 模拟量输出通道。0——AO1;1——AO2 * @returns 可直接下发的蓝牙通信指令 */ static readAOOutputCMD(channel) { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(parseInt(`3${channel}10`, 16), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, // 第7段持续时间 ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取AO周期输出配置返回内容解析 * @param data 读取AO周期输出配置蓝牙返回数据帧 * @returns AO周期输出配置 */ static resolveAOOutput(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是AO周期输出配置的 Modbus PDU 格式数据 const [period, voltage1, delay1, voltage2, delay2, voltage3, delay3, voltage4, delay4, voltage5, delay5, voltage6, delay6, voltage7, delay7] = protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, // 第7段持续时间 ]); return { period, voltage1, delay1, voltage2, delay2, voltage3, delay3, voltage4, delay4, voltage5, delay5, voltage6, delay6, voltage7, delay7, }; } /** * 生成AO周期输出配置下发指令 * @param channel 模拟量输出通道。0——AO1;1——AO2 * @param output AO周期输出配置 * @returns 可直接下发的蓝牙通信指令 */ static writeAOOutputCMD(channel, output) { if (!Number.isInteger(output.period)) throw new Error('周期数量必须为整数'); if (output.period < 0 || output.period > 7) throw new Error('周期数量超范围'); if (!Number.isInteger(output.delay1) || output.delay1 < 0 || !Number.isInteger(output.delay2) || output.delay2 < 0 || !Number.isInteger(output.delay3) || output.delay3 < 0 || !Number.isInteger(output.delay4) || output.delay4 < 0 || !Number.isInteger(output.delay5) || output.delay5 < 0 || !Number.isInteger(output.delay6) || output.delay6 < 0 || !Number.isInteger(output.delay7) || output.delay7 < 0) throw new Error('延迟时间必须为非负整数'); if (!Number.isInteger(output.voltage1) || output.voltage1 < 0 || !Number.isInteger(output.voltage2) || output.voltage2 < 0 || !Number.isInteger(output.voltage3) || output.voltage3 < 0 || !Number.isInteger(output.voltage4) || output.voltage4 < 0 || !Number.isInteger(output.voltage5) || output.voltage5 < 0 || !Number.isInteger(output.voltage6) || output.voltage6 < 0 || !Number.isInteger(output.voltage7) || output.voltage7 < 0) throw new Error('输出电压必须为非负整数'); const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(parseInt(`3${channel}10`, 16), [ [output.period, protocol_1.ModbusDataType.U16], [output.voltage1, protocol_1.ModbusDataType.U16], [output.delay1, protocol_1.ModbusDataType.U16], [output.voltage2, protocol_1.ModbusDataType.U16], [output.delay2, protocol_1.ModbusDataType.U16], [output.voltage3, protocol_1.ModbusDataType.U16], [output.delay3, protocol_1.ModbusDataType.U16], [output.voltage4, protocol_1.ModbusDataType.U16], [output.delay4, protocol_1.ModbusDataType.U16], [output.voltage5, protocol_1.ModbusDataType.U16], [output.delay5, protocol_1.ModbusDataType.U16], [output.voltage6, protocol_1.ModbusDataType.U16], [output.delay6, protocol_1.ModbusDataType.U16], [output.voltage7, protocol_1.ModbusDataType.U16], [output.delay7, protocol_1.ModbusDataType.U16], ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 设置AO周期输出配置返回内容解析 * @param data 写入AO周期输出配置蓝牙返回数据帧 * @param channel AO通道。0——AO1;1——AO2 * @returns 写入控制结果 */ static resolveWriteAOOutputRes(data, channel) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是写入AO周期输出配置返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === parseInt(`3${channel}10`, 16) && count === 15; } //#endregion //#region 通信配置 /** * 读取串口参数配置指令 * @returns 可直接下发的蓝牙通信指令 */ static readUartConfigCMD() { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(0x1000, [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, // 停止位 ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取串口参数配置返回内容解析 * @param data 读取串口参数蓝牙返回数据帧 * @returns 串口参数配置 */ static resolveUartConfig(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是串口参数配置的 Modbus PDU 格式数据 const [baudrate, databits, parity, stopbits] = protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, // 停止位 ]); return { baudrate, databits, parity, stopbits }; } /** * 生成串口参数配置下发指令 * @param config 串口参数配置 * @returns 可直接下发的蓝牙通信指令 */ static writeUartConfigCMD(config) { const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(0x1000, [ [config.baudrate, protocol_1.ModbusDataType.U16], [config.databits, protocol_1.ModbusDataType.U16], [config.parity, protocol_1.ModbusDataType.U16], [config.stopbits, protocol_1.ModbusDataType.U16], ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 配置串口参数返回内容解析 * @param data 配置串口参数蓝牙返回数据帧 * @returns 串口参数配置结果 */ static resolveWriteUartConfigRes(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是配置串口参数返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === 0x1000 && count === 4; } /** * 读取Modbus配置指令 * @returns 可直接下发的蓝牙通信指令 */ static readModbusConfigCMD() { const payloadHex = protocol_1.ModbusPDU.readHoldCMDByDataTypeList(0x1020, [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, // 分帧时间,单位:毫秒 ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 获取Modbus参数配置返回内容解析 * @param data 读取Modbus参数蓝牙返回数据帧 * @returns Modbus参数配置 */ static resolveModbusConfig(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是Modbus参数配置的 Modbus PDU 格式数据 const [slaveId, timeout] = protocol_1.ModbusPDU.resolveHoldResByDataTypeList(util_1.Util.uint8ArrayToHexStr(payload), [ protocol_1.ModbusDataType.U16, protocol_1.ModbusDataType.U16, // 分帧时间,单位:毫秒 ]); return { slaveId, timeout }; } /** * 生成Modbus参数配置下发指令 * @param config Modbus参数 * @returns 可直接下发的蓝牙通信指令 */ static writeModbusConfigCMD(config) { if (!Number.isInteger(config.slaveId)) throw new Error('从机地址非整数'); if (config.slaveId < 1 || config.slaveId > 255) throw new Error('从机地址超范围'); if (!Number.isInteger(config.timeout) || config.timeout < 0) throw new Error('分帧时间不是非负整数'); const payloadHex = protocol_1.ModbusPDU.writeMultiHoldByDataTypeListCMD(0x1020, [ [config.slaveId, protocol_1.ModbusDataType.U16], [config.timeout, protocol_1.ModbusDataType.U16], ]); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 配置Modbus参数返回内容解析 * @param data 配置Modbus参数蓝牙返回数据帧 * @returns Modbus参数配置结果 */ static resolveWriteModbusConfigRes(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是配置Modbus参数返回结果的 Modbus PDU 格式数据 const [address, count] = protocol_1.ModbusPDU.resolveWriteMultiHoldRes(util_1.Util.uint8ArrayToHexStr(payload)); return address === 0x1020 && count === 2; } //#endregion //#region 操作命令 /** * 获取重启指令 * @returns 可直接下发的蓝牙通信指令 */ static rebootCMD() { const payloadHex = protocol_1.ModbusPDU.writeHoldByDataTypeCMD(0xffff, constant_1.OperateCMD.Reboot, protocol_1.ModbusDataType.U16); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 下发重启指令返回内容解析 * @param data 下发重启指令蓝牙返回数据帧 * @returns 重启结果 */ static resolveRebootRes(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是下发重启指令返回结果的 Modbus PDU 格式数据 try { return protocol_1.ModbusPDU.resolveWriteHoldByDataTypeRes(util_1.Util.uint8ArrayToHexStr(payload), 0xffff, constant_1.OperateCMD.Reboot, protocol_1.ModbusDataType.U16); } catch (error) { if (error.message === '未知错误码FF') throw new Error('无权限'); // 支持自定义无权限错误 throw error; } } /** * 获取恢复出厂设置并重启指令 * @returns 可直接下发的蓝牙通信指令 */ static recoveryCMD() { const payloadHex = protocol_1.ModbusPDU.writeHoldByDataTypeCMD(0xffff, constant_1.OperateCMD.Recovery, protocol_1.ModbusDataType.U16); const lengthHex = util_1.Util.getLengthHex(payloadHex); const sumCheckHex = util_1.Util.getSumCheckHex(lengthHex, constant_1.BLE_CMD.Modbus, payloadHex); return util_1.Util.getBLE_CMD(lengthHex, constant_1.BLE_CMD.Modbus, sumCheckHex, payloadHex); } /** * 下发恢复出厂设置指令返回内容解析 * @param data 下发恢复出厂设置指令蓝牙返回数据帧 * @returns 恢复出厂设置结果 */ static resolveRecoveryRes(data) { util_1.Util.formatCheck(data, constant_1.BLE_CMD.Modbus); // * 蓝牙数据帧格式校验 const payload = util_1.Util.getPayload(data); // * 获取数据域内容,此部分就是下发恢复出厂设置指令返回结果的 Modbus PDU 格式数据 try { return protocol_1.ModbusPDU.resolveWriteHoldByDataTypeRes(util_1.Util.uint8ArrayToHexStr(payload), 0xffff, constant_1.OperateCMD.Recovery, protocol_1.ModbusDataType.U16); } catch (error) { if (error.message === '未知错误码FF') throw new Error('无权限'); // 支持自定义无权限错误 throw error; } } } exports.AD02_BLE = AD02_BLE;