package com.hdl.sdk.link.core.connect; import android.content.Context; import android.net.wifi.WifiManager; import android.text.TextUtils; import com.hdl.link.error.HDLLinkCode; import com.hdl.sdk.link.HDLLinkLocalSdk; import com.hdl.sdk.link.common.config.TopicConstant; import com.hdl.sdk.link.common.event.EventDispatcher; import com.hdl.sdk.link.common.event.EventListener; import com.hdl.sdk.link.common.exception.HDLLinkException; import com.hdl.sdk.link.common.utils.LogUtils; import com.hdl.sdk.link.core.bean.BusProRequest; import com.hdl.sdk.link.core.bean.BusProResponse; import com.hdl.sdk.link.core.bean.LinkRequest; import com.hdl.sdk.link.core.bean.LinkResponse; import com.hdl.sdk.link.core.bean.gateway.GatewayBean; import com.hdl.sdk.link.core.callback.BusProCallBack; import com.hdl.sdk.link.core.config.HDLLinkConfig; import com.hdl.sdk.link.core.protocol.LinkMessageDecoderUdp; import com.hdl.sdk.link.core.utils.BusProUtils; import com.hdl.sdk.link.core.utils.ByteUtils; import com.hdl.sdk.link.enums.NativeType; import com.hdl.sdk.link.gateway.HDLLinkLocalGateway; import com.hdl.sdk.link.socket.client.UdpClient; import com.hdl.sdk.link.socket.codec.MessagePipeLine; import com.hdl.sdk.link.socket.udp.UdpSocketBoot; import com.hdl.sdk.link.socket.udp.UdpSocketOptions; /** * Created by hxb on 2021/12/8. * Bus原生通讯相关接口 */ public class HDLBusProConnect { private static final String TAG="HDLBusProConnect"; private static HDLBusProConnect instance; /** * 内部用,主要是处理处理掉透传主题及link主题后,还原Bus原生数据及主题用 */ private final String busProAllTopic = "/BusPro"; /** * udp默认端口 */ public static int UDP_PORT = 6000; /** * 因为考虑到使用一个端口,要支持接收多网关的数据,所以只允许使用一个 */ private static UdpSocketBoot udpSocketBoot; /** * 返回当前实例,不存在就创建并同时注册监听事件 * * @return */ public static HDLBusProConnect getInstance() { if (null == instance) { instance = new HDLBusProConnect(); instance.initEventListener(); } return instance; } private UdpSocketOptions getUdpOptions() { final UdpSocketOptions options = new UdpSocketOptions(); WifiManager manager = (WifiManager) HDLLinkLocalSdk.getInstance().getContext().getApplicationContext() .getSystemService(Context.WIFI_SERVICE); options.setWifiManager(manager); final MessagePipeLine pipeLine = new MessagePipeLine(); pipeLine.add(new LinkMessageDecoderUdp()); // pipeLine.add(new LinkMessageEncoder()); options.setHandleMessage(pipeLine); return options; } /** * 获取当前udp对象,如果不存在就创建 * * @return 返回当前对象 */ public synchronized UdpSocketBoot getUdpBoot() { if (null == initUdp()) { return null; } return udpSocketBoot; } /** * 初始化udp 监听功能 * * @return 返回当前对象 */ public synchronized UdpSocketBoot initUdp() { try { if (udpSocketBoot == null) { udpSocketBoot = UdpClient.init("0.0.0.0",UDP_PORT, getUdpOptions()); udpSocketBoot.bind(); } } catch (Exception e) { LogUtils.e("初始化网关失败:"+e.getMessage()); return null; } return udpSocketBoot; } /** * 注册监听Zigbee所有原生主题及数据 * * @param eventListener */ public void registerListener(EventListener eventListener) { if(null==eventListener){ return; } EventDispatcher.getInstance().register(busProAllTopic, eventListener); } /** * 移除监听Zigbee原生主题及数据 * * @param eventListener */ public void removeListener(EventListener eventListener) { if(null==eventListener){ return; } EventDispatcher.getInstance().remove(busProAllTopic, eventListener); } /** * 初始化监听事件 */ private void initEventListener() { final EventListener eventListener = new EventListener() { @Override public void onMessage(Object msg) { try { if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; //非buspro数据 if (BusProUtils.isBusProBytes(linkResponse.getByteData()) == false) { return; } byte[] busBytes = linkResponse.getByteData(); //数据包长度 int len=ByteUtils.ByteToInt(busBytes[16]); // 源子网号 byte sourceSubnetId = busBytes[17]; // 源设备号 byte sourceDeviceId = busBytes[18]; //设备类型 byte[]deviceType=new byte[]{busBytes[19], busBytes[20]}; //操作码 byte[] command = new byte[]{busBytes[21], busBytes[22]}; // if (sourceSubnetId == BusProUtils.getSourceSubnetId() && sourceDeviceId == BusProUtils.getSourceDeviceId()) { // return;// 自己发送给自己的,不接收 // } //目标子网号 byte desSubnetId = busBytes[23]; //目标设备号 byte desDeviceId = busBytes[24]; //目标不是广播或者不是发给自己的数据,不接收 // if (!((desSubnetId == BusProUtils.getSourceSubnetId() && desDeviceId == BusProUtils.getSourceDeviceId()) // || (desSubnetId == 0xff && desDeviceId == 0xff))) { // return; // } //附加数据包长度 int extraBytesLenght = len - 11; if (extraBytesLenght < 0) { return; } int index=25; //如果是大包,这块比较少用到。这个命令比较特殊 if(len==0xff) { extraBytesLenght = ByteUtils.ByteToInt(busBytes[25]) * 256 + ByteUtils.ByteToInt(busBytes[26]); index=25+2; } byte []extraBytes = new byte[extraBytesLenght]; // 复制附加数据 System.arraycopy(busBytes, index, extraBytes, 0, extraBytesLenght); //提取操作码,通过操作码获取匹配信息 String matchKey = BusProUtils.getMatchString(sourceSubnetId, sourceDeviceId, command, extraBytes); BusProResponse busProResponse = new BusProResponse(); busProResponse.setTopic(matchKey);//这块比较特殊,主题基本上用不上 busProResponse.setData(busBytes);//原始数据 //解析之后的数据 busProResponse.setIpAddress(String.format("%s.%s.%s.%s",ByteUtils.ByteToInt(busBytes[0]),ByteUtils.ByteToInt(busBytes[1]),ByteUtils.ByteToInt(busBytes[2]),ByteUtils.ByteToInt(busBytes[3]))); busProResponse.setSourceSubnetId(sourceSubnetId); busProResponse.setSourceDeviceId(sourceDeviceId); busProResponse.setDeviceType(deviceType); busProResponse.setCommand(command); busProResponse.setDesSubnetId(desSubnetId); busProResponse.setDesDeviceId(desDeviceId); busProResponse.setExtraBytes(extraBytes); String oid = null; //是否是通过主网关透传主题 if (linkResponse.getTopic().contains("/slaveoid/")) { oid = linkResponse.getTopic().split("/")[8]; } else { oid = linkResponse.getTopic().split("/")[2]; } busProResponse.setOid(oid); for (GatewayBean gatewayBean : HDLLinkLocalGateway.getInstance().getGatewayList()) { if (oid.equals(gatewayBean.getGatewayId()) || oid.equals(gatewayBean.getDevice_mac()) || oid.equals(gatewayBean.getOid())) { //上面的oid可能是网关id或者mac或者是oid,不管是哪个统一使用oid表示方式 busProResponse.setOid(gatewayBean.getOid()); break; } } EventDispatcher.getInstance().post(matchKey, busProResponse); } } catch (Exception e) { LogUtils.e(TAG, "LinkResponse转BusProResponse异常:" + e.getMessage()); } } }; //注册直接通讯的主题,包括直接和主网关通讯或者直接和从网关通讯 registerListener(String.format(TopicConstant.NATIVE_BUSPRO_UP, "+"), eventListener); //从网关透传 registerListener(String.format(TopicConstant.NATIVE_BUSPRO_UP_SLAVE, "+", "+"), eventListener); } public void Send(String gatewayOidOrGatewayId, BusProRequest busProRequest, final BusProCallBack busProCallBack) { Send(gatewayOidOrGatewayId, busProRequest, busProCallBack, busProRequest.getAwaitTime() <= 0 ? 1000L : busProRequest.getAwaitTime(), busProRequest.getMaxRetry() <= 0 ? 4 : busProRequest.getMaxRetry()); } /** * 发送Bus命令 * @param gatewayOidOrGatewayId 设备的网关Id * @param busProRequest 发送的请求数据 * @param busProCallBack 结果回调 * @param awaitTime 每次重发的时间 * @param maxRetry 最多重发多少次 */ public void Send(String gatewayOidOrGatewayId, BusProRequest busProRequest, final BusProCallBack busProCallBack,long awaitTime,int maxRetry) { //如果本地有链接这个网关,则用本地连接 GatewayBean gatewayBean = HDLLinkLocalGateway.getInstance().getGatewayByOidOrGatewayId(gatewayOidOrGatewayId); if (null == gatewayBean) { LogUtils.i("找不到网关,Oid是" + gatewayOidOrGatewayId); if (null != busProCallBack) { busProCallBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_GATEWAY_NOT_EXIST)); } return; } String topic = String.format(TopicConstant.NATIVE_BUSPRO_DOWN, gatewayBean.getDevice_mac()); byte[] busBytes = BusProUtils.getBusBytes(busProRequest);//需发出去的bus数据 LinkRequest request = new LinkRequest(topic, busBytes, HDLLinkConfig.getInstance().isLocalEncrypt()); request.setNativeType(NativeType.BusPro); if ("true".equals(gatewayBean.getMaster())) { request.setCloudTopic(String.format(TopicConstant.NATIVE_BUSPRO_DOWN, HDLLinkConfig.getInstance().getGatewayId())); } else { request.setCloudTopic(String.format(TopicConstant.NATIVE_BUSPRO_DOWN_SLAVE, HDLLinkConfig.getInstance().getGatewayId(), gatewayOidOrGatewayId)); } int command; if(busProRequest.getAckCommand()==null){ command = ByteUtils.ByteToInt(busProRequest.getCommand()) + 1;//回复的操作码是发送的操作码+1 } else { //发送的操作码与回复的不是一对的情况,采用此方式 command = ByteUtils.ByteToInt(busProRequest.getAckCommand()); } String matchKey = BusProUtils.getMatchString(busProRequest.getDesSubnetId(), busProRequest.getDesDeviceId(), ByteUtils.IntToByte(command), busProRequest.getExtraBytes()); request.setReplyTopic(matchKey); new HDLConnectHelper(awaitTime,maxRetry, gatewayBean.getIp_address(), 8586, request, new HDLConnectHelper.HdlSocketListener() { @Override public void onSucceed(Object msg) { if (msg instanceof BusProResponse) { if (null != busProCallBack) { busProCallBack.onSuccess((BusProResponse) msg); } } } @Override public void onFailure(HDLLinkCode hdlLinkCode) { if (null != busProCallBack) { busProCallBack.onError(HDLLinkException.getErrorWithCode(hdlLinkCode)); } } }, true).send(); } /** * 注册监听 */ void registerListener(String responseTopic, EventListener eventListener) { if (!TextUtils.isEmpty(responseTopic)) { EventDispatcher.getInstance().register(responseTopic, eventListener); } } /** * 移除监听 */ void removeListener(String responseTopic, EventListener eventListener) { if (!TextUtils.isEmpty(responseTopic)) { EventDispatcher.getInstance().remove(responseTopic, eventListener); } } }