package com.hdl.photovoltaic.internet; import android.text.TextUtils; import android.util.Log; import com.hdl.log.utils.PointUtil; import com.hdl.photovoltaic.other.HdlAccountLogic; import com.hdl.sdk.link.common.exception.HDLLinkException; import com.hdl.sdk.link.core.callback.HDLLinkCallBack; import com.hdl.sdk.link.core.callback.ModbusCallBack; import com.hdl.sdk.link.core.connect.HDLModBusConnect; import com.hdl.sdk.link.gateway.HDLLinkLocalGateway; import java.lang.reflect.Type; import java.util.Arrays; /** * 客户端操作逻辑 */ public class TcpClient { private static volatile TcpClient sTcpClient; /** * 获取当前对象 * * @return HdlAccountLogic */ public static synchronized TcpClient getInstance() { if (sTcpClient == null) { synchronized (TcpClient.class) { if (sTcpClient == null) { sTcpClient = new TcpClient(); } } } return sTcpClient; } /** * 发送数据到Link网关 * * @param mac 网关mac * @param isEncrypt 是否加密 * @param topic 请求主题 * @param jObject 负载数据<没有填null> * @param sendPath 发送路径<类名+方法名>class->methodName */ public void sendDataToLinkGateway(String mac, boolean isEncrypt, String topic, Object jObject, String sendPath, HDLLinkCallBack callBack) { HDLLinkLocalGateway.getInstance().sendDataToLinkGateway(mac, isEncrypt, topic, jObject, sendPath, callBack); } /** * 发送数据到Link网关 * * @param mac 网关mac * @param topic 请求主题 * @param jObject 负载数据<没有填null> * @param sendPath 发送路径<类名+方法名>class->methodName */ public void sendDataToLinkGateway(String mac, String topic, Object jObject, String sendPath, HDLLinkCallBack callBack) { HDLLinkLocalGateway.getInstance().sendDataToLinkGateway(mac, topic, jObject, sendPath, callBack); } /** * 发送ModBus数据到网关 * 下发主题底层默认 * * @param mac 网关mac * @param oidAddresses oid里面Addresses地址 * @param functionCode 功能码【3=(读取多个寄存器)),6=(写入单个寄存器),16=(写入多个寄存器)】 * @param registerAddress 寄存器地址 * @param contentData 内容数据(不含寄存器地址)【注意:功能码=3时,填数值;实际读多少byte就填多少,例如填"20"】 */ public void SendModBusDataToLinkGateway(String mac, String oidAddresses, int functionCode, int registerAddress, String contentData, ModbusCallBack modbusCallBack) { String s = ""; switch (functionCode) { case 3: { s = getReadModbusPassData(oidAddresses, registerAddress, functionCode, contentData); } break; case 6: { s = getWriteSingleModbusPassData(oidAddresses, registerAddress, functionCode, contentData); } break; case 16: { s = getWriteMultipleModbusPassData(oidAddresses, registerAddress, functionCode, contentData); } break; } HDLModBusConnect.getInstance().Send(mac, s.getBytes(), modbusCallBack); } /** * 获取读取【modbus协议】拼接透传数据的字符串 * 下发主题:/user/${gw_id}/custom/native/${driver}/down; * 逆变器回复主题:/user/${gw_id}/custom/native/${driver}/down_reply; * Modbus ECU协议:事件ID(2个byte)->协议[固定:0,0](2个byte)->长度(2byte)->标识符[oid的addresses值](4个byte)->功能码(1个byte)->负载数据(N个byte); * 长度(2个byte)=标识符(4个byte)+功能码(1个byte)+负载数据(N个byte); * 负载数据=寄存器地址(2个byte)+寄存器长度(2个byte)+内容长度(1个byte)+内容数据(N个byte)【注意:单个写入寄存器-->去掉<寄存器长度>和<内容长度>】; * 寄存器长度=(内容数据/2); * 例子:new byte[]{00,01,00,00,00,0x09,00,00,00,01,03,00,00,00,01}; * * @param oidAddresses oid里面Addresses的值 * @param functionCode 功能码【3=(读取多个寄存器)),6=(写入单个寄存器),16=(写入多个寄存器)】 * @param registerAddress 寄存器地址 * @param contentData 内容数据(不含寄存器地址) */ public String getReadModbusPassData(String oidAddresses, int functionCode, int registerAddress, String contentData) { String data = ""; try { String eventID = to2ByteHexString(registerAddress);//事件ID(2byte) String agreement = "0000";//协议(2byte) String dataByteLength = "";//长度(N byte) String oidAddresses_1 = oidAddresses;//标识符(4byte) String functionCode_1 = to1ByteHexString(functionCode);//功能码(=1byte) String registerAddress_1 = to2ByteHexString(registerAddress);//寄存器地址(2byte) String registerLength_1 = to2ByteHexString(Integer.getInteger(contentData) / 2);//寄存器长度(2byte) byte[] bytes = (oidAddresses_1 + functionCode_1 + registerAddress_1 + registerLength_1).getBytes(); dataByteLength = to1ByteHexString(bytes.length / 2); data = eventID + agreement + dataByteLength + oidAddresses_1 + functionCode_1 + registerAddress_1 + registerLength_1; return data; } catch (Exception ignored) { return data; } } /** * 获取写入单个【modbus协议】拼接透传数据的字符串 * 下发主题:/user/${gw_id}/custom/native/${driver}/down; * 逆变器回复主题:/user/${gw_id}/custom/native/${driver}/down_reply; * Modbus ECU协议:事件ID(2个byte)->协议[固定:0,0](2个byte)->长度(2byte)->标识符[oid的addresses值](4个byte)->功能码(1个byte)->负载数据(N个byte); * 长度(2个byte)=标识符(4个byte)+功能码(1个byte)+负载数据(N个byte); * 负载数据=寄存器地址(2个byte)+寄存器长度(2个byte)+内容长度(1个byte)+内容数据(N个byte)【注意:单个写入寄存器-->去掉<寄存器长度>和<内容长度>】; * 寄存器长度=(内容数据/2); * 例子:new byte[]{[0, 11, 0, 0, 0, 30, 0, 0, 0, 26, 6, 0, 11, 49, 50, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32]}; * * @param oidAddresses oid里面Addresses的值 * @param functionCode 功能码【3=(读取多个寄存器)),6=(写入单个寄存器),16=(写入多个寄存器)】 * @param registerAddress 寄存器地址 * @param contentData 内容数据(不含寄存器地址) */ public String getWriteSingleModbusPassData(String oidAddresses, int functionCode, int registerAddress, String contentData) { String data = ""; try { String eventID = to2ByteHexString(registerAddress);//事件ID(2byte) String agreement = "0000";//协议(2byte) String dataByteLength = "";//长度(N byte) String oidAddresses_1 = oidAddresses;//标识符(4byte) String functionCode_1 = to1ByteHexString(functionCode);//功能码(=1byte) String registerAddress_1 = to2ByteHexString(registerAddress);//寄存器地址(2byte) String contentData_1 = contentData;//内容数据(N byte) byte[] bytes = (oidAddresses_1 + functionCode_1 + registerAddress_1 + contentData_1).getBytes(); dataByteLength = to1ByteHexString(bytes.length / 2); data = eventID + agreement + dataByteLength + oidAddresses_1 + functionCode_1 + registerAddress_1 + contentData_1; return data; } catch (Exception ignored) { return data; } } /** * 获取写入多个【modbus协议】拼接透传数据的字符串 * 下发主题:/user/${gw_id}/custom/native/${driver}/down; * 逆变器回复主题:/user/${gw_id}/custom/native/${driver}/down_reply; * Modbus ECU协议:事件ID(2个byte)->协议[固定:0,0](2个byte)->长度(2byte)->标识符[oid的addresses值](4个byte)->功能码(1个byte)->负载数据(N个byte); * 长度(2个byte)=标识符(4个byte)+功能码(1个byte)+负载数据(N个byte); * 负载数据=寄存器地址(2个byte)+寄存器长度(2个byte)+内容长度(1个byte)+内容数据(N个byte)【注意:单个写入寄存器-->去掉<寄存器长度>和<内容长度>】; * 寄存器长度=(内容数据/2); * 例子:new byte[]{[0, 11, 0, 0, 0, 30, 0, 0, 0, 26, 16, 0, 11, 0, 10, 20, 49, 50, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32]}; * * @param oidAddresses oid里面Addresses的值 * @param functionCode 功能码【3=(读取多个寄存器)),6=(写入单个寄存器),16=(写入多个寄存器)】 * @param registerAddress 寄存器地址 * @param contentData 内容数据(不含寄存器地址) */ public String getWriteMultipleModbusPassData(String oidAddresses, int functionCode, int registerAddress, String contentData) { String data = ""; try { String eventID = to2ByteHexString(registerAddress);//事件ID(2byte) String agreement = "0000";//协议(2byte) String dataByteLength = "";//长度(N byte) String oidAddresses_1 = oidAddresses;//标识符(4byte) String functionCode_1 = to1ByteHexString(functionCode);//功能码(=1byte) String registerAddress_1 = to2ByteHexString(registerAddress);//寄存器地址(2byte) String registerLength_1 = to2ByteHexString(contentData.length() / 2);//寄存器长度(2byte) String contentLength_1 = to1ByteHexString(contentData.length());//内容长度(1byte) String contentData_1 = contentData;//内容数据(N byte) byte[] bytes = (oidAddresses_1 + functionCode_1 + registerAddress_1 + registerLength_1 + contentLength_1 + contentData_1).getBytes(); dataByteLength = to1ByteHexString(bytes.length / 2); data = eventID + agreement + dataByteLength + oidAddresses_1 + functionCode_1 + registerAddress_1 + registerLength_1 + contentLength_1 + contentData_1; return data; } catch (Exception ignored) { return data; } } /** * 获取十六进制字符串(不够两位前面补0) * * @param value 寄存器地址(十进制) * @return (2byte)十六进制字符串 */ public String to2ByteHexString(int value) { String high = ""; String low = ""; if (value > 255) { high = to1ByteHexString(value / 256); low = to1ByteHexString(value % 256); } else { high = "00"; low = to1ByteHexString(value); } return high + low; } /** * 获取十六进制字符串(不够两位前面补0) * * @param value 十进制 * @return (1byte)十六进制字符串 */ public String to1ByteHexString(int value) { try { String hexString = Integer.toHexString(value); if (hexString.length() == 1) { return "0" + hexString; } return hexString; } catch (Exception e) { return "00"; } } /** * 获取十六进制字符串(不够两位前面补0) * * @param dataBytes 数组 * @return -(n byte)十六进制字符串 */ public String toNByteHexString(byte[] dataBytes) { StringBuilder stringBuilder = new StringBuilder(); for (byte dataByte : dataBytes) { String dataB = Integer.toHexString(dataByte & 0xFF); if (dataB.length() == 1) { dataB = "0" + dataB; } stringBuilder.append(dataB); } return stringBuilder.toString(); } /** * 获取十六进制字符串(不够两位前面补0) * * @param value 寄存器地址(十进制) * @return (2byte)十六进制字符串 */ private String getByteHexString(int value) { String high = ""; String low = ""; if (value > 255) { high = to1ByteHexString(value / 256); low = to1ByteHexString(value % 256); } else { high = "00"; low = to1ByteHexString(value); } return high + low; } }