package com.hdl.sdk.ttl.HDLDeviceManger.Core; //import android.serialport.api.SerialPort; import android.serialport.SerialPort; import android.util.Log; import com.hdl.sdk.ttl.Config.Configuration; import com.hdl.sdk.ttl.HDLDeviceManger.Bean.UdpDataBean; import com.hdl.sdk.ttl.HDLDeviceManger.HDLListener.IMcuOtaListener; import com.hdl.sdk.ttl.Utils.HDLUtlis.SerialPortSendAndReceiveUtil; import com.hdl.sdk.ttl.Utils.LogUtils.HDLLog; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.List; /** * Created by JLChen on 2019/6/26 * 串口管理类 */ public class HDLSerialPortCore { //串口设备路径名 private static String mPathname = "/dev/ttyS1"; //波特率 private static int mBaudrate = 115200; // public static SerialPortFinder mSerialPortFinder = new SerialPortFinder(); public static SerialPort mSerialPort = null; public static InputStream mInputStream = null; public static OutputStream mOutputStream = null; // private static HDLReadDatasThread mHDLReadDatasThread = new HDLReadDatasThread(); // private static HDLRead485DatasThread mHDLRead485DatasThread = new HDLRead485DatasThread(); private static HDLReadMCUDatasThread mHDLReadMCUDatasThread = new HDLReadMCUDatasThread(); private static HDLSendDatasThread mHDLSendDatasThread = new HDLSendDatasThread(); public static List mSendDatasList = new ArrayList();//发送数据队列 private static List mReceiveDatasList = new ArrayList();//接收数据队列 // private static List mReceive485DatasList = new ArrayList();//485接收数据队列 public static Boolean isModule = false; //判断是否带模组 public static IMcuOtaListener mIMcuOtaListener; public static byte[] upgradeFileDatas; //升级文件数据 /*** 串口是否打开成功*/ private static boolean bOpenSuccess = false; // private static boolean b485DatascChangeStop = false; public static SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException { if (mSerialPort == null) { mSerialPort = new SerialPort(new File(mPathname), mBaudrate); mInputStream = mSerialPort.getInputStream();//调用对象SerialPort方法,获取串口中"读和写"的数据流 mOutputStream = mSerialPort.getOutputStream(); bOpenSuccess = true; } return mSerialPort; } /** * 初始化串口 */ public static void initHDLSerialPort(String mmPathname, int mmBaudrate) { openSerialPort(mmPathname, mmBaudrate); } /** * 判断串口是否打开 */ public static Boolean getIsSerialPortOpen() { return bOpenSuccess; } /** * 打开串口,接收数据 * 通过串口,接收单片机发送来的数据 */ public static Boolean openSerialPort(String mmPathname, int mmBaudrate) { if (mSerialPort != null) { HDLLog.I("HDLSDK 串口 已启动"); } else { HDLLog.I("HDLSDK 串口 init"); try { mPathname = mmPathname; mBaudrate = mmBaudrate; mSerialPort = new SerialPort(new File(mPathname), mBaudrate); HDLLog.I("HDLSDK 串口启动成功"); //调用对象SerialPort方法,获取串口中"读和写"的数据流 mInputStream = mSerialPort.getInputStream(); mOutputStream = mSerialPort.getOutputStream(); bOpenSuccess = true; if (HDLSerialPortCore.getIsModule()) {//带模组,走标准串口 startHDLThread(); } else {//不带模组,走透传 SerialPortSendAndReceiveUtil.getInstance().start(); } } catch (IOException e) { e.printStackTrace(); bOpenSuccess = false; HDLLog.I("HDLSDK 串口启动失败 IOException"); } catch (InvalidParameterException e) { e.printStackTrace(); bOpenSuccess = false; HDLLog.I("HDLSDK 串口启动失败 InvalidParameterException"); } catch (SecurityException e) { e.printStackTrace(); bOpenSuccess = false; HDLLog.I("HDLSDK 串口启动失败 SecurityException"); } } return bOpenSuccess; } /** * 关闭串口 * 关闭串口中的输入输出流 */ public static void closeSerialPort() { HDLLog.I("关闭串口"); try { mSendDatasList.clear();//清空发送队列 mReceiveDatasList.clear();//清空接收队列 bOpenSuccess = false; // HDLCommand.cancelSearching(); // if (mHDLRead485DatasThread != null) mHDLRead485DatasThread.interrupt(); if (mHDLReadMCUDatasThread != null) mHDLReadMCUDatasThread.interrupt(); if (mHDLSendDatasThread != null) mHDLSendDatasThread.interrupt(); if (mInputStream != null) { mInputStream.close(); } if (mOutputStream != null) { mOutputStream.close(); } if (mSerialPort != null) { mSerialPort.close(); mSerialPort = null; } } catch (IOException e) { e.printStackTrace(); } } /** * 启动串口 发送和接收线程 */ private static void startHDLThread() { mHDLReadMCUDatasThread = new HDLReadMCUDatasThread(); mHDLSendDatasThread = new HDLSendDatasThread(); mHDLReadMCUDatasThread.start(); mHDLSendDatasThread.start(); } /** * 串口接收线程 * 对接HDL协议 * 引导头 控制域 数据长度 数据 校验码 * 0xA8 * * @author 2019年07月12日 */ private static class HDLReadMCUDatasThread extends Thread { @Override public void run() { super.run(); HDLLog.I("接收线程 开启"); while (bOpenSuccess) { int size = 0; try { Thread.sleep(1);//2019-07 降低CPU占用率 if (mInputStream == null) return; byte[] buffer = new byte[64]; size = mInputStream.read(buffer); // HDLLog.I("mReceiveDatasList: " + HDLStringUtils.ByteArrToHex(buffer, 0, buffer.length) ); for (int i = 0; i < size; i++) { mReceiveDatasList.add(buffer[i]); } while (0 < mReceiveDatasList.size()) { // HDLLog.I("arraylist.size():" + mReceiveDatasList.size()); if (mReceiveDatasList.size() < 3) break;//2019-07-02 if (mReceiveDatasList.size() > 3000) { //数据缓存太多错误情况下 清空一次 mReceiveDatasList.clear(); break;//2019-07-24 } int len = -1; int startIndex = 0; for (startIndex = 0; startIndex < mReceiveDatasList.size(); startIndex++) { if ((mReceiveDatasList.get(startIndex) & 0xFF) == 0xAA && (mReceiveDatasList.get(startIndex + 1) & 0xFF) == 0xAA) { len = (mReceiveDatasList.get(startIndex + 2) & 0xFF) + 2;//发现len会出现负数增加 & 0xFF 运算 break; } } if (len == -1 || mReceiveDatasList.size() < len) break; // HDLLog.I("startIndex:" + startIndex + " LEN:" + len); for (int i = 0; i < startIndex; i++) { if (mReceiveDatasList.size() < 1) break;//2019-07-02 mReceiveDatasList.remove(0); } byte[] tempBytes = new byte[len]; for (int i = 0; i < tempBytes.length; i++) { if (mReceiveDatasList.size() < 1) break;//2019-07-02 tempBytes[i] = mReceiveDatasList.get(0); mReceiveDatasList.remove(0); } HandleHDLdata(tempBytes); } } catch (Exception e) { e.printStackTrace(); HDLLog.I("error:" + e.getMessage()); } } HDLLog.I("接收线程 关闭"); } } /** * 串口发送线程 */ private static class HDLSendDatasThread extends Thread { @Override public void run() { super.run(); HDLLog.I("发送线程 开启"); while (bOpenSuccess) { try { Thread.sleep(100); } catch (Exception e) { e.getMessage(); } for (int i = 0; i < mSendDatasList.size(); i++) { try { Thread.sleep(50); } catch (Exception e) { } try { byte[] sendBytes = mSendDatasList.get(i); try { mOutputStream.flush(); mOutputStream.write(sendBytes); // HDLLog.I( // "sendBytes:" + HDLStringUtils.ByteArrToHex(sendBytes, 0, sendBytes.length)); } catch (Exception e) { e.printStackTrace(); } mSendDatasList.remove(i); i--; } catch (Exception ex) { ex.getMessage(); } } } HDLLog.I("发送线程 关闭"); } } public static Boolean getIsModule() { return isModule; } public static void setIsModule(Boolean isModule) { HDLSerialPortCore.isModule = isModule; } // /** // * 发送MUC串口协议数据包 // * @param mcuDataList // * @param bPassThrough 是否为透传 // */ // public static void sendMCUData(final MCUCrc mcuDataList, Boolean bPassThrough) { // if(HDLSerialPortCore.bPassThrough != bPassThrough ){ // HDLSerialPortCore.bPassThrough = bPassThrough; // } // //打印接受数据 // HDLLog.I("HHHHHsendMCUData: "+ HDLStringUtils.ByteArrToHex(mcuDataList.getMCUSendBytes(),0, mcuDataList.getMCUSendBytes().length)); // if (!bOpenSuccess) return; // mSendDatasList.add(mcuDataList.getMCUSendBytes()); // } /** * 发送MUC串口协议数据包 * * @param mcuDataList */ public static void sendMCUData(final MCUCrc mcuDataList) { //打印接受数据 // HDLLog.I("HHHHHsendMCUData: "+ HDLStringUtils.ByteArrToHex(mcuDataList.getMCUSendBytes(),0, mcuDataList.getMCUSendBytes().length)); if (!bOpenSuccess) return; mSendDatasList.add(mcuDataList.getMCUSendBytes()); } /** * 发送数据包 * 点对点或广播 * * @param sendDatas */ public static void sendData(final Crc sendDatas) { if (!bOpenSuccess) return; mSendDatasList.add(sendDatas.GetSendBytes()); } /** * 发送组播 * * @param sendDatas */ public static void sendMulticastData(final Crc sendDatas) { if (!bOpenSuccess) return; mSendDatasList.add(sendDatas.GetSendBytes()); } /** * 判断是否为HDL AA AA 开头数据 * * @param bytes * @return */ private static boolean isHDLDataWithHead(byte[] bytes) { boolean isWant = true; if ((bytes[0] & 0xFF) != 0xAA) { isWant = false; } if ((bytes[1] & 0xFF) != 0xAA) { isWant = false; } return isWant; } /** * 处理HDL Data * * @param receiveBytes */ public synchronized static void HandleHDLdata(byte[] receiveBytes) { if (receiveBytes.length < 14) { return; } //2019-8-21 校验Crc if (!Crc.checkCRC(receiveBytes)) { // HDLLog.I("checkCRC:检验失败"); return; } //操作码 int command = (receiveBytes[7] & 0xFF) * 256 + (receiveBytes[8] & 0xFF); //数据长度 int addDataLength = (receiveBytes[2] & 0xFF) - 11; //附加数据 byte[] usefulBytes = new byte[addDataLength]; //复制附加数据 System.arraycopy(receiveBytes, 11, usefulBytes, 0, addDataLength); //源子网号 int sourceSubnetID = receiveBytes[3] & 0xFF; //源设备号 int sourceDeviceID = receiveBytes[4] & 0xFF; //目标子网号 int targetSubnetID = receiveBytes[9] & 0xFF; //目标设备号 int targetDeviceID = receiveBytes[10] & 0xFF; //s2019-8-20 增加目标子网号设备号判断 if ((targetSubnetID == 0xFF && targetDeviceID == 0xFF) || (targetSubnetID == Crc.localSubnetID && targetDeviceID == Crc.localDeviceID)) { //参数 UdpDataBean udpDataBean = new UdpDataBean(); udpDataBean.sourceSubnetID = sourceSubnetID; udpDataBean.sourceDeviceID = sourceDeviceID; udpDataBean.desSubnetID = targetSubnetID; udpDataBean.desDeviceID = targetDeviceID; udpDataBean.command = command; udpDataBean.addBytes = usefulBytes; HandleInsideData(udpDataBean); } } /** * 处理内部命令数据 * * @param sendDatas */ public static void HandleInsideData(UdpDataBean sendDatas) { switch (sendDatas.command) { case Configuration.DEVICES_SEARCH_FROM_GATEWAY_BACK_COMMAND: // 先判断搜索模式,家居搜索则只需要判断两个随机数。酒店搜索则需要判断两个随机数和ip地址 if (HandleSearch.curSearchMode == HandleSearch.GET_BUS_DEVICES) { if (sendDatas.addBytes[0] == HandleSearch.random1 && sendDatas.addBytes[1] == HandleSearch.random2) { HDLDeviceManager.handle(sendDatas, sendDatas.command); } } else { if (sendDatas.addBytes[0] == HandleSearch.random1 && sendDatas.addBytes[1] == HandleSearch.random2) { HDLDeviceManager.handle(sendDatas, sendDatas.command); } } break; /***2020-04-01 新增通用开关**/ case Configuration.COMMON_SWITCH_CTRL_BACK_COMMAND: case Configuration.COMMON_SWITCH_STATE_BACK_COMMAND: case Configuration.LIGHT_CTRL_BACK_COMMAND: case Configuration.LIGHT_RGB_CTRL_BACK_COMMAND: case Configuration.CURTAIN_CTRL_BACK_COMMAND: case Configuration.AIR_CTRL_BACK_COMMAND: case Configuration.LOGIC_CTRL_BACK_COMMAND: case Configuration.LOGIC_STATE_BACK_COMMAND: case Configuration.LIGHT_STATE_BACK_COMMAND: case Configuration.LIGHT_RGB_STATE_BACK_COMMAND: case Configuration.SECURITY_ARMING_CTRL_BACK_COMMAND://20190729安防模块 布防设置反馈 case Configuration.SECURITY_STATE_BACK_COMMAND://20190729 读取安防设置反馈 case Configuration.SECURITY_ALARM_CTRL_BACK_COMMAND://20190729 报警设置反馈 case Configuration.CURTAIN_STATE_BACK_COMMAND: case Configuration.CURTAIN_STATE_BROADCAST_BACK_COMMAND://2019-12-16 新增广播状态监听 case Configuration.AIR_STATE_BACK_COMMAND: case Configuration.AIR_HVAC_CTRL_BACK_COMMAND: case Configuration.AIR_HVAC_STATE_BACK_COMMAND: // case Configuration.RCU_ROOM_CAST_COMMAND: // case Configuration.RCU_CURTAIN_CAST_COMMAND: case Configuration.DEVICES_READ_FROM_GATEWAY_BACK_COMMAND://读取备注命令 case Configuration.DEVICES_MODIFY_BACK_COMMAND://修改基本信息回复 case Configuration.MODULE_UPDATE_REMARK_BACK_COMMAND://修改模块备注回复 case Configuration.WARNING_COMMAND: case Configuration.SENSOR_STATE_BACK_COMMAND: case Configuration.SENSOR_BROADCAST_STATE_BACK_COMMAND://2019-11-1 增加 case Configuration.DRY_CONTACT_STATE_BACK_COMMAND: case Configuration.DRY_CONTACT_BROADCAST_STATE_COMMAND://2019-11-5 增加干接点状态回复 // case Configuration.AUDIO_CTRL_READ_COMMAND: case Configuration.AUDIO_CTRL_READ_BACK_COMMAND: // case Configuration.AUDIO_MenuPlay_INSTRUCTION_COMMAND: case Configuration.AUDIO_MenuPlay_INSTRUCTION_BACK_COMMAND: case Configuration.FRESH_AIR_CTRL_BACK_COMMAND://2020-07-20 新增 新风系统 case Configuration.FRESH_AIR_STATE_BACK_COMMAND://2020-07-20 新增 新风系统 case Configuration.FRESH_AIR_JINMAO_CTRL_BACK_COMMAND://2020-07-20 新增 金茂新风 case Configuration.FRESH_AIR_JINMAO_STATE_BACK_COMMAND://2020-07-20 新增 金茂新风 case Configuration.GEOTHERMAL_MODULE_CTRL_BACK_COMMAND://2020-07-20 新增 地热模块 case Configuration.GEOTHERMAL_MODULE_STATE_BACK_COMMAND://2020-07-20 新增 地热模块 case Configuration.DOOR_MACHINE_MODULE_CTRL_FRIST_BACK_COMMAND://2023-08-22 新增 门锁 case Configuration.DOOR_MACHINE_MODULE_CTRL_BACK_COMMAND://2023-08-22 新增 门锁 case Configuration.DOOR_MACHINE_MODULE_STATE_BACK_COMMAND://2023-08-22 新增 门锁 case Configuration.DOOR_MACHINE_BROADCAST_STATE_BACK_COMMAND://2023-08-25 新增门锁状态和报警广播 case Configuration.SCENE_SEARCH_FROM_GATEWAY_BACK_COMMAND: case Configuration.SCENE_READ_FROM_GATEWAY_BACK_COMMAND: HDLDeviceManager.handle(sendDatas, sendDatas.command); break; case Configuration.MANUAL_ADD_DEVICE_COMMAND: //固定随机数181、250 if (sendDatas.addBytes[0] == ((byte) 181) && sendDatas.addBytes[1] == ((byte) 250)) { HDLDeviceManager.handle(sendDatas, sendDatas.command); } break; case Configuration.MANUAL_ADD_REMARK_COMMAND: HDLDeviceManager.handle(sendDatas, sendDatas.command); break; default: break; } } // /** // * 判断是否为HDL数据 // * @param bytes // * @return // */ // private static boolean isHDLData(byte[] bytes) { // // boolean isWant = true; // for (int index = 0; index < bytes.length; index++) { // switch (index) { // case 0: // if (bytes[index] != 0x48) { // isWant = false; // } // break; // case 1: // if (bytes[index] != 0x44) { // isWant = false; // } // break; // case 2: // if (bytes[index] != 0x4C) { // isWant = false; // } // break; // case 3: // if (bytes[index] != 0x4D) { // isWant = false; // } // break; // case 4: // if (bytes[index] != 0x49) { // isWant = false; // } // break; // case 5: // if (bytes[index] != 0x52) { // isWant = false; // } // break; // case 6: // if (bytes[index] != 0x41) { // isWant = false; // } // break; // case 7: // if (bytes[index] != 0x43) { // isWant = false; // } // break; // case 8: // if (bytes[index] != 0x4C) { // isWant = false; // } // break; // case 9: // if (bytes[index] != 0x45) { // isWant = false; // } // break; // // default: // break; // } // } // return isWant; // } // // /** // * 处理HDL Data // * // * @param receiveBytes // */ // private synchronized static void HandleMCUdata(byte[] receiveBytes) { // if (receiveBytes.length < 5) { // return; // } // // //打印接受数据 // HDLLog.I("receiveBytes HandleMCUdata: " + HDLStringUtils.ByteArrToHex(receiveBytes, 0, receiveBytes.length)); // //操作码 // int command = receiveBytes[1] & 0xFF; // //数据长度 // int addDataLength = (receiveBytes[2] & 0xFF) * 256 + (receiveBytes[3] & 0xFF); // //附加数据 // byte[] usefulBytes = new byte[addDataLength]; // //复制附加数据 // System.arraycopy(receiveBytes, 4, usefulBytes, 0, addDataLength); // // //参数 // MCUDataBean mMCUDataBean = new MCUDataBean(); // mMCUDataBean.command = command; // mMCUDataBean.receiveBytes = usefulBytes; // // HandleMCUData(mMCUDataBean); // // } // // /** // * 处理MCU返回的命令数据 // * // * @param mMCUDataBean // */ // private static void HandleMCUData(MCUDataBean mMCUDataBean) { // switch (mMCUDataBean.command) { // case MCUConstants.MCU_COMMAND_SEND_BACK: //0x80 上报数据 // if (!HDLSerialPortCore.bPassThrough) { //// HandleHDLdata(mMCUDataBean.receiveBytes); //不是透传的话,处理485数据 // // AddReceive485DatasList(mMCUDataBean.receiveBytes); // } else { // HDLDeviceManager.HandleMCUData(mMCUDataBean); // // } // break; // case MCUConstants.MCU_SEND_UPGRADE_DATA_BACK: //0x05 发送升级数据返回 注意,当文件地址为0xF5F5F5F5的时候,代表发生错误,升级包不对,会退出升级模式。当文件地址为0xF8F8F8F8,代表成功,成功后会重启,监听到重启完毕,才代表完成。 // handleSendUpgradeDataBack(mMCUDataBean); // break; // default: // HDLDeviceManager.HandleMCUData(mMCUDataBean); // break; // } // } // //// /** //// * //// * @param receive485Bytes //// */ //// private static void AddReceive485DatasList(byte[] receive485Bytes) { //// for (int i = 0; i < receive485Bytes.length; i++) { //// mReceive485DatasList.add(receive485Bytes[i]); //// } //// } // // // private static void handleSendUpgradeDataBack(MCUDataBean mMCUDataBean) { // try { // int addressIndex = HDLUtlis.byteArrayToInt(mMCUDataBean.receiveBytes); // HDLLog.I("addressIndex:" + addressIndex); // if (addressIndex == 0xF5F5F5F5) { // //当文件地址为0xF5F5F5F5的时候,代表发生错误,升级包不对,会退出升级模式 // sendIMcuOtaListeneronFailure(EventCode.FAILURE_DATA_ERROR, "升级错误,升级包不对"); // } else if (addressIndex == 0xF8F8F8F8) { // //当文件地址为0xF8F8F8F8,代表成功,成功后会重启,监听到重启完毕 // sendIMcuOtaListenerOnProgress(100); // sendIMcuOtaListenerOnSuccess(); // upgradeFileDatas = null;//升级文件清空 // } else { // //继续升级 返送下一个升级包 并返回进度 // if (addressIndex > upgradeFileDatas.length) { // HDLLog.E("addressIndex 大于升级包长度"); // return; // } // // HDLCommand.mcuSendUpgradeData(getNextUpgradebytes(mMCUDataBean.receiveBytes, addressIndex)); // int progress = addressIndex * 100 / (upgradeFileDatas.length - 1); // sendIMcuOtaListenerOnProgress(progress); // } // } catch (Exception e) { // e.printStackTrace(); // HDLLog.E("handleSendUpgradeDataBack 出错"); // } // // } // // /** // * 获取下一段升级包数据 // * // * @param index // */ // private static byte[] getNextUpgradebytes(byte[] addressBytes, int index) { // byte[] newBytes = new byte[1030];//1024+6 // System.arraycopy(addressBytes, 0, newBytes, 0, 4); // int sub = upgradeFileDatas.length - 1 - index; // if (sub >= 1024) { // System.arraycopy(upgradeFileDatas, index, newBytes, 6, 1024); // } else { // System.arraycopy(upgradeFileDatas, index, newBytes, 6, sub); // } // newBytes[4] = 0x04;//默认数据长度为1024 // newBytes[5] = 0x00; // // return newBytes; // } // // // /** // * 设置监听事件 // * // * @param listener // */ // public static void setIMcuOtaListener(IMcuOtaListener listener) { // mIMcuOtaListener = listener; // } // // public static void removeIMcuOtaListener() { // mIMcuOtaListener = null; // } // // /** // * onProgress // * // * @param progress // */ // public static void sendIMcuOtaListenerOnProgress(int progress) { // if (mIMcuOtaListener != null) { // progress = HDLUtlis.getTrueProgressInt(progress);//确保progress 在0到100 // mIMcuOtaListener.onProgress(progress); // } // } // // /** // * onSuccess // */ // public static void sendIMcuOtaListenerOnSuccess() { // if (mIMcuOtaListener != null) { // mIMcuOtaListener.onSuccess(); // } // } // // /** // * onFailure // * // * @param code 错误码 // * @param error 失败原因 // */ // public static void sendIMcuOtaListeneronFailure(int code, String error) { // if (mIMcuOtaListener != null) { // mIMcuOtaListener.onFailure(code, error); // } // } // }