2021SC@SDUSC
CRC8Util 类
这个类主要描写了如何利用串口数据对柜子的状态进行操作
static int crc8_maxim(int[] data, int length) {
int end = length;
int i, j = 0;
int crc = 0;
while (length > 0) {
crc ^= data[j ++];
for (i = 0; i < 8; i ++) {
if ((crc & 1) == 1) {
crc = (crc >> 1) ^ 0x8C; // 0x8C = reverse 0x31
} else {
crc >>= 1;
}
}
length--;
}
data[end] = crc;
return crc;
}
本项目在使用的CRC-8/MAXIM,它的参数模型为x8+x5+x4+1。所以,CRC校验的等效多项式是: CRC = x8 + x5 + x4 + 1
原理解析:
for (i = 0; i < 8; i ++)
数据往左移了8位,因此需要计算8次。使用if ((crc & 1) == 1)
进行最高位的判断,如果最高位为1,不需要异或,往左移一位,然后与0x8C
异或,如果最高位为0时,不需要异或,整体数据往左移一位。最后可以得到相应的校验数据。
static boolean checkCrc(int[] data) {
if (data.length <= 1) {
return false;
}
int end = data[data.length - 1];
int check = crc8_maxim(data, data.length - 1);
return end == check;
}
}
调用crc8_maxim()函数
校验Crc 的结果,最后一位是校验位
public static int[] getUnLockCRC8Data(int tableNum, int lockNum) {
int[] data = new int[] {0xAA, 0x55, 0x03, tableNum, 0x50, lockNum, 0x00};
CRC8Util.crc8_maxim(data, 6);
return data;
}
public static String getUnLockCrc8String(int tableNum, int lockNum) {
int[] temp = getUnLockCRC8Data(tableNum, lockNum);
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < temp.length; i ++) {
buffer.append(temp[i] < 16 ? ("0" + Integer.toHexString(temp[i])) : Integer.toHexString(temp[i]));
}
return buffer.toString();
}
在getUnLockCRC8Data()
方法中,tableNum
为锁控版编号,lockNum
为锁编号,通过这两个参数获得UnLockCRC8数据,并将其转换成字符串,获取解锁命令。
static boolean getLockState(int[] retData, int lockNum) {
lockNum--;
int byteNum = lockNum / 8;
int bitNum = lockNum % 8;
int checkBit = 1 << bitNum;
int tempByte = retData[5 + byteNum];
return (checkBit & tempByte) != checkBit;
}
retData
为串口返回的数据, RLC-18E对应9字节,RLC-24E对应10字节
lockNum
为锁编号,从1开始,最大24
只有当retData和lockNum相匹配,符合要求规范时,快递柜才能拥有开锁的状态。
此方法从响应值中获取某锁的状态。
public static boolean checkLockRet(int[] retData, int tableNum, int lockNum) {
if (!checkResponseForm(retData, tableNum)) {
System.out.println("数据格式错误");
return false;
}
return getLockState(retData, lockNum);
}
使用if (!checkResponseForm(retData, tableNum))
检验数据格式是否错误,如果格式错误直接返回false,接着调用getLockState()函数
检查开锁命令的响应值,验证锁是否打开。true表示锁已开,false表示锁未开。
static boolean checkResponseForm(int[] retData, int tableNum) {
if (retData[0] != 0xAA
|| retData[1] != 0x55
|| retData[3] != tableNum
|| retData[2] + 4 != retData.length
) {
return false;
}
return checkCrc(retData);
}
此方法检查串口的响应的数据格式,包括(两个帧头,版地址,校验位,数据总长度)。其中,0xAA
为帧头1,0x55
为帧头2,tableNum
为板地址,retData.length
为数据长度,通过或运算,如果有一项不符合要求则返回false。最后通过checkCrc(retData)
计算校验位是否正确。