参考
Netty集成串口RXTX编程,为什么过时了?
Java版本
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)
RXTX版本
# 官网 http://rxtx.qbang.org/wiki/index.php/Download
# 版本 rxtx-2.2pre1-bins
POM依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
</dependencies>
Com 配置类封装
package com.yushanma.config;
import io.netty.channel.rxtx.RxtxChannelConfig;
import lombok.Data;
/**
* desc
*
* @author Yushanma
* @since 2023/6/4 17:20
*/
@Data
public final class ComConfig {
/**
* 串口名称,以COM开头(COM0、COM1、COM2等等)
*/
private String serialPortName;
/**
* 波特率, 默认:9600
*/
private int baudRate = 9600;
/**
* 数据位 默认8位
* 可以设置的值:SerialPort.DATABITS_5、SerialPort.DATABITS_6、SerialPort.DATABITS_7、SerialPort.DATABITS_8
*/
private RxtxChannelConfig.Databits dataBits = RxtxChannelConfig.Databits.DATABITS_8;
/**
* 停止位
* 可以设置的值:SerialPort.STOPBITS_1、SerialPort.STOPBITS_2、SerialPort.STOPBITS_1_5
*/
private RxtxChannelConfig.Stopbits stopBits = RxtxChannelConfig.Stopbits.STOPBITS_1;
/**
* 校验位
* 可以设置的值:SerialPort.PARITY_NONE、SerialPort.PARITY_ODD、SerialPort.PARITY_EVEN、SerialPort.PARITY_MARK、SerialPort.PARITY_SPACE
*/
private RxtxChannelConfig.Paritybit parity = RxtxChannelConfig.Paritybit.NONE;
}
字节编解码工具
package com.yushanma.utils;
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
/**
* 解码器
*
* @author Yushanma
* @since 2023/6/4 17:17
*/
public class ByteArrayDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 标记一下当前的 readIndex 的位置
in.markReaderIndex();
int dataLength = in.readableBytes();
byte[] array = new byte[dataLength];
in.readBytes(array, 0, dataLength);
if(array.length > 0){
out.add(array);
}
}
}
package com.yushanma.utils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* 编码器
*
* @author Yushanma
* @since 2023/6/4 17:18
*/
public class ByteArrayEncoder extends MessageToByteEncoder<byte[]> {
@Override
protected void encode(ChannelHandlerContext ctx, byte[] msg, ByteBuf out) throws Exception {
// 消息体,包含我们要发送的数据
out.writeBytes(msg);
}
}
Channel 事件处理器
package com.yushanma.handler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.ReferenceCountUtil;
import java.time.LocalDateTime;
/**
* Channel 事件处理器
* 需要处理什么事件就重写 SimpleChannelInboundHandler 中对应的方法
* @author Yushanma
* @since 2023/6/4 17:19
*/
@ChannelHandler.Sharable
public class RxtxHandler extends SimpleChannelInboundHandler<byte[]> {
/**
* 当 COM 口接收到数据时
* 根据不同的进制对数据包进行解码
* 然后执行对应业务逻辑
* @param ctx 上下文
* @param msg 接收到的数据包
* @throws Exception 异常
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, byte[] msg) throws Exception {
// 十六进制发送编解码
int dataLength = msg.length;
ByteBuf buf = Unpooled.buffer(dataLength);
buf.writeBytes(msg);
System.out.println(LocalDateTime.now() + "接收到:");
while(buf.isReadable()){
System.out.print(buf.readByte() + " ");
}
System.out.println();
// 释放资源
ReferenceCountUtil.release(msg);
}
}
启动类封装
package com.yushanma.server;
import com.yushanma.config.ComConfig;
import com.yushanma.handler.RxtxHandler;
import com.yushanma.utils.ByteArrayDecoder;
import com.yushanma.utils.ByteArrayEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.rxtx.RxtxChannel;
import io.netty.channel.rxtx.RxtxDeviceAddress;
import io.netty.util.concurrent.GenericFutureListener;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
/**
* desc
*
* @author Yushanma
* @since 2023/6/4 17:23
*/
public class RxtxServer {
private RxtxChannel channel;
private ComConfig config;
public RxtxServer(ComConfig config) {
this.config = config;
}
public void createRxtx() throws Exception {
// 串口使用阻塞io
EventLoopGroup group = new OioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channelFactory(() -> {
RxtxChannel rxtxChannel = new RxtxChannel();
rxtxChannel.config()
.setBaudrate(config.getBaudRate()) // 波特率
.setDatabits(config.getDataBits()) // 数据位
.setParitybit(config.getParity()) // 校验位
.setStopbits(config.getStopBits()); // 停止位
return rxtxChannel;
})
.handler(new ChannelInitializer<RxtxChannel>() {
@Override
protected void initChannel(RxtxChannel rxtxChannel) {
rxtxChannel.pipeline().addLast(
// 十六进制形式发送编解码
new ByteArrayDecoder(),
new ByteArrayEncoder(),
new RxtxHandler()
);
}
});
ChannelFuture f = bootstrap.connect(new RxtxDeviceAddress(config.getSerialPortName())).sync();
f.addListener(connectedListener);
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
// 连接监听
GenericFutureListener<ChannelFuture> connectedListener = (ChannelFuture f) -> {
final EventLoop eventLoop = f.channel().eventLoop();
if (!f.isSuccess()) {
System.out.println("连接失败");
} else {
channel = (RxtxChannel) f.channel();
System.out.println("连接成功");
sendData();
}
};
/**
* 发送数据
*/
public void sendData() {
// 十六机制形式发送
ByteBuf buf = Unpooled.buffer(2);
buf.writeByte(3);
buf.writeByte(2);
channel.writeAndFlush(buf.array());
// 文本形式发送
//channel.writeAndFlush("2");
}
public void start() {
CompletableFuture.runAsync(() -> {
try {
// 阻塞的函数
createRxtx();
} catch (Exception e) {
e.printStackTrace();
}
}, Executors.newSingleThreadExecutor());//不传默认使用ForkJoinPool,都是守护线程
}
public static void main(String[] args) {
// 串口连接服务类
ComConfig comConfig = new ComConfig();
comConfig.setSerialPortName("COM1");
comConfig.setBaudRate(9600);
RxtxServer rxtxServer = new RxtxServer(comConfig);
rxtxServer.start();
try {
// 连接串口需要一点时间,这里稍微等待一下
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 发送数据
rxtxServer.sendData();
}
}
测试效果
这里注意,因为解码是按照十六进制解码,所以需要以“十六进制发送”,“十六进制显示”。