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);
|
}
|
}
|
}
|