android作为服务器的开发,安卓与pc的串口开发
公司要求,一个比较扯淡的架构
在安卓系统上完成一套mini的完整服务
包括规约解析的规约插件;包括调度,采集,存库等的采集系统;以及上层面向客户的各个应用
也就接触了android开发;
先说踩的坑把
在IDEA上做android开发;gradle的构建工具最好选下面版本,不然可能会报版本问题
classpath 'com.android.tools.build:gradle:7.0.0'
其他问题几乎没有,有应该也不是啥大问题把,没印象了
然后要在安卓上实现AB芯的通信,通过串口
应该是安卓模拟器天生的bug,发送数据超过8个字节就会挂掉,
环境构建的坑:
1.安卓模拟器没有root权限,需要命令行修改:
adb root
adb shell setenforce 0
adb shell
chmod 777 /dev/tty*
2.命令行启动模拟器,挂载串口 emulator @Nexus_9_API_30 -qemu -serial COM1
为了规避安卓模拟一发就挂,只能安卓往外发,在另一端写好接收后的代码,调试OK,搬回android项目,等上了真实终端调试
调试代码需要依赖rxtx
http://fizzed.com/oss/rxtx-for-java
还需要将dll文件放入:1将jar包放入jre/lib下的ext文件夹;2C:/System/System32
可能放一个地方也行,我两边都放了,项目能运行,也就没管
串口工具网上很多的我主要用了Configure Virtual Serial Port Driver开端口,serial_port_utility来开端口发数据
网上确实有解决安卓模拟器异常退出的方法,我倒腾了半天,没有成功,安装的程序又大又笨重,最后还是自己在PC写个接收程序,实现安卓端程序的分包问题等。
贴一下接收端的纯PC的java代码,代码主要也是从网上来得,但是源码的接收写的有问题,我这里优化了接收,以及我自己的分包策略
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | package com.company; import gnu.io.SerialPort; import java.nio.charset.StandardCharsets; import java.util.Locale; import static com.company.SerialPortConstants.BEGIN_BYTES; import static com.company.SerialPortConstants.END_BYTE; public class client { static int i = 0 ; public static StringBuffer sb = new StringBuffer(); public static void main(String[] args) throws SerialPortParameterFailure, NoSuchPort, InterruptedException { /* ArrayList<String> findPort = SerialTool.findPort(); System.out.println("可用串口"); for(String f:findPort) { System.out.println(f); } System.out.println(); //设定发送字符串 System.out.println(Arrays.toString(bs));//打印字符串 System.out.println(findPort.get(0));//找到COM1串口*/ byte [] bs = "AA" .getBytes(); SerialPort Port = SerialTool.openPort( "COM2" , 9600 ); //打开串口 System.out.println(Port.getName()); //获取串口名 SerialTool.addListener(Port, new SerialTool.DataAvailableListener() { @SuppressWarnings ( "unused" ) @Override public void dataAvailable() { try { if (Port == null ) { System.out.println( "串口对象为空,监听失败!" ); } else { // 读取串口数据 new Thread(() -> { while ( true ) { byte [] data = null ; try { data = SerialTool.readFromPort(Port); /*System.out.println("打印"+data);*/ if (data != null && data.length > 0 ) { sb.append( new String(data)); spilt(sb); System.out.println(); System.out.println(); System.out.println( "------------" ); System.out.println( new String(data)); System.out.println(sb.toString()); System.out.println( "------------" ); System.out.println(); System.out.println(); } } catch (NoSuchPort e) { e.printStackTrace(); } finally { try { Thread.sleep( 1000 ); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } catch (Exception e) { System.out.println( "错误" ); } } }); String s = "##0897{\"businessObjList\":[{\"commObj\":{\"authId\":0,\"commAddr\":\"116000009488\",\"deviceId\":\"200000312\",\"eigenvalue\":3,\"extendObj\":{\"comInfo\":{\"baudRate\":\"2400\",\"byteSize\":\"0\",\"comPort\":31,\"parity\":\"0\",\"stopBits\":\"0\"},\"measurNo\":201,\"port\":0,\"pulseSerial\":-1,\"roadNo\":201,\"totalSerial\":0},\"protocolNumber\":401070011},\"dataObj\":{\"collBeginTime\":\"2023-02-07 15:15:00\",\"collCycle\":15,\"collEndTime\":\"2023-02-07 15:15:00\",\"dataItemList\":[{\"finshFlag\":0,\"itemId\":\"30303006\"}],\"timeType\":4},\"soureDeviceId\":\"200023123\",\"transCommand\":false}],\"cmdType\":2,\"commObj\":{\"authId\":0,\"commAddr\":\"201500010134\",\"deviceId\":\"200023123\",\"eigenvalue\":2,\"extendObj\":{\"comInfo\":{\"baudRate\":\"0\",\"byteSize\":\"0\",\"comPort\":111111,\"parity\":\"0\",\"stopBits\":\"0\"},\"measurNo\":0,\"port\":0,\"pulseSerial\":-1,\"roadNo\":0,\"totalSerial\":0},\"protocolNumber\":201130010},\"priority\":0,\"spathId\":111111,\"taskId\":280370423755964416,\"timeout\":0,\"udSign\":0}+\r\n" ; //send(s,Port); //SerialTool.sendToPort(Port, s.getBytes()); /*byte[] readFromPort = SerialTool.readFromPort(Port); System.out.println(readFromPort);*/ /*SerialTool.closePort(Port);*/ } public static void spilt(StringBuffer sb) { int begin = sb.indexOf( new String(BEGIN_BYTES)); int end = sb.indexOf( new String(END_BYTE)); if (begin != - 1 && begin > 0 ) { System.out.println( "起始符不在0位置,去掉起始符之前的数据,当前数据:" + sb); sb.replace( 0 , begin, "" ); } if (begin != - 1 && end != - 1 ) { i++; String s = sb.substring(begin + 6 , end - 1 ); sb.replace(begin, end + 2 , "" ); System.out.println( "拆分的第" + i + "条数据:" + s); // System.out.println("sb内容" + sb); } } private static void send(String s, SerialPort Port) throws NoSuchPort, InterruptedException { byte [] bytes = s.getBytes(StandardCharsets.UTF_8); for ( int i = 0 ; i < bytes.length; i = i + 7 ) { if (i + 7 < bytes.length) { byte [] bytes1 = new byte [ 7 ]; for ( int j = 0 ; j < 7 ; j++) { bytes1[j] = bytes[i + j]; } SerialTool.sendToPort(Port, bytes1); Thread.sleep( 1000 ); } else { if (bytes.length % 7 != 0 ) { byte [] bytes1 = new byte [bytes.length % 7 ]; for ( int j = 0 ; j < bytes.length % 7 ; j++) { bytes1[j] = bytes[i + j]; } SerialTool.sendToPort(Port, bytes1); } } } } public static byte [] hex2Bytes(String hex) { if (hex == null || hex.length() == 0 ) { return null ; } char [] hexChars = hex.toCharArray(); byte [] bytes = new byte [hexChars.length / 2 ]; // 如果 hex 中的字符不是偶数个, 则忽略最后一个 for ( int i = 0 ; i < bytes.length; i++) { bytes[i] = ( byte ) Integer.parseInt( "" + hexChars[i * 2 ] + hexChars[i * 2 + 1 ], 16 ); } return bytes; } /** * byte[]转十六进制字符串 * * @param array byte[] * @return 十六进制字符串 */ public static String byteArrayToHexString( byte [] array) { if (array == null ) { return "" ; } StringBuffer buffer = new StringBuffer(); for ( int i = 0 ; i < array.length; i++) { buffer.append(byteToHex(array[i])); } return buffer.toString(); } /** * byte转十六进制字符 * * @param b byte * @return 十六进制字符 */ public static String byteToHex( byte b) { String hex = Integer.toHexString(b & 0xFF ); if (hex.length() == 1 ) { hex = '0' + hex; } return hex.toUpperCase(Locale.getDefault()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 | package com.company; public class NoSuchPort extends Exception { /** * */ private static final long serialVersionUID = 1L; @Override public String toString() { return "没有该端口对应的串口设备!" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.company; public interface SerialPortConstants { /** * 帧起始字符 */ byte [] BEGIN_BYTES = "##" .getBytes(); String BEGIN_STR = "##" ; /** * 帧结束字符 */ byte [] END_BYTE = new byte []{ 0x0d , 0x0a }; String UP_TOPIC_PRE = "iot/A-CHIP/700020010/up/" ; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.company; public class SerialPortParameterFailure extends Exception { /** * */ private static final long serialVersionUID = 1L; public SerialPortParameterFailure() {} @Override public String toString() { return "设置串口参数失败!打开串口操作未完成!" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | package com.company; import gnu.io.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.TooManyListenersException; public class SerialTool { /** * 查找所有可用端口 * * @return 可用端口名称列表 */ public static final ArrayList<String> findPort() { //获得当前所有可用串口 @SuppressWarnings ( "unchecked" ) Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList = new ArrayList<String>(); //将可用串口名添加到List并返回该List while (portList.hasMoreElements()) { String portName = portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /** * 打开串口 * * @param portName 端口名称 * @param baudrate 波特率 * @return 串口对象 * @throws SerialPortParameterFailure 设置串口参数失败 * @throws NotASerialPort 端口指向设备不是串口类型 * @throws NoSuchPort 没有该端口对应的串口设备 * @throws PortInUse 端口已被占用 */ public static final SerialPort openPort(String portName, int baudrate) throws SerialPortParameterFailure, NoSuchPort, NoSuchPort, NoSuchPort { try { //通过端口名识别端口 CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); //打开端口,并给端口名字和一个timeout(打开操作的超时时间) CommPort commPort = portIdentifier.open(portName, 2000 ); //判断是不是串口 if (commPort instanceof SerialPort) { SerialPort serialPort = (SerialPort) commPort; try { //设置一下串口的波特率等参数 serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); /*serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);*/ } catch (UnsupportedCommOperationException e) { throw new SerialPortParameterFailure(); } System.out.println( "Open " + portName + " successfully !" ); return serialPort; } else { //不是串口 throw new NoSuchPort(); } } catch (NoSuchPortException e1) { throw new NoSuchPort(); } catch (PortInUseException e2) { throw new NoSuchPort(); } } /** * 关闭串口 * * @param serialport 待关闭的串口对象 */ public static void closePort(SerialPort serialPort) { if (serialPort != null ) { serialPort.close(); serialPort = null ; } } /** * 往串口发送数据 * * @param serialPort 串口对象 * @param order 待发送数据 * @throws SendDataToSerialPortFailure 向串口发送数据失败 * @throws SerialPortOutputStreamCloseFailure 关闭串口对象的输出流出错 */ public static void sendToPort(SerialPort serialPort, byte [] order) throws NoSuchPort, NoSuchPort { OutputStream out = null ; try { //order="ad".getBytes(StandardCharsets.UTF_8); out = serialPort.getOutputStream(); out.write(order); out.flush(); System.out.println( "写入成功" + new String(order)); } catch (IOException e) { throw new NoSuchPort(); } finally { try { if (out != null ) { out.close(); out = null ; } } catch (IOException e) { throw new NoSuchPort(); } } } /** * 从串口读取数据 * * @param serialPort 当前已建立连接的SerialPort对象 * @return 读取到的数据 * @throws ReadDataFromSerialPortFailure 从串口读取数据时出错 * @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错 */ public static byte [] readFromPort(SerialPort serialPort) throws NoSuchPort, NoSuchPort { InputStream in = null ; List< byte []> list = new ArrayList<>(); int length = 0 ; try { in = serialPort.getInputStream(); int bufflenth = in.available(); //获取buffer里的数据长度 while (bufflenth != 0 ) { byte [] bytes = new byte [bufflenth]; //初始化byte数组为buffer中数据的长度 in.read(bytes); bufflenth = in.available(); list.add(bytes); length = length + bytes.length; System.out.println( "读取成功" ); } } catch (IOException e) { throw new NoSuchPort(); } finally { try { if (in != null ) { in.close(); in = null ; } } catch (IOException e) { throw new NoSuchPort(); } } if (length > 0 ) { byte [] bytesb = new byte [length]; int index = 1 ; for ( byte [] item : list) { index = copyToReq(bytesb, item, index); } System.out.println( "读取数据" + new String(bytesb)); return bytesb; } return null ; } private static int copyToReq( byte [] req, byte [] msg, int index) { for ( int i = 0 ; i < msg.length; i++) { req[i + index - 1 ] = msg[i]; } return index + msg.length; } /** * 添加监听器 * * @param port 串口对象 * @param listener 串口监听器 * @throws TooManyListeners 监听类对象过多 */ public static void addListener(SerialPort port, DataAvailableListener listener) throws NoSuchPort { try { //给串口添加监听器 port.addEventListener( new SerialPortListener(listener)); //设置当有数据到达时唤醒监听接收线程 port.notifyOnDataAvailable( true ); //设置当通信中断时唤醒中断线程 port.notifyOnBreakInterrupt( true ); } catch (TooManyListenersException e) { throw new NoSuchPort(); } } /** * 串口监听 */ public static class SerialPortListener implements SerialPortEventListener { private DataAvailableListener mDataAvailableListener; public SerialPortListener(DataAvailableListener mDataAvailableListener) { this .mDataAvailableListener = mDataAvailableListener; } @Override public void serialEvent(SerialPortEvent serialPortEvent) { switch (serialPortEvent.getEventType()) { case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效数据 if (mDataAvailableListener != null ) { mDataAvailableListener.dataAvailable(); } break ; case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.输出缓冲区已清空 break ; case SerialPortEvent.CTS: // 3.清除待发送数据 break ; case SerialPortEvent.DSR: // 4.待发送数据准备好了 break ; case SerialPortEvent.RI: // 5.振铃指示 break ; case SerialPortEvent.CD: // 6.载波检测 break ; case SerialPortEvent.OE: // 7.溢位(溢出)错误 break ; case SerialPortEvent.PE: // 8.奇偶校验错误 break ; case SerialPortEvent.FE: // 9.帧错误 break ; case SerialPortEvent.BI: // 10.通讯中断 System.out.println( "与串口设备通讯中断" ); break ; default : break ; } } } /** * 串口存在有效数据监听 */ public interface DataAvailableListener { /** * 串口存在有效数据 */ void dataAvailable(); } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!