光大DVR模块串口通信协议开发总结

之前我写了如何使用串口发送和接收数据,但这只是最原始的一步,下面分享一下我开发基于广大DVR串口通信协议的过程。
概述:
1、每一帧的协议数据必须要是完整的才能用,主要是通过冗余校验位来检测。校验位放在每一帧数据的最后面,它的值是除了它自己之外前面所有数据的总和。每一帧数据的协议头始终是aa开头。
2、广大DVR串口协议要求主机系统每秒都要发送同步状态的请求给到DVR模块,于是在应用必须启动一个定时器来不断发送请求命令,我使用的是Handler来不断循环。此功能号是0x20。
3、一般的回复的数据只有一帧,但是DVR回放列表的数据,却会有6条数据。系统不断从串口读取DVR模块的数据,但是不是每一次都可以读取到完整的数据,而且有时候一次性读取出来的数据还不止一帧数据。大多数情况我们是处理完一条数据就丢弃掉一条数据的信息,但是读取到列表信息的时候,我们需要把列表信息存起来并共同显示到界面。因此我们要做一定的缓存和批量处理的算法。
4、由于处理的数据比较多,缓存buffer又是一个数组,不能处理一点前面的数据,就做一次移除和重新排列,因此使用索引指针的方式来标定数据处理到什么地方了。

代码详解:
1、检验校验位的算法:

private boolean isAppendData(byte[] buffer, int size) {
        byte sum = 0;

        for(int i = 0; i < buffer.length - 1; ++i) {
            sum += buffer[i];
        }

        return !Integer.toHexString(sum & 255).equals(Integer.toHexString(buffer[size - 1] & 255));
    }

返回true代表需要追加,也就是没有检验成功,需要缓存数据。

2、数据接收:

 private byte[] mBufferData = new byte[512];   //缓存buffer
 private int mBufferSumLength = 0;                //缓存中数据的长度
 public void setData(byte[] buffer, int size) {
        boolean isAppend = this.isAppendData(buffer, size);
        if(isAppend) {
            if(this.mBufferSumLength + size < 512) {
                /**
                *拷贝数据到缓存buffer中
                */
                System.arraycopy(buffer, 0, this.mBufferData, this.mBufferSumLength, size);
                 
                 /**
                 *缓存长度增加
                 */
                this.mBufferSumLength += size;
                
                /**
                *这里表示是0x20数据的反馈,且刚好是一帧的数据。这里是为了快速响应每秒同步状态的数据
                *因为这条协议中包含了dvr录制或者回放状态,还有录制或者回放的时间更新
                */
                if(this.mBufferData[4] == 32 && this.mBufferSumLength == 14) {
                    this.dealSingleData();
                    return;
                }

                this.dealBufferDataAndResult(false);
            } else {
                this.dealBufferDataAndResult(true);
            }
        } else {
        	/**
        	*读取的这帧数据是完整的,直接处理,为了防止其他情况发生,需要去检查一下缓存buffer数据
        	*/
            this.dealBufferDataAndResult(true);
            this.notifyByteBufferListener(buffer, size);
        }

    }

3、buffer数据的处理算法

private List<byte[]> mByteList = new ArrayList();    //处理多条数据的集合
int index = 0; //buffer中数据处理的索引,表述数据处理到什么地方了
/**
*true表示是buffer已经溢出的情况,强行清空buffer数据
*/
private void dealBufferDataAndResult(boolean isForceClear) {
        this.mByteList.clear();

		/**
		*必须保证每一帧数据都是从aa开始的
		*/
        String indexTheLastOne;
        while(this.index < this.mBufferSumLength) {
            indexTheLastOne = Integer.toHexString(this.mBufferData[this.index] & 255);
            if("aa".equals(indexTheLastOne)) {
                break;
            }
            ++this.index;
        }

		/**
		*首先保证要处理的数据的索引比buffer存在的数据的总长度小
		*虽然现在处理的数据为aa,但是有可能缓存后面已经没有数据,防止不必要的计算
		*/
        while(this.index < this.mBufferSumLength && this.mBufferData[this.index + 3] != 0) {
            indexTheLastOne = Integer.toHexString(this.mBufferData[this.index + 1] & 255);
            String indexTheLastTwo = Integer.toHexString(this.mBufferData[this.index + 2] & 255);
            /**
            *这里继续判断协议的可用性,必须符合下面两个的判断,才能说明这个aa开头的数据是一条协议头,
            *而不是前面命令中遗留的aa数据
            */            
            if(!"4d".equals(indexTheLastOne) || !"44".equals(indexTheLastTwo)) {
                break;
            }
			
			/**
			*这条数据的长度
			*/
            int lengthValue = this.mBufferData[this.index + 3];
            
            //拷贝出这条数据并再次检验校验位
            byte[] tempArr = new byte[lengthValue];
            System.arraycopy(this.mBufferData, this.index, tempArr, 0, lengthValue);
            boolean isnotPass = this.isAppendData(tempArr, lengthValue);
            if(isnotPass) {
                break;
            }

			/**
			*校验通过,则把这条完整的协议数据放到list中,在循环检查完整个buffer之后,
			*把这个list里的数据回调给监听接口
			*/
            this.mByteList.add(tempArr);

			/**
			*处理完一条数据,索引增加
			*/
            this.index += lengthValue;
            Log.i("tf", "cycleone");
        }

        if(this.mByteList.size() > 0) {
            this.notifyByteListListener(this.mByteList);
        }

		/**
		*如果是处理的数据下标已经和整个长度一样,或者是强制清空的,那么就需要清空整个缓存buffer
		*/
        if(this.index == this.mBufferSumLength || isForceClear) {
            this.clearBufferData();
        }

    }

4、处理单条buffer数据

 private void dealSingleData() {
        int lengthValue = this.mBufferData[this.index + 3];
        byte[] tempArr = new byte[lengthValue];
        System.arraycopy(this.mBufferData, this.index, tempArr, 0, lengthValue);
        this.notifyByteBufferListener(tempArr, lengthValue);
        this.clearBufferData();
    }

5、清空buffer和标记

private void clearBufferData() {
        for(int i = 0; i < this.mBufferData.length; ++i) {
            this.mBufferData[i] = 0;
        }

        this.mBufferSumLength = 0;
        this.index = 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值