赞
踩
RXTX是一个提供串口和并口通信的开源java类库,由该项目发布的文件均遵循LGPL协议。
RXTX项目提供了Windows,Linux,Mac os X,Solaris操作系统下的兼容javax.comm串口通讯包API的实现,为其他开发人员在此类系统下开发串口应用提供了相当的方便。
RXTX的使用上与sun提供的comm.jar基本相同,编程时最明显的不同是要包含的包名由javax.comm.改成了gnu.io.
RxtxAPI 的核心是抽象的CommPort类(用于描述一个被底层系统支持的端口的抽象类,它包含一些高层的IO控制方法,这些方法对于所有不同的通讯端口来说是通用的)及其两个子类:SerialPort类和ParallePort类。其中,SerialPort类是用于串口通信的类,ParallePort类是用于并行口通信的类。CommPort类还提供了常规的通信模式和方法,例如:getInputStream( )方法和getOutputStream( )方法,专用于与端口上的设备进行通信。
然而,这些类的构造方法都被有意的设置为非公有的(non-public)。所以,不能直接构造对象,而是先通过静态的CommPortIdentifer.getPortIdentifiers()获得端口列表,再从这个端口列表中选择所需要的端口,并调用CommPortIdentifer对象的Open( )方法,这样,就能得到一个CommPort对象。当然,还要将这个CommPort对象的类型转换为某个非抽象的子类,表明是特定的通讯设备,该子类可以是SerialPort类和ParallePort类中的一个。下面将分别对CommPortIdentifier类,串口类SerialPort进行详细的介绍。
- 接口
-
- CommDriver可负载设备(the loadable device)驱动程序接口的一部分
-
- CommPortOwnershipListener传递各种通讯端口的所有权事件
-
- ParallelPortEventListener传递并行端口事件
-
- SerialPortEventListener传递串行端口事件
-
- 类
-
- CommPort通讯端口
-
- CommPortIdentifier通讯端口管理
-
- ParallelPort并行通讯端口
-
- ParallelPortEvent并行端口事件
-
- SerialPortRS-232串行通讯端口
-
- SerialPortEvent 串行端口事件
-
- 异常类
-
- NoSuchPortException当驱动程序不能找到指定端口时抛出
-
- PortInUseException当碰到指定端口正在使用中时抛出
-
- UnsupportedCommOperationException驱动程序不允许指定操作时抛出
-
- CommPortIdentifier类
-
- 这个类主要用于对通信端口进行管理和设置,是对端口进行访问控制的核心类,主要包括以下方法:
-
- addPortName(String,int, CommDriver) 添加端口名到端口列表里
-
- addPortOwnershipListener(CommPortOwnershipListener)添加端口拥有的监听器
-
- removePortOwnershipListener(CommPortOwnershipListener)移除端口拥有的监听器
-
- getCurrentOwner()获取当前占有端口的对象或应用程序
-
- getName()获取端口名称
-
- getPortIdentifier(CommPort)获取指定打开的端口的CommPortIdentifier类型对象
-
- getPortIdentifier(String)获取以参数命名的端口的CommPortIdentifier类型对象
-
- getPortIdentifiers()获取系统中的端口列表
-
- getPortType()获取端口的类型
-
- isCurrentlyOwned()判断当前端口是否被占用
-
- open(FileDescriptor)用文件描述的类型打开端口
-
- open(String,int) 打开端口,两个参数:程序名称,延迟时间(毫秒数)
-
- SerialPort类
-
- 这个类用于描述一个RS-232串行通信端口的底层接口,它定义了串口通信所需的最小功能集。通过它,用户可以直接对串口进行读、写及设置工作。
-
- SerialPort类中关于串口参数的静态成员变量说明:
-
- DATABITS_5 数据位为5
-
- DATABITS_6 数据位为6
-
- DATABITS_7 数据位为7
-
- DATABITS_8 数据位为8
-
- PARITY_NONE 空格检验
-
- PARITY_ODD 奇检验
-
- PARITY_EVEN 偶检验
-
- PARITY_MARK 标记检验
-
- PARITY_SPACE 无检验
-
- STOPBITS_1 停止位为1
-
- STOPBITS_2 停止位为2
-
- STOPBITS_1_5 停止位为1.5
-
-
-
- SerialPort类中关于串口参数的方法说明:
-
- getBaudRate()得到波特率
-
- getParity()得到检验类型
-
- getDataBits()得到数据位数
-
- getStopBits()得到停止位数
-
- setSerialPortParams(int,int, int, int) 设置串口参数依次为(波特率,数据位,停止位,奇偶检验)
-
- SerialPort类中关于事件的静态成员变量说明:
-
- BI Break interrupt 通讯中断
-
- FE Framing error 帧错误
-
- CD Carrier detect 载波侦听
-
- OE Overrun error 溢位错误
-
- CTS Clear to send 清除发送
-
- PE Parity error 奇偶检验错误
-
- DSR Data set ready 数据设备准备好
-
- RI Ring indicator 响铃侦测
-
- DATA_AVAILABLE 串口中的可用数据
-
- OUTPUT_BUFFER_EMPTY 输出缓冲区已清空
-
-
-
- SerialPort类中关于事件的方法说明:
-
- isCD()是否有载波
-
- isCTS()是否清除以传送
-
- isDSR()数据是否备妥
-
- isDTR()是否数据端备妥
-
- isRI()是否响铃侦测
-
- isRTS()是否要求传送
-
- addEventListener(SerialPortEventListener)向SerialPort对象中添加串口事件监听器
-
- removeEventListener()移除SerialPort对象中的串口事件监听器
-
- notifyOnBreakInterrupt(boolean)设置中断事件true有效,false无效
-
- notifyOnCarrierDetect(boolean)设置载波监听事件true有效,false无效
-
- notifyOnCTS(boolean)设置清除发送事件true有效,false无效
-
- notifyOnDataAvailable(boolean)设置串口有数据的事件true有效,false无效
-
- notifyOnDSR(boolean)设置数据备妥事件true有效,false无效
-
- notifyOnFramingError(boolean)设置发生错误事件true有效,false无效
-
- notifyOnOutputEmpty(boolean)设置发送缓冲区为空事件true有效,false无效
-
- notifyOnParityError(boolean)设置发生奇偶检验错误事件true有效,false无效
-
- notifyOnRingIndicator(boolean)设置响铃侦测事件true有效,false无效
-
- getEventType()得到发生的事件类型返回值为int型
-
- sendBreak(int)设置中断过程的时间,参数为毫秒值
-
- setRTS(boolean)设置或清除RTS位
-
- setDTR(boolean)设置或清除DTR位
-
- SerialPort中的其他常用方法说明:
-
- close()关闭串口
-
- getOutputStream()得到OutputStream类型的输出流
-
- getInputStream()得到InputStream类型的输入流
-
解压rxtx-2.2pre2-bins.zip,将RXTXcomm.jar加入项目依赖库里,对应操作的系统的rxtxSerial.dll和rxtxParallel.dll文件放入jdk的bin目录下
- 前提条件:maven已经加入环境变量中
- mvn install:install-file -DgroupId=gnu.io -DartifactId=RXTXcomm -Dversion=1.0 -Dpackaging=jar -Dfile=E:\Work\Yotrio\libs\RXTXcomm.jar
Image.png
Image [2].png
封装串口读写工具类
-
- /**
- * 模块名称:projects-parent com.yotrio.common
- * 功能说明:串口服务类,提供打开、关闭串口,读取、发送串口数据等服务(采用单例设计模式)
- * <br>
- * 开发人员:Wangyq
- * 创建时间: 2018-09-20 10:05
- * 系统版本:1.0.0
- **/
- public class SerialPortUtil {
-
- private static SerialPortUtil serialPortUtil = null;
-
- static {
- //在该类被ClassLoader加载时就初始化一个SerialTool对象
- if (serialPortUtil == null) {
- serialPortUtil = new SerialPortUtil();
- }
- }
-
- //私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象
- private SerialPortUtil() {
- }
-
- /**
- * 获取提供服务的SerialTool对象
- *
- * @return serialPortUtil
- */
- public static SerialPortUtil getSerialPortUtil() {
- if (serialPortUtil == null) {
- serialPortUtil = new SerialPortUtil();
- }
- return serialPortUtil;
- }
-
-
- /**
- * 查找所有可用端口
- *
- * @return 可用端口名称列表
- */
- public static final ArrayList<String> findPort() {
- //获得当前所有可用串口
- Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
-
- ArrayList<String> portNameList = new ArrayList<>();
-
- //将可用串口名添加到List并返回该List
- while (portList.hasMoreElements()) {
- String portName = portList.nextElement().getName();
- portNameList.add(portName);
- }
-
- return portNameList;
- }
-
- /**
- * 打开串口
- *
- * @param portName 端口名称
- * @param baudrate 波特率
- * @param databits 数据位
- * @param parity 校验位(奇偶位)
- * @param stopbits 停止位
- * @return 串口对象
- * @throws SerialPortParameterFailure 设置串口参数失败
- * @throws NotASerialPort 端口指向设备不是串口类型
- * @throws NoSuchPort 没有该端口对应的串口设备
- * @throws PortInUse 端口已被占用
- */
- public static final SerialPort openPort(String portName, int baudrate, int databits, int parity, int stopbits) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse {
-
- 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, databits, stopbits, parity);
- } catch (UnsupportedCommOperationException e) {
- throw new SerialPortParameterFailure();
- }
-
- //System.out.println("Open " + portName + " sucessfully !");
- return serialPort;
- } else {
- //不是串口
- throw new NotASerialPort();
- }
- } catch (NoSuchPortException e1) {
- throw new NoSuchPort();
- } catch (PortInUseException e2) {
- throw new PortInUse();
- }
- }
-
- /**
- * 关闭串口
- *
- * @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 SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure {
- OutputStream out = null;
- try {
- out = serialPort.getOutputStream();
- out.write(order);
- out.flush();
- } catch (IOException e) {
- throw new SendDataToSerialPortFailure();
- } finally {
- try {
- if (out != null) {
- out.close();
- out = null;
- }
- } catch (IOException e) {
- throw new SerialPortOutputStreamCloseFailure();
- }
- }
- }
-
- /**
- * 从串口读取数据
- *
- * @param serialPort 当前已建立连接的SerialPort对象
- * @return 读取到的数据
- * @throws ReadDataFromSerialPortFailure 从串口读取数据时出错
- * @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错
- */
- public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure {
-
- InputStream in = null;
- byte[] bytes = null;
-
- try {
- in = serialPort.getInputStream();
- int bufflenth = in.available(); //获取buffer里的数据长度
-
- while (bufflenth != 0) {
- bytes = new byte[bufflenth]; //初始化byte数组为buffer中数据的长度
- in.read(bytes);
- bufflenth = in.available();
- }
- } catch (IOException e) {
- throw new ReadDataFromSerialPortFailure();
- } finally {
- try {
- if (in != null) {
- in.close();
- in = null;
- }
- } catch (IOException e) {
- throw new SerialPortInputStreamCloseFailure();
- }
- }
-
- return bytes;
-
- }
-
- /**
- * 添加监听器
- *
- * @param port 串口对象
- * @param listener 串口监听器
- * @throws TooManyListeners 监听类对象过多
- */
- public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners {
-
- try {
- //给串口添加监听器
- port.addEventListener(listener);
- //设置当有数据到达时唤醒监听接收线程
- port.notifyOnDataAvailable(true);
- //设置当通信中断时唤醒中断线程
- port.notifyOnBreakInterrupt(true);
- } catch (TooManyListenersException e) {
- throw new TooManyListeners();
- }
- }
-
- /**
- * 删除监听器
- *
- * @param port 串口对象
- * @param listener 串口监听器
- * @throws TooManyListeners 监听类对象过多
- */
- public static void removeListener(SerialPort port, SerialPortEventListener listener) {
- //删除串口监听器
- port.removeEventListener();
- }
-
- }
整合websocket获取并推送给前台页面实时显示
- @ServerEndpoint(value = "/websocket") //接受websocket请求路径
- @Component
- public class PoundWebSocket {
- private Logger logger = LoggerFactory.getLogger(this.getClass());
-
- /**
- * 保存所有在线socket连接
- */
- private static Map<String, PoundWebSocket> webSocketMap = new LinkedHashMap<>();
-
- /**
- * 记录当前在线数目
- */
- private static int count = 0;
-
- /**
- * 当前连接(每个websocket连入都会创建一个MyWebSocket实例
- */
- private Session session;
-
- /**
- * 创建监听串口
- */
- private static SerialPort serialPort = null;
-
- /**
- * 创建监听器
- */
- private static SerialPortEventListener serialPortEventListener = null;
-
- /**
- * 监听串口
- */
- private static String PORT_NAME;
-
- /**
- * 监听串口波特率
- */
- private static int BAUD_RATE;
-
- /**
- * 数据位
- */
- private static int DATA_BITS;
-
- /**
- * 停止位
- */
- private static int STOP_BITS;
-
- /**
- * 奇偶位
- */
- private static int PARITY;
-
- /**
- * 地磅型号
- */
- private static String MODEL;
-
- private static IPoundInfoService poundInfoService;
-
- private static ApplicationContext applicationContext;
-
- public static void setApplicationContext(ApplicationContext applicationContext) {
- PoundWebSocket.applicationContext = applicationContext;
- }
-
- private static StringBuffer stringBuffer = new StringBuffer();
-
- /**
- * 处理连接建立
- *
- * @param session
- */
- @OnOpen
- public void onOpen(Session session) {
- if (poundInfoService == null) {
- poundInfoService = applicationContext.getBean(IPoundInfoService.class);
- }
- //获取地磅信息
- PoundInfo poundInfo = poundInfoService.findOne();
- PORT_NAME = poundInfo.getSerialPort();
- BAUD_RATE = poundInfo.getBaudRate();
- MODEL = poundInfo.getModel();
- DATA_BITS = poundInfo.getDataBits() != null ? poundInfo.getDataBits() : SerialPort.DATABITS_8;
- STOP_BITS = poundInfo.getStopBits() != null ? poundInfo.getStopBits() : SerialPort.STOPBITS_1;
- PARITY = poundInfo.getParity() != null ? poundInfo.getParity() : SerialPort.PARITY_NONE;
-
- this.session = session;
- webSocketMap.put(session.getId(), this);
- addCount();
- // logger.info("新的连接加入:{}", session.getId());
- try {
- //确保串口已被关闭,未关闭会导致重新监听串口失败
- if (serialPort != null) {
- SerialPortUtil.closePort(serialPort);
- serialPort = null;
- }
- //创建串口 COM5位串口名称 9600波特率
- if (serialPort == null && StringUtils.isNotEmpty(PORT_NAME) && StringUtils.isNotEmpty(MODEL)) {
- serialPort = SerialPortUtil.openPort(PORT_NAME, BAUD_RATE, DATA_BITS, PARITY, STOP_BITS);
- // logger.info("创建串口:{}", serialPort);
- //设置串口监听
- SerialPortUtil.addListener(serialPort, new SerialPortEventListener() {
-
- @Override
- public void serialEvent(SerialPortEvent serialPortEvent) {
- if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
- try {
- //读取串口数据
- byte[] bytes = SerialPortUtil.readFromPort(serialPort);
-
- //根据型号解析字符串
- switch (MODEL) {
- case PoundConstant.MODEL_XK_3190:
- parsingString1(bytes);
- break;
- case PoundConstant.MODEL_XK_3190_10:
- parsingString2(bytes);
- break;
- case PoundConstant.MODEL_D_2008:
- parsingString1(bytes);
- break;
- case PoundConstant.MODEL_DK_3230_D_6:
- parsingString3(bytes);
- break;
- case PoundConstant.MODEL_D_2009_F:
- parsingString4(bytes);
- break;
- default:
- String value = String.valueOf(Integer.valueOf(new String(bytes, "GB2312")) - RandomUtil.randomInt(1000, 10000));
- sendMessageToAll(value);
- }
-
- // System.out.println("收到的数据:" + new String(bytes, "GB2312") + "----" + new Date());
-
- } catch (ReadDataFromSerialPortFailure readDataFromSerialPortFailure) {
- logger.error(readDataFromSerialPortFailure.toString());
- } catch (SerialPortInputStreamCloseFailure serialPortInputStreamCloseFailure) {
- logger.error(serialPortInputStreamCloseFailure.toString());
- } catch (UnsupportedEncodingException e) {
- logger.error(e.toString());
- } catch (IOException e) {
- logger.error(e.toString());
- }
- }
- }
- });
- }
- } catch (SerialPortParameterFailure serialPortParameterFailure) {
- logger.error(serialPortParameterFailure.toString());
- } catch (NotASerialPort notASerialPort) {
- logger.error(notASerialPort.toString());
- } catch (NoSuchPort noSuchPort) {
- logger.error(noSuchPort.toString());
- } catch (PortInUse portInUse) {
- logger.error(portInUse.toString());
- } catch (TooManyListeners tooManyListeners) {
- logger.error(tooManyListeners.toString());
- }
- }
-
- /**
- * 解析字符串 方法1
- *
- * @param bytes 获取的字节码
- */
- private void parsingString1(byte[] bytes) {
- StringBuffer sb = new StringBuffer();
- //将ASCII码转成字符串
- for (int i = 0; i < bytes.length; i++) {
- sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));
- }
-
- //解析字符串
- String[] strs = sb.toString().trim().split("\\+");
- int weight = 0;
- for (int j = 0; j < strs.length; j++) {
- if (strs[j].trim().length() >= 6) {
- weight = Integer.parseInt(strs[j].trim().substring(0, 6));
- //发送数据
- sendMessageToAll(String.valueOf(weight));
- break;
- }
- }
- }
-
- /**
- * 解析字符串 方法2
- *
- * @param bytes 获取的字节码
- */
- private void parsingString2(byte[] bytes) {
- StringBuffer sb = new StringBuffer();
- //将ASCII码转成字符串
- for (int i = 0; i < bytes.length; i++) {
- sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));
- }
- //解析字符串
- String[] strs = sb.toString().trim().split("\\+");
- double weight = 0;
- for (int j = 0; j < strs.length; j++) {
- if (strs[j].trim().length() >= 6) {
- weight = Double.parseDouble(strs[j].trim().substring(0, 6)) / 10;
- //发送数据
- sendMessageToAll(String.valueOf(weight));
- break;
- }
- }
- }
-
- /**
- * 解析字符串 方法3
- *
- * @param bytes 获取的字节码
- */
- private void parsingString3(byte[] bytes) {
- StringBuffer sb = new StringBuffer();
- //将ASCII码转成字符串
- for (int i = 0; i < bytes.length; i++) {
- sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));
- }
-
- // logger.info("sb:" + sb.toString());
- sb.reverse();
-
- //解析字符串
- String[] strs = sb.toString().trim().split("\\=");
- double weight = 0;
- for (int j = 0; j < strs.length; j++) {
- if (strs[j].trim().length() >= 6) {
- weight = Double.parseDouble(strs[j].trim());
- //发送数据
- sendMessageToAll(String.valueOf(weight));
- break;
- }
- }
- }
-
- /**
- * 解析字符串 方法3
- *
- * @param bytes 获取的字节码
- */
- private void parsingString4(byte[] bytes) {
- StringBuffer sb = new StringBuffer();
- //将ASCII码转成字符串
- for (int i = 0; i < bytes.length; i++) {
- sb.append((char) Integer.parseInt(String.valueOf(bytes[i])));
- }
-
- // logger.info("sb:" + sb.reverse());
- //字符串反转
- sb.reverse();
-
- //解析字符串
- String[] strs = sb.toString().trim().split("\\=");
- int weight = 0;
- for (int j = 0; j < strs.length; j++) {
- if (strs[j].trim().length() >= 6) {
- weight = Integer.parseInt(strs[j].trim().substring(0, 6));
- //发送数据
- sendMessageToAll(String.valueOf(weight));
- break;
- }
- }
- }
-
- /**
- * 接受消息
- *
- * @param message
- * @param session
- */
- @OnMessage
- public void onMessage(String message, Session session) {
- logger.info("收到客户端{}消息:{}", session.getId(), message);
- try {
- this.sendMessage(message);
- } catch (Exception e) {
- logger.error(e.toString());
- }
- }
-
- /**
- * 处理错误
- *
- * @param error
- * @param session
- */
- @OnError
- public void onError(Throwable error, Session session) {
- logger.info("发生错误{},{}", session.getId(), error.getMessage());
- }
-
- /**
- * 处理连接关闭
- */
- @OnClose
- public void onClose() {
- webSocketMap.remove(this.session.getId());
- reduceCount();
- logger.info("连接关闭:{}", this.session.getId());
-
- //连接关闭后关闭串口,下一次打开连接重新监听串口
- if (serialPort != null) {
- SerialPortUtil.closePort(serialPort);
- serialPort = null;
- }
- }
-
- /**
- * 群发消息
- *
- * @param message
- */
- public void sendMessageToAll(String message) {
- for (int i = 0; i < webSocketMap.size(); i++) {
- try {
- // logger.info("session:id=" + session.getId());
- this.session.getBasicRemote().sendText(message);
- } catch (IOException e) {
- logger.error(e.getMessage());
- }
- }
- }
-
- /**
- * 发送消息
- *
- * @param message
- * @throws IOException
- */
- public void sendMessage(String message) throws IOException {
- // logger.info("session:id=" + session.getId());
- this.session.getBasicRemote().sendText(message);
- }
-
- //广播消息
- public static void broadcast() {
- PoundWebSocket.webSocketMap.forEach((k, v) -> {
- try {
- v.sendMessage("这是一条测试广播");
- } catch (Exception e) {
- }
- });
- }
-
- //获取在线连接数目
- public static int getCount() {
- return count;
- }
-
- //操作count,使用synchronized确保线程安全
- public static synchronized void addCount() {
- PoundWebSocket.count++;
- }
-
- public static synchronized void reduceCount() {
- PoundWebSocket.count--;
- }
- }
作者:小土豆哥哥
链接:https://www.jianshu.com/p/cb61f797ffc1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。