协议的定义和实现

      最近三个月的时间,做了几个小的项目,或者说是任务吧,都涉及到了协议的实现。也参与了协议的制定,在这里就先说说协议的实现吧。一开始做个是给出了已经实现的协议,我们就是要在这个协议上完成开发。先看一下协议的部分吧~。   

      

数据帧头
x串口通道数据
y串口通道数据
4byte
N byte
M byte
 
 

数据帧头定义

控制字
当前ip包中承载的实际
串口数据通道数
数据包累加循环计数
1byte
1 byte
2 byte
00(H)
0~64
0~65535

 
 
某X 或 Y串口通道数据:

节点标识2
节点表识1
串口通道号
保留字节
承载有效数据长度N(低位)
承载有效数据长度N(高位)
data
1byte
1 byte
1 byte
1 byte
1 byte
1 byte
N x byte
00
0~64
1~8
00
xx
xx
0~65535
         根据对协议的分析,主要将整个数据看作一个对象,然后下面再分成小的对象.主要设计了以下几个对象:数据包MsgPacket和串口通道数据ChannelData.

          先看MsgPacket的实现:

         

package comm;



import java.nio.ByteBuffer;

import java.util.Date;



public class MsgPacket {

	private int packetId;

	private static final int MSGPACKET_LENGTH= 300; //设定每个包传输数据的最大长度

	

	private ChannelData[] channelData;

	private byte[] packetData; //消息包的数据字节信息

	/**

	 * 根据输入的信息构造消息包,并将信息进行编码,用于数据的发送

	 * @param packetId 当前数据包的循环累计计数,即包标识

	 * @param channelData 当前数据包中的串口通道数据信息

	 */

	public MsgPacket(int packetId, ChannelData[] channelData){

		this.packetId= packetId;

		

		byte CONTROL_HEAD= 0x00;

		byte CHANNEL_SUM= (byte)channelData.length;

		byte[] PACKET_ID= getPacketId(packetId);

		

		ByteBuffer dataBuffer= ByteBuffer.allocate(MSGPACKET_LENGTH); 

		dataBuffer.put(CONTROL_HEAD); //填加数据帧头控制字

		dataBuffer.put(CHANNEL_SUM); //填加实际负载的串口通道数

		dataBuffer.put(PACKET_ID); //填加当前包的循环累计计数

		

		for(int i= 0; i< CHANNEL_SUM; i++){

			dataBuffer.put(channelData[i].getMsgData()); //填加串口通道数据

		}

		dataBuffer.flip();

		

		packetData= new byte[dataBuffer.limit()];

		dataBuffer.get(packetData); //将串口通道数据信息放入字节数组

		

	}

	

	/**

	 * 使用接收到的字节数组构造消息包,用于数据的解析

	 * @param msg

	 */

	public MsgPacket(byte[] msg){

		System.out.println(new Date());

		byte CONTROL_HEAD= msg[0];

		System.out.println("数据控制头信息: "+ CONTROL_HEAD);

		byte CHANNEL_SUM= msg[1];

		int PACKET_ID= 	byte2int(msg[2])+ byte2int(msg[3])* 256; //通过表示数据包累加计数的两位确定数据包标识

		System.out.println("当前数据包标识: "+ PACKET_ID);

		

		channelData= new ChannelData[CHANNEL_SUM];

		

		int position= 4; //串口通道数据的起始位置

		int data_sum= 0; //存放串口通道数据长度

		for(int i= 1; i<= CHANNEL_SUM; i++){

			int length= byte2int(msg[position+ 4])+ byte2int(msg[position+ 5])* 256;

			

			ByteBuffer dataBuffer= ByteBuffer.allocate(length+ 6); //将当前通道数据存入字节缓冲区

			for(int j= 0; j< dataBuffer.limit(); j++){

				dataBuffer.put(msg[position+ j]);

			}

			dataBuffer.flip();

			byte[] data= new byte[length+ 6]; //创建字节数组存放串口通道数据信息

//			dataBuffer.get(data); //将字节缓冲区信息放入该数组

			for(int j= 0; j< length+ 6; j++){

				data[j]= dataBuffer.get(j);

			}

			

			ChannelData channel= new ChannelData(data); //将串口通道数据信息组成串口通道数据对象

			channelData[i-1]= channel; //将该对象放入对象数组中

			

			data_sum+= length; //计算串口通道数据信息的长度

			position+= length+ 6* i; //计算下一个串口通道数据的起始位置

		}

	}

	

	

	/**

	 * 将字节数据转换成整型数据

	 * @param value

	 * @return

	 */

	public int byte2int(byte value){

		return value>=0? value: value+256;

	}

	

	/**

	 * 获得当前数据包循环累计计数的字节表示数组

	 * @param id

	 * @return

	 */

	public byte[] getPacketId(int id){

		byte[] packetId= new byte[2];

		if(id< 256){

			packetId[0]= (byte)id; //低位在前,高位在后

			packetId[1]= 0;

		}else if(id> 256){

			packetId[0]= (byte)(id& 0x00ff);

			packetId[1]= (byte)((id& 0xff00)>>>8);

		}

		return packetId;

	}

	

	/**

	 * 返回当前数据包的循环累计计数

	 * @return

	 */

	public int getPacketId() {

		return packetId;

	}



	/**

	 * 返回消息包发送数据信息的字节数组

	 * @return

	 */

	public byte[] getPacketData() {

		return packetData;

	}



	/**

	 * 返回消息包的串口通道数据信息数组

	 * @return

	 */

	public ChannelData[] getChannelData() {

		return channelData;

	}

	

	



}

然后再看看ChannelData的实现:

 

package comm;



import java.nio.ByteBuffer;



public class ChannelData {

	private int nodeID; //确定设备分布的基站编号

	private byte channelID;

	private static final byte CHANNEL_LENGTH= 100; //设置串口通道数据最大发送数据长度

	

	private final byte RESERVE= 0X00;

	private int length= 0; //存储串口通道数据信息的有效数据长度

	private byte[] data; //存储串口通道数据信息

	private String msg;  //返回串口通道数据信息的字符串

	

	/**

	 * 根据接收的字节数组创建串口通道数据信息

	 * @param data

	 */

	public ChannelData(byte[] data){

		this.data= data;

		

		this.nodeID= byte2int(data[0])+ byte2int(data[1])* 256;

		this.channelID= data[2];

		this.length= byte2int(data[4])+ byte2int(data[5])* 256;

		

		StringBuffer strBuffer= new StringBuffer();

		for(int i= 6; i< length+ 6; i++){

			String value;

			if(data[i]>= 16){

				value= Integer.toHexString(data[i]).toUpperCase();

			}else if(data[i]>= 0){

				value= "0".concat(Integer.toHexString(data[i])).toUpperCase();

			}else{

				value= Integer.toHexString(data[i]).substring(6).toUpperCase(); //当数据小于0时转换成十六进制显示时取后两位数据位,忽略符号位

			}

			

			

			strBuffer.append(value+ " ");

		} 

		this.msg= strBuffer.toString();

	}

	

	/**

	 * 根据输入发送数据创建串口通道数据

	 * @param node

	 * @param channelID

	 * @param codingData 发送数据信息编码后的字节数组

	 */

	public ChannelData(int nodeID, byte channelID, byte[] codingData){

		this.nodeID= (byte)nodeID;

		this.channelID= channelID;



		this.length= codingData.length;

		

		ByteBuffer byteBuffer= ByteBuffer.allocate(CHANNEL_LENGTH);

		byteBuffer.put(int2byte(nodeID)); //填加节点标识

		byteBuffer.put(channelID); //填加穿口通道号

		byteBuffer.put(RESERVE); //填加保留字节

		byteBuffer.put(int2byte(codingData.length)); //填加承载有效数据长度

		

		byteBuffer.put(codingData); //将发送数据信息放入缓冲区

		byteBuffer.flip();

		

		data= new byte[byteBuffer.limit()];

		byteBuffer.get(data); //将串口通道数据信息放入字节数组

	}

	

	/**

	 * 将字节数据转换成整型数据

	 * @param value

	 * @return

	 */

	public int byte2int(byte value){

		return value>=0? value: value+256;

	}

	

	/**

	 * 将INT数据类型转换成字节数组

	 * @param id

	 * @return

	 */

	public byte[] int2byte(int id){

		byte[] channelId= new byte[2];

		if(id< 256){

			channelId[0]= (byte)id;

			channelId[1]= 0;

		}else if(id> 256){

			channelId[0]= (byte)(id& 0x00ff); //低位在前,高位在后

			channelId[1]= (byte)((id& 0xff00)>>>8);

		}

		return channelId;

	}



	/**

	 * 返回发送数据信息的串口通道标识

	 * @return

	 */

	public int getNodeID() {

		return nodeID;

	}



	/**

	 * 返回发送数据信息的串口通道标识

	 * @return

	 */

	public byte getChannelID() {

		return channelID;

	}



	/**

	 * 返回发送数据信息的长度,去掉数据控制信息

	 * @return

	 */

	public int getLength() {

		return length;

	}



	/**

	 * 获得串口通道数据信息的字符串表示

	 * @return

	 */

	public String getMsg() {

		return msg;

	}



	/**

	 * 返回表示串口通道数据信息的字节数组

	 * @return

	 */

	public byte[] getMsgData() {

		return data;

	}



}
     对于协议个部分,无非就是对数据的封装和解析,在对数据进行封装时,我主要采取使用参数构造对象,然后对参数按协议进行封装.至于对协议的解析,也是将字节数组作为参数构造对象,然后通过
调用该对象的方法就可以得到数据信息了~~
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值