后来才得知,还需要将数据上传到上位机。大概就是别人的主机,通过串口发命令给我们的主机,根据接收到命令,将相应的数据返回给上位机。同样需要通过modbus协议的rtu来通信。
这里附上一个博客可以作为参考,https://blog.csdn.net/lsh159357/article/details/84936294
这个博客是串口通信,也用modbus协议,不过不是rtu,而是tcp通信的。不过也可以借鉴。
可以将其中ModbusFactory 的 createModbusSlaveTCP方法,改用createRtuSlave方法来创建rtu的slave端,存储数据一样的。如下:
String commPortId = "COM2";
int baudRate = 9600;
int flowControlIn = 0;
int flowControlOut = 0;
int dataBits = 8;
int stopBits = 1;
int parity = 0;
SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl(commPortId, baudRate, flowControlIn, flowControlOut, dataBits, stopBits, parity);
ModbusFactory modbusFactory = new ModbusFactory();
final ModbusSlaveSet listener = modbusFactory.createRtuSlave(wrapper);
不过,毕竟是人家写的东西,始终会有些不适用的地方。比如,每个寄存器,只能存储一个整数,不能存小数(这也很正常,通常都 用两个寄存器来存小数)。再比如,不能存储一个字节的boolean类型数据。
所以有得研究。
其实,终究还是对这个太陌生了。上一篇不是讲过rxtxComm是对串口进行读写操作的吗,直接操作呗。于是就动手。其实代码和前一篇差不多。前一篇是需要自己发送请求命令,然后对接收到的传感器数据进行解析。而这里,只需要接收上位机的命令,然后整理报文,将相应的数据返回 回去即可。 使用netty+rxtxComm,代码如下:
Slave.java
public class Slave{
private String portName;//串口名
private int baudrate;//波特率
RxtxChannel channel;
List<String> data;//虚拟的寄存器,用来存数据
public Slave(String portName, int baudrate,List list) {
this.data=list;
this.portName = portName;
this.baudrate = baudrate;
}
public void run(){
try {
OioEventLoopGroup group = new OioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channelFactory(new ChannelFactory<RxtxChannel>() {
public RxtxChannel newChannel() {
return channel;
}
})
.handler(new ChannelInitializer<RxtxChannel>() {
@Override
public void initChannel(RxtxChannel ch) throws Exception {
ch.pipeline().addLast(
new PacketDecoder(),
new RxtxHandler(data)
);
}
});
channel = new RxtxChannel();
channel.config().setBaudrate(baudrate);
channel.config().setDatabits(RxtxChannelConfig.Databits.DATABITS_8);
channel.config().setParitybit(RxtxChannelConfig.Paritybit.EVEN);
channel.config().setStopbits(RxtxChannelConfig.Stopbits.STOPBITS_1);
ChannelFuture future = b.connect(new RxtxDeviceAddress(portName)).sync();
System.out.println("rxtx启动成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序入口
public static void main(String[] args) {
Slave slave=new Slave();
slave.run();
slave.request();
}
}
RxtxHandler.java
public class RxtxHandler extends ChannelInboundHandlerAdapter {
private List<String> data;//虚拟的寄存器,用于存数据。这里存的是16进制的字符串,这样可以存任意类型的数据
public RxtxHandler(List<String> data) {
this.data = data;
}
/**
* 客户端接收到数据的回调
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
if(msg instanceof String ){
String packet = (String)msg;
System.out.println("获取主机请求:"+packet);
int starAddr = InputCommandUtil.getStarAddrInt(packet);
int dataCountInt = InputCommandUtil.getReqDataCountInt(packet);
//获取相应命令相应的寄存器的数据
List<String> strings =ListUtil.subList(data,starAddr,starAddr + dataCountInt);
//组装返回的命令,包括报文头,长度,crc
String resCommand = OutputCommandUtil.packet(strings);
writeAndFlush(ctx.channel(),resCommand);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
private void writeAndFlush(Channel channel,String hexString) {
byte[] bytes = ByteUtil.hexStringToBytes(hexString);
ByteBuf buffer = channel.alloc().buffer();
ByteBuf byteBuf = buffer.writeBytes(bytes);
channel.writeAndFlush(byteBuf);
}
PacketDecoder .java
public class PacketDecoder extends ByteToMessageDecoder {
StringBuilder sb=new StringBuilder();
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {
byte[] read =new byte[in.readableBytes()];
in.readBytes(read);
String packet = ByteUtil.BinaryToHexString(read).toUpperCase();
//System.out.println("ByteToMessageDecoder "+packet);
sb.append(packet);
if (!InputCommandUtil.isMasterCmd(packet) && !InputCommandUtil.isSlaveCmd(packet)) {
return;
}
out.add(sb.toString());
sb.setLength(0);
}
}