Android开发中遇到关于Byte位运算通信协议类项目的文档解读分析
Posted Engineer-Jsp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发中遇到关于Byte位运算通信协议类项目的文档解读分析相关的知识,希望对你有一定的参考价值。
android开发中经常会遇到Byte位运算通信协议的项目,一个简单的Byte可能隐藏着极其复杂的数据,需要根据既定的协议来解析和封装。那么开发中要怎么解决这类项目呢,还是要多熟悉文档和源码。
这类项目笔者15年的时候接触过,是独立开发的。因为当初入行不到两年,所以接触的这类项目可以说是初次接触,看个文档对于那时很菜鸟的我来说简直是要了我的命,但是客户的对接工程师是个C老鸟,人也不错,我有问题就会找他帮忙,而且他也不吝赐教,这让笔者倍感欣慰。然而今天又遇到了一个这样的项目,就想着写一篇博客笔记来记录这个分析的过程,避免以后笔者或读者再遇到这类项目时无从下手。
首先笔者介绍开发中常接触到的一些位运算符号。
<<(左移)
/**
* 逻辑运算符
*
* @author Engineer-Jsp
* 运算符:<<
*/
public static void ByteCalc()
// 0x01为1的16进制,运行结果是2
System.out.println(0x01 << 1);
该段代码的意思是将1向左移1位,先将16进制的0x01转换成10进制即1,运行结果为2。
解析,先将1转换为二进制数据,然后向左(从右边开始,依次往左)位移1位,在低位处补0:
左移前:0000 0000 0000 0000 0000 0000 0000 0001
左移后:0000 0000 0000 0000 0000 0000 0000 0010
将二进制数据 0000 0000 0000 0000 0000 0000 0000 0010 转换为10进制数据,结果为2。
>>(右移)
/**
* 逻辑运算符
*
* @author Engineer-Jsp
* 运算符:>>
*/
public static void ByteCalc()
// 0x02为2的16进制,运行结果是1
System.out.println(0x02 >> 1);
该段代码的意思是将2向右移1位,先将16进制的0x02转换成10进制即2,运行结果为1。
解析(不考虑负数位移),先将2转换为二进制数据,然后向右(从左边开始,依次往右)位移1位,高位补0:
右移前:0000 0000 0000 0000 0000 0000 0000 0010
右移后:0000 0000 0000 0000 0000 0000 0000 0001
将二进制数据 0000 0000 0000 0000 0000 0000 0000 0001 转换为10进制数据,结果为1。
&(与)
规则:当相同的位上均为1时结果为1,否则为0。
/**
* 逻辑运算符
*
* @author Engineer-Jsp
* 运算符:&
*/
public static void ByteCalc()
// 0x02为2的16进制,运行结果是0
System.out.println(0x02 & 1);
该段代码的意思是将2和1进行&的位运算,先将16进制的0x02转换成10进制即2,运行结果为0。
解析,先将2转换为二进制数据,然后将1也转换为二进制数据再进行与运算:
2的二进制:0000 0000 0000 0000 0000 0000 0000 0010
1的二进制:0000 0000 0000 0000 0000 0000 0000 0001
&运算后的二进制:0000 0000 0000 0000 0000 0000 0000 0000
将二进制数据 0000 0000 0000 0000 0000 0000 0000 0000 转换为10进制数据,结果为0。
|(或)
规则:当两边操作数的位有一边为1时,结果为1,否则为0。
/**
* 逻辑运算符
*
* @author Engineer-Jsp
* 运算符:|
*/
public static void ByteCalc()
// 0x02为2的16进制,运行结果是3
System.out.println(0x02 | 1);
该段代码的意思是将2和1进行|的位运算,先将16进制的0x02转换成10进制即2,运行结果为3。
解析,先将2转换为二进制数据,然后将1也转换为二进制数据再进行或运算:
2的二进制:0000 0000 0000 0000 0000 0000 0000 0010
1的二进制:0000 0000 0000 0000 0000 0000 0000 0001
|运算后的二进制:0000 0000 0000 0000 0000 0000 0000 0011
将二进制数据 0000 0000 0000 0000 0000 0000 0000 0011 转换为10进制数据,结果为3。
^(异或)
规则:两边的位不同时,结果为1,否则为0。
/**
* 逻辑运算符
*
* @author Engineer-Jsp
* 运算符:^
*/
public static void ByteCalc()
// 0x02为2的16进制,运行结果是3
System.out.println(0x02 ^ 1);
该段代码的意思是将2和1进行^的位运算,先将16进制的0x02转换成10进制即2,运行结果为3。
解析,先将2转换为二进制数据,然后将1也转换为二进制数据再进行异或运算:
2的二进制:0000 0000 0000 0000 0000 0000 0000 0010
1的二进制:0000 0000 0000 0000 0000 0000 0000 0001
^运算后的二进制:0000 0000 0000 0000 0000 0000 0000 0011
将二进制数据 0000 0000 0000 0000 0000 0000 0000 0011 转换为10进制数据,结果为3。
关于常用的位运算就介绍到这里,下面介绍项目案例,根据文档需求,分析位的运算。
看上述表中的状态字段,DWORD为无符号四字节整型(双字,32 位),那怎么对需求文档中所述,对位0进行赋值来表示定位状态、对位1赋值表示经度类型......
分析:既然DWORD为无符号四字节整型(双字,32 位),又因为Java int类型占4个字节,所以把其视为Java中的int类型。
处理:Java中一个Byte占一个字节(8个位),把int拆分成4个Byte进行重组赋值来表示位的变化。
/**
* 位赋值运算
*
* @author Engineer-Jsp
*/
public static void ByteCalc()
// 将Bytes(由4个Byte组成的Byte数组)视为一个int类型的值
byte[]Bytes = new byte[4];
// 伪代码假设满足条件:定到位置
if(定位成功)
//表示对位0进行赋值
Bytes[3] |= 0x01;
// 伪代码假设满足条件:西经
if(西经)
//表示对位1进行赋值
Bytes[3] |= 0x02;
// 伪代码假设满足条件:南纬
if(南纬)
//表示对位2进行赋值
Bytes[3] |= 0x04;
// 伪代码假设满足条件:震动
if(震动)
//表示对位8进行赋值
Bytes[2] |= 0x01;
// 伪代码假设满足条件:切断电源
if(切断电源)
//表示对位9进行赋值
Bytes[2] |= 0x02;
// 伪代码假设满足条件:Acc 开
if(Acc 开)
//表示对位10进行赋值
Bytes[2] |= 0x04;
上述代码是分别对 位0~位2、位8~位10 进行了赋值,下面用图加文字分析来介绍为什么要这么写。
见上图,笔者进行逐步分解介绍:
1.Bytes是长度为4(即4个16进制字节组成)的字节数组,因为是空数组,所以元素值均为0。
2.Bytes[0]~Bytes[3]分别为Bytes数组的元素,每个元素对应一个16进制的字节。
3.每个字节对应Bytes(看作4个字节的int类型,总共32位)的8个位,升序排列从右开始,依次往左。
4.0000 0000 0000 0000 0000 0000 0000 0000二进制数据由int类型的值即十进制的0转换而来。
5.0000 0000 0000 0000 0000 0000 0000 0000二进制数据顶部的小字体的数字就代表着位,最后一位应该是31,因为是从0开始的,这里笔者作图的时候写错了,所以最后一位应该是31。
搞清楚这个之后,开始详细介绍伪代码的位运算。
因为Bytes是长度为4(即4个16进制字节组成)的字节数组,因为是空数组,所以元素值均等于0,转换成int也是0,再将0转换成二进制数据 0000 0000 0000 0000 0000 0000 0000 0000。
①位0表示定位状态:
位计算:
因为位0~位2处于Bytes数组元素的第3个即Bytes[3](从0开始,所以元素下标为0~3),所以只需要将位0进行赋值即可。
Bytes[3]|=0x01;
Bytes[3]= 0x00 = 0 = 0000 0000 0000 0000 0000 0000 0000 0000 将第三个16进制元素byte转换成10进制,然后再将其转换成2进制
Bytes[3]二进制:0000 0000 0000 0000 0000 0000 0000 0000
0x01二进制 :0000 0000 0000 0000 0000 0000 0000 0001
或运算结果:0000 0000 0000 0000 0000 0000 0000 0001
结果说明 位0 已为1,表示定位成功。
②位1表示经度类型:
位计算:
因为位0~位2处于Bytes数组元素的第3个即Bytes[3](从0开始,所以元素下标为0~3),所以只需要将位1进行赋值即可。
Bytes[3]|=0x02;
Bytes[3]= 0x00 = 0 = 0000 0000 0000 0000 0000 0000 0000 0000 将第三个16进制元素byte转换成10进制,然后再将其转换成2进制
Bytes[3]二进制:0000 0000 0000 0000 0000 0000 0000 0000
0x02二进制 :0000 0000 0000 0000 0000 0000 0000 0010
或运算结果:0000 0000 0000 0000 0000 0000 0000 0010
结果说明 位1 已为1,表示经度为西经。
③位2表示纬度类型:
位计算:
因为位0~位2处于Bytes数组元素的第3个即Bytes[3](从0开始,所以元素下标为0~3),所以只需要将位2进行赋值即可。
Bytes[3]|=0x04;
Bytes[3]= 0x00 = 0 = 0000 0000 0000 0000 0000 0000 0000 0000 将第三个16进制元素byte转换成10进制,然后再将其转换成2进制
Bytes[3]二进制:0000 0000 0000 0000 0000 0000 0000 0000
0x04二进制 :0000 0000 0000 0000 0000 0000 0000 0100
或运算结果:0000 0000 0000 0000 0000 0000 0000 0100
结果说明 位2 已为1,表示纬度为南纬。
④位8表示防盗震动报警状态:
位计算:
因为位8~位10处于Bytes数组元素的第2个即Bytes[2](从0开始,所以元素下标为0~3),所以只需要将位8进行赋值即可。
Bytes[2]|=0x01;
Bytes[2]= 0x00 = 0 = 0000 0000 0000 0000 0000 0000 0000 0000 将第三个16进制元素byte转换成10进制,然后再将其转换成2进制
Bytes[2]二进制:0000 0000 0000 0000 0000 0000 0000 0000
0x01二进制 :0000 0000 0000 0000 0000 0000 0000 0001
或运算结果:0000 0000 0000 0000 0000 0000 0000 0001
结果说明 位8 已为1,表示报警。
⑤位9表示终端电源状态:
位计算:
因为位8~位10处于Bytes数组元素的第2个即Bytes[2](从0开始,所以元素下标为0~3),所以只需要将位9进行赋值即可。
Bytes[2]|=0x02;
Bytes[2]= 0x00 = 0 = 0000 0000 0000 0000 0000 0000 0000 0000 将第三个16进制元素byte转换成10进制,然后再将其转换成2进制
Bytes[2]二进制:0000 0000 0000 0000 0000 0000 0000 0000
0x02二进制 :0000 0000 0000 0000 0000 0000 0000 0010
或运算结果:0000 0000 0000 0000 0000 0000 0000 0010
结果说明 位9 已为1,表示电源被切断。
⑥位10表示Acc状态:
位计算:
因为位8~位10处于Bytes数组元素的第2个即Bytes[2](从0开始,所以元素下标为0~3),所以只需要将位10进行赋值即可。
Bytes[2]|=0x04;
Bytes[2]= 0x00 = 0 = 0000 0000 0000 0000 0000 0000 0000 0000 将第三个16进制元素byte转换成10进制,然后再将其转换成2进制
Bytes[2]二进制:0000 0000 0000 0000 0000 0000 0000 0000
0x04二进制 :0000 0000 0000 0000 0000 0000 0000 0100
或运算结果:0000 0000 0000 0000 0000 0000 0000 0100
结果说明 位10 已为1,表示Acc开。
6个位的值全部赋值完后,Bytes数组的元素应为: 0x00 , 0x00 , 0x07 , 0x07
转换成10进制后应为: 0 , 0 , 7 , 7
// 输出结果:0,0,7,7
for (int i = 0; i < Bytes.length; i++)
int v = Bytes[i] & 0xFF;
if (i == Bytes.length - 1)
result += v + "";
else
result += v + ",";
若转换成2进制后应为(简写): 0 , 0 , 111 , 111
再将Bytes转换成10进制应为:1799;1799 对应的二进制数据为:0000 0000 0000 0000 0000 0111 0000 0111
红色的部分正好对应 位0~位2、位8~位10。
至此,关于Byte通信协议的介绍就结束了,如发现其中存在问题的,欢迎随时批评指正,以免误人子弟。因为本博客的目的是帮助更多的人,而不是害读者,所以各位读者发现问题请在评论区评论指出,谢谢大家!
以上是关于Android开发中遇到关于Byte位运算通信协议类项目的文档解读分析的主要内容,如果未能解决你的问题,请参考以下文章
Android与单片机 | 开发板 | 智能硬件 | 智能设备 | 数据协议 |开发总结