包括规约解析的规约插件;包括调度,采集,存库等的采集系统;以及上层面向客户的各个应用
也就接触了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代码,代码主要也是从网上来得,但是源码的接收写的有问题,我这里优化了接收,以及我自己的分包策略
代码
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());
}
}
package com.company;
public class NoSuchPort extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public String toString() {
return "没有该端口对应的串口设备!";
}
}
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/";
}
package com.company;
public class SerialPortParameterFailure extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public SerialPortParameterFailure() {}
@Override
public String toString() {
return "设置串口参数失败!打开串口操作未完成!";
}
}
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();
}
}