第一次提交
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
|
||||
****.约定报文格式如下*****
|
||||
modbus-rtu报文示例:
|
||||
1. 上报: 010302030578B7
|
||||
01 03 02 0305 78B7
|
||||
设备地址 命令号 返回数据字节数 数据 CRC校验
|
||||
|
||||
2. 下发: 0106010100151839
|
||||
01 06 0101 0015 1839
|
||||
设备地址 命令号 寄存器地址 数据位 CRC校验
|
||||
|
||||
1.设备主动上报数据组成:
|
||||
上报的指令数据
|
||||
FFAA0001010302030578B7
|
||||
FFAA 0001 010302030578B7
|
||||
包头 起始寄存器 数据包
|
||||
|
||||
2.服务下发数据组成
|
||||
下发的指令数据
|
||||
FFDDa690351586788884480106010100151839
|
||||
FFDD a69035158678888448 0106010100151839
|
||||
固定报文头 9字节消息ID 数据包
|
||||
|
||||
3.设备应答服务下发数据组成
|
||||
下发的指令数据
|
||||
FFDDa690351586788884480106010100151839
|
||||
FFDD a69035158678888448 0106010100151839
|
||||
固定报文头 9字节消息ID 数据包
|
@@ -0,0 +1,87 @@
|
||||
package com.fastbee.pakModbus.codec;
|
||||
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.gateway.CRC16Utils;
|
||||
import com.fastbee.pakModbus.model.PakModbusRtu;
|
||||
import com.fastbee.protocol.WModelManager;
|
||||
import com.fastbee.protocol.base.model.ActiveModel;
|
||||
import com.fastbee.protocol.util.ArrayMap;
|
||||
import com.fastbee.protocol.util.ExplainUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* modbus-rtu协议解码器
|
||||
* @author bill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@NoArgsConstructor
|
||||
public class ModbusRtuPakDecoder {
|
||||
|
||||
@Autowired
|
||||
private WModelManager modelManager;
|
||||
private ArrayMap<ActiveModel> headerSchemaMap;
|
||||
|
||||
public ModbusRtuPakDecoder(String...basePackages) {
|
||||
this.modelManager = new WModelManager(basePackages);
|
||||
this.headerSchemaMap = this.modelManager.getActiveMap(PakModbusRtu.class);
|
||||
}
|
||||
|
||||
public PakModbusRtu decode(ByteBuf in){
|
||||
return decode(in,null);
|
||||
}
|
||||
|
||||
public PakModbusRtu decode(ByteBuf in, ExplainUtils explain){
|
||||
this.build();
|
||||
ByteBuf copy = in.duplicate();
|
||||
byte[] bytes = new byte[in.writerIndex()];
|
||||
copy.readBytes(bytes);
|
||||
verify(bytes);
|
||||
ActiveModel<PakModbusRtu> activeModel = headerSchemaMap.get(0);
|
||||
PakModbusRtu message = new PakModbusRtu();
|
||||
message.setPayload(in);
|
||||
message.setVerified(false);
|
||||
activeModel.mergeFrom(in,message,explain);
|
||||
log.info("=>解析:[{}]",message);
|
||||
return message;
|
||||
}
|
||||
|
||||
public PakModbusRtu decodeMessage(ByteBuf in, int version){
|
||||
this.build();
|
||||
ByteBuf copy = in.duplicate();
|
||||
byte[] bytes = new byte[in.writerIndex()];
|
||||
copy.readBytes(bytes);
|
||||
ActiveModel<PakModbusRtu> activeModel = headerSchemaMap.get(version);
|
||||
PakModbusRtu message = new PakModbusRtu();
|
||||
message.setPayload(in);
|
||||
message.setVerified(false);
|
||||
activeModel.mergeFrom(in,message,null);
|
||||
log.info("=>解析:[{}]",message);
|
||||
return message;
|
||||
}
|
||||
|
||||
private void verify(byte[] source){
|
||||
byte[] checkBytes = {source[source.length - 3],source[source.length -2]};
|
||||
byte[] sourceCheck = ArrayUtils.subarray(source,4,source.length -3);
|
||||
String crc = CRC16Utils.getCRC(sourceCheck);
|
||||
if (!crc.equalsIgnoreCase(ByteBufUtil.hexDump(checkBytes))){
|
||||
log.warn("=>CRC校验异常,报文={}",ByteBufUtil.hexDump(source));
|
||||
throw new ServiceException("CRC校验异常");
|
||||
}
|
||||
}
|
||||
|
||||
private void build(){
|
||||
if (this.headerSchemaMap == null) {
|
||||
this.headerSchemaMap = this.modelManager.getActiveMap(PakModbusRtu.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package com.fastbee.pakModbus.codec;
|
||||
|
||||
import com.fastbee.common.core.protocol.modbus.ModbusCode;
|
||||
import com.fastbee.pakModbus.model.PakModbusRtu;
|
||||
import com.fastbee.protocol.WModelManager;
|
||||
import com.fastbee.protocol.base.model.ActiveModel;
|
||||
import com.fastbee.protocol.util.ArrayMap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author gsb
|
||||
* @date 2022/11/15 11:34
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ModbusRtuPakEncoder {
|
||||
|
||||
private static final ByteBufAllocator ALLOC = PooledByteBufAllocator.DEFAULT;
|
||||
|
||||
@Autowired
|
||||
private WModelManager modelManager;
|
||||
private ArrayMap<ActiveModel> headerSchemaMap;
|
||||
|
||||
public ModbusRtuPakEncoder(String...basePackages) {
|
||||
this.modelManager = new WModelManager(basePackages);
|
||||
this.headerSchemaMap = this.modelManager.getActiveMap(PakModbusRtu.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 组装下发指令
|
||||
* @param pakModbusRtu
|
||||
* @return
|
||||
*/
|
||||
public ByteBuf encode(PakModbusRtu pakModbusRtu){
|
||||
this.build();
|
||||
ByteBuf buf = ALLOC.buffer();
|
||||
// 下发读
|
||||
int version = 1;
|
||||
if (pakModbusRtu.getCode() == ModbusCode.Write05.getCode() || pakModbusRtu.getCode() == ModbusCode.Write06.getCode()) {
|
||||
// 下发写单个
|
||||
version = 2;
|
||||
} else if (pakModbusRtu.getCode() == ModbusCode.Write10.getCode()) {
|
||||
// 下发写多个
|
||||
version = 3;
|
||||
}else if (pakModbusRtu.getCode() == ModbusCode.Write0F.getCode()){
|
||||
version = 5;
|
||||
}
|
||||
ActiveModel activeModel = headerSchemaMap.get(version);
|
||||
activeModel.writeTo(buf, pakModbusRtu, null);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private void build(){
|
||||
if (this.headerSchemaMap == null) {
|
||||
this.headerSchemaMap = this.modelManager.getActiveMap(PakModbusRtu.class);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,187 @@
|
||||
package com.fastbee.pakModbus.codec;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fastbee.common.annotation.SysProtocol;
|
||||
import com.fastbee.common.constant.FastBeeConstant;
|
||||
import com.fastbee.common.core.mq.DeviceReport;
|
||||
import com.fastbee.common.core.mq.MQSendMessageBo;
|
||||
import com.fastbee.common.core.mq.message.DeviceData;
|
||||
import com.fastbee.common.core.mq.message.DeviceDownMessage;
|
||||
import com.fastbee.common.core.mq.message.FunctionCallBackBo;
|
||||
import com.fastbee.common.core.protocol.modbus.ModbusCode;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelValuesInput;
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.common.utils.gateway.CRC16Utils;
|
||||
import com.fastbee.common.utils.modbus.BitUtils;
|
||||
import com.fastbee.iot.cache.IModbusConfigCache;
|
||||
import com.fastbee.iot.domain.ModbusConfig;
|
||||
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
|
||||
import com.fastbee.pakModbus.model.PakModbusRtu;
|
||||
import com.fastbee.protocol.base.protocol.IProtocol;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 包装过的modbus-rtu协议
|
||||
*
|
||||
* @author gsb
|
||||
* @date 2022/11/15 11:16
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@SysProtocol(name = "ModbusRtu扩展自定义协议", protocolCode = FastBeeConstant.PROTOCOL.ModbusRtuPak, description = "ModbusRtu扩展自定义协议")
|
||||
public class ModbusRtuPakProtocol implements IProtocol {
|
||||
|
||||
/**
|
||||
* 1.约定报文格式如下
|
||||
* 1.设备主动上报数据组成:
|
||||
* * 上报的指令数据
|
||||
* * FFAA 0001 010302030578B7
|
||||
* * FFAA 0001 010302030578B7
|
||||
* * 包头 起始寄存器 数据包
|
||||
* <p>
|
||||
* * 数据包
|
||||
* * 01 03 02 0305 78B7
|
||||
* * 设备地址 命令号 返回数据字节数 数据 CRC校验
|
||||
* <p>
|
||||
* 2.服务下发数据组成
|
||||
* * 下发的指令数据
|
||||
* * FFDD a69035158678888448 01 06 0101 0015 1839
|
||||
* * FFDD a69035158678888448 0106010100151839
|
||||
* * 固定报文头 9字节消息ID 数据包
|
||||
* </p>
|
||||
* * 数据包
|
||||
* * 01 06 0101 0015 1839
|
||||
* * 设备地址 命令号 寄存器地址 数据位 CRC校验
|
||||
* <p>
|
||||
* 3.设备应答服务下发数据组成
|
||||
* * 下发的指令数据
|
||||
* * FFDD a69035158678888448 01 06 0101 0015 1839
|
||||
* * FFDD a69035158678888448 0106010100151839
|
||||
* * 固定报文头 9字节消息ID 数据包
|
||||
* <p>
|
||||
* * 数据包
|
||||
* * 01 06 0101 0015 1839
|
||||
* * 设备地址 命令号 寄存器地址 数据位 CRC校验
|
||||
*/
|
||||
|
||||
private final static String FFDD = "ffdd";
|
||||
|
||||
@Resource
|
||||
private ModbusRtuPakDecoder rtuPakDecoder;
|
||||
@Resource
|
||||
private ModbusRtuPakEncoder rtuPakEncoder;
|
||||
@Resource
|
||||
private IModbusConfigCache modbusConfigCache;
|
||||
|
||||
@Override
|
||||
public DeviceReport decode(DeviceData deviceData, String clientId) {
|
||||
DeviceReport report = new DeviceReport();
|
||||
ByteBuf buf = deviceData.getBuf();
|
||||
String hexDump = ByteBufUtil.hexDump(buf);
|
||||
if (hexDump.startsWith(FFDD)){
|
||||
report.setIsReply(true);
|
||||
report.setMessageId(hexDump.substring(4,22));
|
||||
report.setClientId(clientId);
|
||||
report.setProtocolCode(FastBeeConstant.PROTOCOL.ModbusRtuPak);
|
||||
return report;
|
||||
}
|
||||
PakModbusRtu message = rtuPakDecoder.decode(buf);
|
||||
List<ThingsModelSimpleItem> values = new ArrayList<>();
|
||||
short[] data = message.getData();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
int address = message.getAddress() + i;
|
||||
handleModbusDataType(deviceData.getProductId(),address+"",data[i]+"",values);
|
||||
}
|
||||
report.setClientId(clientId);
|
||||
report.setThingsModelSimpleItem(values);
|
||||
report.setSources(hexDump);
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理不同数据
|
||||
* @param productId
|
||||
* @param values
|
||||
*/
|
||||
private void handleModbusDataType(Long productId,String address,String value,List<ThingsModelSimpleItem> values){
|
||||
|
||||
int nValue = Integer.parseInt(value);
|
||||
List<ModbusConfig> modbusConfig = modbusConfigCache.getSingleModbusConfig(productId, address);
|
||||
if (CollectionUtils.isEmpty(modbusConfig)){
|
||||
log.warn("寄存器地址:{},不存在",address); return;
|
||||
}
|
||||
Map<Integer, List<ModbusConfig>> listMap = modbusConfig.stream().collect(Collectors.groupingBy(ModbusConfig::getType));
|
||||
//处理IO类型
|
||||
List<ModbusConfig> IOConfigList = listMap.get(1);
|
||||
if (!CollectionUtils.isEmpty(IOConfigList)){
|
||||
if (IOConfigList.size() > 1){
|
||||
//按位运行情况,需要将16进制转换为2进制,按位取值
|
||||
for (ModbusConfig config : IOConfigList) {
|
||||
int result = BitUtils.deter(nValue, config.getBitOrder());
|
||||
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
|
||||
simpleItem.setId(config.getIdentifier());
|
||||
//simpleItem.setSlaveId(config.getSlave());
|
||||
simpleItem.setValue(result+"");
|
||||
simpleItem.setTs(DateUtils.getNowDate());
|
||||
values.add(simpleItem);
|
||||
}
|
||||
}else {
|
||||
//普通IO取值,应该只有一个数据,将identity与address替换
|
||||
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
|
||||
simpleItem.setId(IOConfigList.get(0).getIdentifier());
|
||||
//simpleItem.setSlaveId(IOConfigList.get(0).getSlave());
|
||||
simpleItem.setValue(value);
|
||||
simpleItem.setTs(DateUtils.getNowDate());
|
||||
values.add(simpleItem);
|
||||
}
|
||||
}
|
||||
List<ModbusConfig> dataConfigList = listMap.get(2);
|
||||
if (!CollectionUtils.isEmpty(dataConfigList)){
|
||||
//普通取值,应该只有一个数据,将identity与address替换
|
||||
ThingsModelSimpleItem simpleItem = new ThingsModelSimpleItem();
|
||||
simpleItem.setId(dataConfigList.get(0).getIdentifier());
|
||||
//simpleItem.setSlaveId(dataConfigList.get(0).getSlave());
|
||||
simpleItem.setValue(value);
|
||||
simpleItem.setTs(DateUtils.getNowDate());
|
||||
values.add(simpleItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FunctionCallBackBo encode(MQSendMessageBo bo) {
|
||||
FunctionCallBackBo callBack = new FunctionCallBackBo();
|
||||
String thingsModel = bo.getThingsModel();
|
||||
ThingsModelValueItem item = JSONObject.parseObject(thingsModel, ThingsModelValueItem.class);
|
||||
ModbusConfig modbusConfig = item.getConfig();
|
||||
String value = bo.getValue();
|
||||
PakModbusRtu modbusRtu = new PakModbusRtu();
|
||||
modbusRtu.setMessageId(bo.getMessageId());
|
||||
modbusRtu.setSlaveId(modbusConfig.getSlave());
|
||||
modbusRtu.setCode(modbusConfig.getModbusCode().getCode());
|
||||
modbusRtu.setDownAdd(modbusConfig.getAddress());
|
||||
modbusRtu.setWriteData(Integer.parseInt(value));
|
||||
ByteBuf out = rtuPakEncoder.encode(modbusRtu);
|
||||
byte[] result = new byte[out.writerIndex()];
|
||||
out.readBytes(result);
|
||||
ReferenceCountUtil.release(out);
|
||||
callBack.setMessage(result);
|
||||
callBack.setSources(ByteBufUtil.hexDump(result));
|
||||
return callBack;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
package com.fastbee.pakModbus.model;
|
||||
|
||||
|
||||
import com.fastbee.protocol.util.ByteToHexUtil;
|
||||
import com.fastbee.protocol.util.IntegerToByteUtil;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* bit位数据组装
|
||||
*
|
||||
* @author gsb
|
||||
* @date 2022/5/24 11:26
|
||||
*/
|
||||
|
||||
public class CombineFactory {
|
||||
|
||||
/**
|
||||
* 是否是位值修改的物模型 0-单值single_value 1-多选multiple_bit 2-单选single_bit 3-多值multiple_value,4-单选值 single_select_value
|
||||
*
|
||||
* @param type MCU数据类型
|
||||
* @param map position:value
|
||||
* @param oldValue 最新记录的数据
|
||||
* @return 结果
|
||||
*/
|
||||
public static byte[] toBytes(int type, Map<Integer, Integer> map, Object oldValue) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return toOldBitBytes(map, oldValue);
|
||||
case 2:
|
||||
return toBitBytes(map);
|
||||
case 3:
|
||||
return toByte2Bytes(map);
|
||||
default:
|
||||
return toValueBytes(map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1-多选multiple_bit
|
||||
*
|
||||
* @param map 数据map
|
||||
* @param oldValue 原始数据值
|
||||
* @return 结果
|
||||
*/
|
||||
private static byte[] toOldBitBytes(Map<Integer, Integer> map, Object oldValue) {
|
||||
oldValue = oldValue == null ? 0 : oldValue;
|
||||
String strV = String.join("", oldValue.toString().split(","));
|
||||
int data = IntegerToByteUtil.binaryToInt(strV);
|
||||
int result = IntegerToByteUtil.bitOperationBatch(data, map);
|
||||
return IntegerToByteUtil.intToByteArr(result, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多值multiple_value
|
||||
*
|
||||
* @param map 数据
|
||||
* @return 结果
|
||||
*/
|
||||
private static byte[] toByte2Bytes(Map<Integer, Integer> map) {
|
||||
byte[] result = new byte[2];
|
||||
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
||||
if (entry.getKey() ==0){
|
||||
result[1] = (byte)entry.getValue().intValue();
|
||||
}
|
||||
if (entry.getKey() ==1){
|
||||
result[0] = (byte)entry.getValue().intValue();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2-单选single_bit
|
||||
*
|
||||
* @param map 数据值
|
||||
* @return 结果
|
||||
*/
|
||||
private static byte[] toBitBytes(Map<Integer, Integer> map) {
|
||||
if (!CollectionUtils.isEmpty(map)) {
|
||||
int result = IntegerToByteUtil.bitOperationBatch(0, map);
|
||||
return IntegerToByteUtil.intToByteArr(result, 2);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 0-单值single_value
|
||||
*
|
||||
* @param map 数据
|
||||
* @return 结果
|
||||
*/
|
||||
private static byte[] toValueBytes(Map<Integer, Integer> map) {
|
||||
if (!CollectionUtils.isEmpty(map) && map.size() == 1) {
|
||||
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
||||
return IntegerToByteUtil.intToBytes2(entry.getValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<Integer, Integer> map = new HashMap<>();
|
||||
map.put(0,0);
|
||||
map.put(1,1);
|
||||
map.put(2,0);
|
||||
//map.put(1,15); 0000001100000110
|
||||
byte[] bytes = toOldBitBytes(map,"0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1");
|
||||
byte[] bytes1 = toBitBytes(map);
|
||||
String string = ByteToHexUtil.bytesToHexString(bytes1);
|
||||
System.out.println(string);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,292 @@
|
||||
package com.fastbee.pakModbus.model;
|
||||
|
||||
import com.fastbee.common.core.protocol.Message;
|
||||
import com.fastbee.common.core.protocol.modbus.ModbusCode;
|
||||
import com.fastbee.protocol.base.annotation.Column;
|
||||
import com.fastbee.protocol.util.ToStringBuilder;
|
||||
import com.fastbee.base.session.Session;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* modbus采集方式二:dtu或模组主动轮询,变化上报,以约定报文格式进行上报
|
||||
*
|
||||
* @author gsb
|
||||
* @date 2022/12/5 16:43
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class PakModbusRtu extends Message {
|
||||
|
||||
/**
|
||||
* 1.约定报文格式如下
|
||||
* 1.设备主动上报数据组成:
|
||||
* * 上报的指令数据
|
||||
* * FFAA 0001 010302030578B7
|
||||
* * FFAA 0001 010302030578B7
|
||||
* * 包头 起始寄存器 数据包
|
||||
* <p>
|
||||
* * 数据包
|
||||
* * 01 03 02 0305 78B7
|
||||
* * 设备地址 命令号 返回数据字节数 数据 CRC校验
|
||||
* <p>
|
||||
* 2.服务下发数据组成
|
||||
* * 下发的指令数据
|
||||
* * FFDD a69035158678888448 01 06 0101 0015 1839
|
||||
* * FFDD a69035158678888448 0106010100151839
|
||||
* * 固定报文头 9字节消息ID 数据包
|
||||
* </p>
|
||||
* * 数据包
|
||||
* * 01 06 0101 0015 1839
|
||||
* * 设备地址 命令号 寄存器地址 数据位 CRC校验
|
||||
* <p>
|
||||
* 3.设备应答服务下发数据组成
|
||||
* * 下发的指令数据
|
||||
* * FFDD a69035158678888448 01 06 0101 0015 1839
|
||||
* * FFDD a69035158678888448 0106010100151839
|
||||
* * 固定报文头 9字节消息ID 数据包
|
||||
* <p>
|
||||
* * 数据包
|
||||
* * 01 06 0101 0015 1839
|
||||
* * 设备地址 命令号 寄存器地址 数据位 CRC校验
|
||||
*/
|
||||
|
||||
@Column(length = 1, version = {0x80, 0x81}, desc = "起始地址")
|
||||
protected int begin;
|
||||
@Column(length = 1, version = {0x80, 0x81}, desc = "标识位,实例设备是0x80")
|
||||
private int mId;
|
||||
@Column(length = 6, version = 0x80, desc = "MAC地址,6个字节")
|
||||
private String mac;
|
||||
@Column(length = 1, version = {0x80, 0x81}, desc = "结尾,如:7E")
|
||||
private int end;
|
||||
@Column(length = 2, desc = "固定报文头: FFDD或FFAA",version = {0,1,2,3,4,5})
|
||||
protected int start = 0xFFDD;
|
||||
@Column(length = 9,desc = "消息id",version = {1,2,3,4,5})
|
||||
protected String messageId;
|
||||
@Column(length = 2, desc = "寄存器地址" ,version = 0)
|
||||
protected int address;
|
||||
@Column(length = 1,desc = "从机地址",version = {0,1,2,3,4,5})
|
||||
protected int slaveId;
|
||||
@Column(length = 1,desc = "功能码" ,version = {0,1,2,3,4,5})
|
||||
protected int code;
|
||||
@Column(length = 2 ,desc ="下发寄存器",version = {1,2,3,4,5})
|
||||
protected int downAdd;
|
||||
@Column(length = 2,desc = "寄存器数量",version = {1,3,4,5})
|
||||
protected int count;
|
||||
@Column(length = 1,desc = "字节数",version = {3,5})
|
||||
protected int bitCount;
|
||||
@Column(totalUnit = 1,desc = "上报数据",version = {0,4})
|
||||
protected short[] data;
|
||||
@Column(length = 2, desc = "下发数据", version = 2)
|
||||
protected int writeData;
|
||||
@Column(totalUnit = 0,desc = "10下发数据",version = 3)
|
||||
protected short[] tenWriteData;
|
||||
@Column(totalUnit = 0,desc = "10下发数据",version = 5)
|
||||
protected byte[] bitData;
|
||||
/*原始的bit字符串*/
|
||||
protected String bitString;
|
||||
|
||||
|
||||
public String getBitString() {
|
||||
return bitString;
|
||||
}
|
||||
|
||||
public void setBitString(String bitString) {
|
||||
this.bitString = bitString;
|
||||
}
|
||||
|
||||
public byte[] getBitData() {
|
||||
return bitData;
|
||||
}
|
||||
|
||||
public void setBitData(byte[] bitData) {
|
||||
this.bitData = bitData;
|
||||
}
|
||||
|
||||
/**
|
||||
* crc校验
|
||||
*/
|
||||
protected boolean verified = true;
|
||||
|
||||
protected transient Session session;
|
||||
|
||||
protected transient ByteBuf payload;
|
||||
|
||||
protected transient int serialNo;
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int getBitCount() {
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
public void setBitCount(int bitCount) {
|
||||
this.bitCount = bitCount;
|
||||
}
|
||||
|
||||
public short[] getTenWriteData() {
|
||||
return tenWriteData;
|
||||
}
|
||||
|
||||
public void setTenWriteData(short[] tenWriteData) {
|
||||
this.tenWriteData = tenWriteData;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(int address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getSlaveId() {
|
||||
return slaveId;
|
||||
}
|
||||
|
||||
public void setSlaveId(int slaveId) {
|
||||
this.slaveId = slaveId;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public short[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(short[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public boolean isVerified() {
|
||||
return verified;
|
||||
}
|
||||
|
||||
public void setVerified(boolean verified) {
|
||||
this.verified = verified;
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public void setSession(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public ByteBuf getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(ByteBuf payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public int getSerialNo() {
|
||||
return serialNo;
|
||||
}
|
||||
|
||||
public void setSerialNo(int serialNo) {
|
||||
this.serialNo = serialNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageId(String messageId) {
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
public int getDownAdd() {
|
||||
return downAdd;
|
||||
}
|
||||
|
||||
public void setDownAdd(int downAdd) {
|
||||
this.downAdd = downAdd;
|
||||
}
|
||||
|
||||
public int getWriteData() {
|
||||
return writeData;
|
||||
}
|
||||
|
||||
public void setWriteData(int writeData) {
|
||||
this.writeData = writeData;
|
||||
}
|
||||
|
||||
public int getBegin() {
|
||||
return begin;
|
||||
}
|
||||
|
||||
public void setBegin(int begin) {
|
||||
this.begin = begin;
|
||||
}
|
||||
|
||||
public int getmId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public void setmId(int mId) {
|
||||
this.mId = mId;
|
||||
}
|
||||
|
||||
public String getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
public void setMac(String mac) {
|
||||
this.mac = mac;
|
||||
}
|
||||
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
protected StringBuilder toStringHead() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
String des = ModbusCode.getDes(this.code);
|
||||
sb.append(des);
|
||||
sb.append("[");
|
||||
sb.append(",slaveId[从机地址]=").append(slaveId);
|
||||
sb.append(",code[功能码]=").append(code);
|
||||
sb.append(",length[返回数据个数]").append(data==null? 0: data.length);
|
||||
sb.append(",data[上报数据]=").append(Arrays.toString(data));
|
||||
// sb.append(",count[读取寄存器个数]=").append(len);
|
||||
sb.append(",address[寄存器地址]=").append(address);
|
||||
sb.append(",writeData[下发数据]=").append(writeData);
|
||||
sb.append("]");
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.toString(toStringHead(), this, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package com.fastbee.pakModbus.test;
|
||||
|
||||
import com.fastbee.common.core.protocol.modbus.ModbusCode;
|
||||
import com.fastbee.common.utils.gateway.CRC16Utils;
|
||||
import com.fastbee.iot.util.SnowflakeIdWorker;
|
||||
import com.fastbee.pakModbus.codec.ModbusRtuPakDecoder;
|
||||
import com.fastbee.pakModbus.codec.ModbusRtuPakEncoder;
|
||||
import com.fastbee.pakModbus.model.PakModbusRtu;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
//import org.checkerframework.checker.units.qual.A;
|
||||
|
||||
/**
|
||||
* @author bill
|
||||
*/
|
||||
public class PakModbusTest {
|
||||
|
||||
private static ModbusRtuPakDecoder decoder = new ModbusRtuPakDecoder("com.fastbee.pakModbus");
|
||||
private static ModbusRtuPakEncoder encoder = new ModbusRtuPakEncoder("com.fastbee.pakModbus");
|
||||
private static SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(6);
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
/**
|
||||
* 单个解析
|
||||
*/
|
||||
String hex = "ffaa000001030400d800dafb930d";
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(hex));
|
||||
PakModbusRtu message = decoder.decode(buf);
|
||||
System.out.println("单个解析=" + message);
|
||||
buf.release();
|
||||
/**
|
||||
* 批量上报解析
|
||||
*/
|
||||
String hexMore = "FFAA00010103a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000cff039c00200000ffffffff0000006e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa0000000000000000ffc900100019001e0010001900190057000747790D";
|
||||
ByteBuf bufMore = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(hexMore));
|
||||
PakModbusRtu messageMore = decoder.decode(bufMore);
|
||||
System.out.println("批量上传报文解析=" + messageMore);
|
||||
bufMore.release();
|
||||
|
||||
PakModbusRtu modbusRtu = new PakModbusRtu();
|
||||
modbusRtu.setMessageId(snowflakeIdWorker.nextId()+"");
|
||||
modbusRtu.setSlaveId(1);
|
||||
modbusRtu.setCode(ModbusCode.Write06.getCode());
|
||||
modbusRtu.setDownAdd(1);
|
||||
modbusRtu.setWriteData(100);
|
||||
ByteBuf out = encoder.encode(modbusRtu);
|
||||
byte[] result = new byte[out.writerIndex()];
|
||||
out.readBytes(result);
|
||||
ReferenceCountUtil.release(out);
|
||||
byte[] crc = CRC16Utils.CRC(result);
|
||||
System.out.println("->下发指令:"+ ByteBufUtil.hexDump(crc));
|
||||
|
||||
// ModbusRtu read03 = new ModbusRtu();
|
||||
// read03.setSlaveId(1);
|
||||
// read03.setAddress(1);
|
||||
// read03.setCode(3);
|
||||
// read03.setCount(3);
|
||||
// ByteBuf out = encoder.encode(read03);
|
||||
// System.out.println(ByteBufUtil.hexDump(out));
|
||||
//
|
||||
// ModbusRtu write06 = new ModbusRtu();
|
||||
// write06.setSlaveId(1);
|
||||
// write06.setAddress(1);
|
||||
// write06.setCode(6);
|
||||
// write06.setWriteData(17);
|
||||
// ByteBuf writeOut = encoder.encode(write06);
|
||||
// System.out.println(ByteBufUtil.hexDump(writeOut));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user