From 8dc7fb4e356869704b0123a243c5a484ab183ce6 Mon Sep 17 00:00:00 2001 From: DXL <64101226@qq.com> Date: Thu, 27 Aug 2020 12:24:58 +0800 Subject: [PATCH] Add files via upload --- appmain/executor/ChameleonExecutorProxy.java | 125 +++++++++++ appmain/executor/ChameleonStdExecutor.java | 224 +++++++++++++++++++ appmain/executor/ChameleonUsbExecutor.java | 19 ++ 3 files changed, 368 insertions(+) create mode 100644 appmain/executor/ChameleonExecutorProxy.java create mode 100644 appmain/executor/ChameleonStdExecutor.java create mode 100644 appmain/executor/ChameleonUsbExecutor.java diff --git a/appmain/executor/ChameleonExecutorProxy.java b/appmain/executor/ChameleonExecutorProxy.java new file mode 100644 index 0000000..3517b5a --- /dev/null +++ b/appmain/executor/ChameleonExecutorProxy.java @@ -0,0 +1,125 @@ +package com.proxgrind.chameleon.executor; + +import java.io.IOException; +import java.util.ArrayList; + +import com.proxgrind.chameleon.defined.BasicTypesCallback; +import com.proxgrind.chameleon.posixio.PosixCom; +import com.proxgrind.chameleon.defined.IChameleonExecutor; +import com.proxgrind.chameleon.utils.system.SystemUtils; +import com.proxgrind.devices.DriverInterface; + +/** + * 这个类实际是个代理类,留了一个接口来初始化其中引用的实际(执行器)的实现! + * 抽出这个类主要是为了实现将具体的类隐匿。 + * 因此我们需要将初始化的必要接口留下来,此类也必须是单例! + * + * @author DXL + */ +public class ChameleonExecutorProxy implements IChameleonExecutor { + + private static IChameleonExecutor mExecutor; + private static ChameleonExecutorProxy mImpl; + private ArrayList entrys = new ArrayList<>(); + + public static void setExecutor(IChameleonExecutor executor) throws RuntimeException { + mExecutor = executor; + } + + public static ChameleonExecutorProxy getInstance() { + synchronized (ChameleonExecutorProxy.class) { + if (mImpl == null) mImpl = new ChameleonExecutorProxy(); + } + return mImpl; + } + + @Override + public boolean initExecutor(DriverInterface com) { + if (mExecutor != null) + return mExecutor.initExecutor(com); + return false; + } + + @Override + public byte[] requestChameleon(String at, int timeout, boolean xmodemMode) { + if (mExecutor != null) + return callback(mExecutor.requestChameleon(at, timeout, xmodemMode)); + else return "Device Disconnected".getBytes(); + } + + @Override + public byte[] requestChameleon(int timeout, int length) { + if (mExecutor != null) + return callback(mExecutor.requestChameleon(timeout, length)); + else return "Device Disconnected".getBytes(); + } + + @Override + public int requestChameleon(String at, int timeout) throws IOException { + if (mExecutor != null) + return mExecutor.requestChameleon(at, timeout); + else + return -1; + } + + @Override + public DriverInterface getDriver() { + if (mExecutor == null) return null; + return mExecutor.getDriver(); + } + + @Override + public int clear(int timeout) { + if (mExecutor != null) + return mExecutor.clear(timeout); + else return -1; + } + + @Override + public void close() { + try { + DriverInterface driverInterface = getDriver(); + if (driverInterface != null) { + driverInterface.disconnect(); + driverInterface.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public String getVersion() { + if (mExecutor != null) + return mExecutor.getVersion(); + else + return "Device Disconnected"; + } + + @Override + public boolean isConnected() { + if (mExecutor != null) + return mExecutor.isConnected(); + return false; + } + + public void addEntry(BasicTypesCallback.ByteType entry) { + this.entrys.add(entry); + } + + public void removeEntry(BasicTypesCallback.ByteType entry) { + this.entrys.remove(entry); + } + + public byte[] callback(byte[] in) { + if (entrys.size() > 0) + for (BasicTypesCallback.ByteType type : entrys) { + type.onBytes(in); + } + return in; + } + + public IChameleonExecutor getExecutorInternalImpl() { + return mExecutor; + } +} diff --git a/appmain/executor/ChameleonStdExecutor.java b/appmain/executor/ChameleonStdExecutor.java new file mode 100644 index 0000000..87f9688 --- /dev/null +++ b/appmain/executor/ChameleonStdExecutor.java @@ -0,0 +1,224 @@ +package com.proxgrind.chameleon.executor; + +import com.proxgrind.chameleon.utils.tools.HexUtil; +import com.proxgrind.chameleon.utils.system.LogUtils; +import com.proxgrind.chameleon.utils.system.SystemUtils; +import com.proxgrind.chameleon.defined.IChameleonExecutor; +import com.proxgrind.chameleon.utils.chameleon.ChameleonResult; +import com.proxgrind.devices.DriverInterface; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * @author DXL + * BLE执行器实现类,具体封装了执行和获得返回值的函数! + * 由于BLE的通讯原因,我们必须实现封包和解包! + */ +public class ChameleonStdExecutor implements IChameleonExecutor { + + //static final Object lock = new Object(); + static DriverInterface mCom; + public static String version = "not"; + + /** + * 设备初始化方法! + * + * @param com 传入的串口通信接口! + */ + @Override + public boolean initExecutor(DriverInterface com) { + mCom = com; + //判断一下设备是否可以正常开启关闭! + byte[] result = requestChameleon("VERSION?", 2000, false); + // 重发! + if (result == null) + result = requestChameleon("VERSION?", 2000, false); + // 判断结果! + if (result != null && ChameleonResult.isCommandResponse(result)) { + ChameleonResult r = new ChameleonResult(null); + if (r.processCommandResponse(result)) { + version = r.getCmdResponseData(); + ChameleonExecutorProxy.setExecutor(this); + LogUtils.d("ChameleonExecutorProxy初始化成功: " + this); + return true; + } + } + LogUtils.d("ChameleonExecutorProxy初始化失败: " + new String(result != null ? result : new byte[0])); + return false; + } + + /** + * @param at 指令,ascii编码集,需要在后缀附带\r换行! + * @param timeout 超时,多久之后接收不到完整的数据帧自动返回? + * @return 设备的返回信息,可能超时(无返回值),如果超时则返回null,否则返回对应命令的应答! + */ + @Override + public byte[] requestChameleon(String at, int timeout, boolean xmodemMode) { + try { + //请求并且判断结果! + if (requestChameleon(at, timeout) == -1) return null; + //初始化必须的变量 + ByteArrayOutputStream bos = new ByteArrayOutputStream(512); + long currentTime = System.currentTimeMillis(); + //Log.d(LOG_TAG, "得到锁成功,当前线程ID: " + Thread.currentThread().getId()); + do { + if (SystemUtils.isTimeout(currentTime, timeout)) return null; + //开始接收,每次接收一个字节! + byte tmpByte = read(1); + if (tmpByte != -1) { + //接收完毕,有有效的字节!!! + bos.write(tmpByte); + //Log.d(LOG_TAG, "打印接收到的字节: " + HexUtil.toHexString(tmpByte)); + //有有效数据,进行超时拖延! + currentTime = System.currentTimeMillis(); + //判断到换行,则可能是一帧的结束! + // FIXME: 2019/4/21 谨记,上传或下载将会打开xmodem通道,此时应当进行判断,断定下一步的操作! + if (tmpByte == 0x0A) { + //Log.d(LOG_TAG, "有换行,下一步判断是否需要继续接收!"); + if (!xmodemMode) { + //延迟判断新行,最大限度提升成功率!!! + tmpByte = read(50); + if (tmpByte != -1) { + //Log.d(LOG_TAG, "需要"); + bos.write(tmpByte); + currentTime = System.currentTimeMillis(); + } else { + //Log.d(LOG_TAG, "不需要"); + //接收完毕,直接返回! + //Log.d(LOG_TAG, "锁释放完成: " + Thread.currentThread().getId()); + return bos.toByteArray(); + } + } else { + return bos.toByteArray(); + } + } + } + } while (true); //超时中处理! + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 在指定的时间内接收指定的长度的值, + * + * @param timeout 超时值 + * @param length 欲接收的长度! + * @return 接收结果! + */ + @Override + public byte[] requestChameleon(int timeout, int length) { + byte[] ret = new byte[length]; + int pos = 0; + long currentTime = System.currentTimeMillis(); + //Log.d(LOG_TAG, "得到锁成功,当前线程ID: " + Thread.currentThread().getId()); + do { + //开始接收,每次接收一个字节! + byte tmpByte = read(1); + if (tmpByte != -1) { + ret[pos] = tmpByte; + if (++pos == length) break; + } + } while (SystemUtils.isTimeout(currentTime, timeout)); //超时中处理! + return ret; + } + + /** + * @param at 指令,ascii编码集,需要在后缀附带\r换行! + * @param timeout 超时,多久之后接收不到完整的数据帧自动返回? + * @return 发送成功的字节数,如果发送失败则返回 -1 + */ + @Override + public int requestChameleon(String at, int timeout) throws IOException { + if (at == null) return -1; + //Log.d(LOG_TAG, "尝试得到锁,当前线程ID: " + Thread.currentThread().getId()); + //发送命令必须回应,否则系命令错误! + at = checkAT(at); + byte[] sendBuf = HexUtil.getAsciiBytes(at); + return mCom.write(sendBuf, 0, sendBuf.length, timeout); + } + + /** + * @param at 指令! + * @return 如果命令带\r后缀,则直接返回,否则添加! + */ + protected String checkAT(String at) { + return at.endsWith("\r") ? at : (String.format("%s\r", at)); + } + + /** + * 读取一个字节,简化读取! + * + * @param timeout 超时值 + * @return 读取结果,-1为失败! + */ + protected byte read(int timeout) { + byte[] b = new byte[1]; + try { + int len = mCom.read(b, 0, 1, timeout); + if (len > 0) { + return b[0]; + } + return -1; + } catch (IOException e) { + e.printStackTrace(); + } + return -1; + } + + /** + * 得到通信端口! + * + * @return 通信端口! + */ + @Override + public DriverInterface getDriver() { + LogUtils.w("警告,直接操作COM端口可能产生通信数据串行干扰的问题," + + "请务必保证同时操作com的只有一个Thread: " + Thread.currentThread().getId()); + return mCom; + } + + /** + * 清除可能缓存的数据! + * + * @param timeout 超时值 + * @return 被清除的字节个数 + */ + @Override + public int clear(int timeout) { + int count = 0; + long currentTime = System.currentTimeMillis(); + //Log.d(LOG_TAG, "得到锁成功,当前线程ID: " + Thread.currentThread().getId()); + do { + //开始接收,每次接收一个字节! + byte tmpByte = read(1); + if (tmpByte != -1) { + ++count; + } + } while (System.currentTimeMillis() - currentTime < timeout); //超时中处理! + return count; + } + + @Override + public void close() { + if (getDriver() != null) { + try { + getDriver().close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public String getVersion() { + return version; + } + + @Override + public boolean isConnected() { + return mCom != null && mCom.isDeviceConnected(); + } +} diff --git a/appmain/executor/ChameleonUsbExecutor.java b/appmain/executor/ChameleonUsbExecutor.java new file mode 100644 index 0000000..9e37514 --- /dev/null +++ b/appmain/executor/ChameleonUsbExecutor.java @@ -0,0 +1,19 @@ +package com.proxgrind.chameleon.executor; + +import com.proxgrind.chameleon.defined.IChameleonExecutor; + +/** + * @author DXL + * USB执行器实现类,具体封装了执行和获得返回值的函数! + */ +public class ChameleonUsbExecutor extends ChameleonStdExecutor implements IChameleonExecutor { + + private static final ChameleonUsbExecutor executor = new ChameleonUsbExecutor(); + + /** + * @return 单例 + */ + public static IChameleonExecutor get() { + return executor; + } +}