Files
VX5-DiaphragmPump/rfid/rfidfunction.cpp
T
2026-08-26 16:13:59 +08:00

646 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "rfidfunction.h"
#include "sm3.h"
#include "sm4.h"
#include <QTime>
#include <QCoreApplication>
// 计算校验和并输出
void RFIDFunction::CheckSumOut(unsigned char* buf, unsigned char len)
{
unsigned char i;
unsigned char checksum;
checksum = 0;
for (i = 0; i < (len - 1); i++)
{
checksum ^= buf[i]; // 逐位异或计算校验和
}
buf[len - 1] = (unsigned char)~checksum; // 取反作为校验和
}
// 检查输入的校验和是否正确
bool RFIDFunction::CheckSumIn(unsigned char* buf, unsigned char len)
{
unsigned char i;
unsigned char checksum;
checksum = 0;
for (i = 0; i < (len - 1); i++)
{
checksum ^= buf[i]; // 逐位异或计算校验和
}
if (buf[len - 1] == (unsigned char)~checksum) // 比较校验和
{
return true; // 校验和正确
}
return false; // 校验和错误
}
// 将十六进制字符串转换为字节数组
void hexStrToByte(const QByteArray& hexIn, unsigned char* dest)
{
int sourceLen = hexIn.size();
unsigned char* source = (unsigned char*)hexIn.constData();
short i;
unsigned char highByte, lowByte;
for (i = 0; i < sourceLen; i += 2)
{
highByte = toupper(source[i]); // 高位
lowByte = toupper(source[i + 1]); // 低位
if (highByte > 0x39)
{
highByte -= 0x37; // A-F转换
}
else
{
highByte -= 0x30; // 0-9转换
}
if (lowByte > 0x39)
{
lowByte -= 0x37; // A-F转换
}
else
{
lowByte -= 0x30; // 0-9转换
}
dest[i / 2] = (highByte << 4) | lowByte; // 合并高低位
}
return;
}
// 检测输入的字符是否是有效的16进制字符
bool isValidHex(const QByteArray& input)
{
int length = input.size(); // 获取输入的长度
for (int i = 0; i < length; ++i) // 使用传统的for循环
{
char c = input[i]; // 获取当前字符
// 检查字符是否在0-9, A-F, a-f范围内
if (!((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F') ||
(c >= 'a' && c <= 'f')))
{
return false; // 如果有无效字符,返回false
}
}
return true; // 所有字符均有效,返回true
}
void sleepMs(unsigned int msec)
{
QTime dieTime = QTime::currentTime().addMSecs(msec);
while( QTime::currentTime() < dieTime )
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
RFIDFunction::RFIDFunction(QObject *parent)
: QObject(parent),m_SerialPort(NULL)
{
m_SerialSate = initSerialPortAndOpen("COM3"); // 初始化串口
}
RFIDFunction::~RFIDFunction()
{
if (m_SerialPort) {
if (m_SerialPort->isOpen()) {
m_SerialPort->close();
}
delete m_SerialPort;
m_SerialPort = nullptr;
}
}
/***
* @描述 : 创建读写卡的密码(Key_A和Key_B)
* @入参 : info 生成密码的数据
* @输出 : 无
* @返回 : 密钥的原始数据
*/
const QByteArray RFIDFunction::createPassword(const QByteArray& info)
{
if (info.isEmpty())
{
return ""; // 如果输入为空,返回空
}
int inputSize = info.size();
if (inputSize > 8192)
{
return ""; // 如果输入大小超过限制,返回空
}
//先用SM3对原始数据进行哈希生成
unsigned char hashDataOrigin[32] = { 0 };
SM3::sm3Hash((unsigned char*)info.data(), inputSize, hashDataOrigin); // 生成哈希
//接着使用哈希生成SM4加密密钥
unsigned char sm4Key[16] = { 0 };
unsigned char sm4IV[16] = { 0 };
int index_1 = 0;
int index_2 = 0;
for (int i = 0; i < 32; i++)
{
if (i % 2 == 0)
{
sm4Key[index_1++] = hashDataOrigin[i]; // 偶数位作为SM4密钥
}
else
{
sm4IV[index_2++] = hashDataOrigin[i]; // 奇数位作为SM4初始向量
}
}
//再用SM4对原始数据进行加密
unsigned char out[8192] = {0};
sm4_context sm4Ctx;
SM4::sm4_setkey_enc(&sm4Ctx, sm4Key); // 设置SM4加密密钥
SM4::sm4_crypt_cbc(&sm4Ctx, SM4_ENCRYPT, inputSize, sm4IV, (unsigned char*)info.data(), out); // 执行SM4加密
//最后再用SM3对加密后的数据取哈希
unsigned char hashEncrypted[32] = { 0 };
SM3::sm3Hash(out, inputSize, hashEncrypted); // 生成加密数据的哈希
index_1 = 0;
char key[16] = { 0 };
for (int i = 0; i < 32; i++)
{
if (i % 2 != 0)//取哈希的奇数位作为最终的密码
{
key[index_1++] = hashEncrypted[i];
}
}
return QByteArray(key,16).toHex(); // 返回最终的密码
}
bool RFIDFunction::getSerialState()
{
return m_SerialSate; // 返回串口状态
}
RFIDFunction::ErrorCode RFIDFunction::initSerialPortAndOpen(const QString& portName,
BaudRateType baudRate,
DataBitsType setDataBits,
StopBitsType stopBits,
ParityType parity)
{
m_SerialPort = new Posix_QextSerialPort("/dev/ttyO3",QextSerialBase::Polling); // 创建串口对象
m_SerialPort->setPortName(portName); // 设置串口名称
m_SerialPort->setBaudRate((BaudRateType)baudRate); // 设置波特率
m_SerialPort->setDataBits(setDataBits); // 设置数据位
m_SerialPort->setStopBits(stopBits); // 设置停止位
m_SerialPort->setParity(parity); // 设置校验位
m_SerialPort->setFlowControl(FLOW_OFF);
if (m_SerialPort->open(QIODevice::ReadWrite)) // 打开串口
{
return Serial_Error; // 打开失败,返回串口错误
}
return No_Error; // 打开成功,返回无错误
}
RFIDFunction::ErrorCode RFIDFunction::setOriginPassword(const QByteArray& psw)
{
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x03; // 命令头
com[1] = 0x0B; // 数据长度
com[2] = 0xC4; // 命令类型
com[3] = 0x20; // 额外数据
unsigned char hexOut[32] = { 0 }; // 存储转换后的十六进制数据
hexStrToByte(psw, hexOut); // 将密码转换为字节数组
memcpy(com + 4, hexOut, 6); // 将密码添加到命令中
CheckSumOut(com, com[1]); // 计算校验和
//QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x03) && (revData[1] == 0x08) && (revData[2] == 0xC4) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}
RFIDFunction::ErrorCode RFIDFunction::setWriteAndReadPassword(const QByteArray& writePassword, const QByteArray& readPassword, KeyFunction keyFunc)
{
if (writePassword.isEmpty() || readPassword.isEmpty())
{
return Data_Is_Empty_Error; // 如果密码为空,返回错误
}
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x03; // 命令头
com[1] = 0x15; // 数据长度
com[2] = 0xC3; // 命令类型
com[3] = 0x20; // 额外数据
unsigned char hexOut[32] = { 0 }; // 存储转换后的十六进制数据
hexStrToByte(writePassword.toHex(), hexOut); // 将写密码转换为字节数组
memcpy(com + 4, hexOut, 6); // 将写密码添加到命令中
switch (keyFunc) // 根据密钥功能设置命令
{
case RFIDFunction::KeyA_Same_KeyB:
/*
* 控制如下:KEYA,KEYB 可以用来读 、写 、增值 、减值 、更改扇区密钥
*/
com[10] = 0xFF; // 设置KEYA和KEYB相同
com[11] = 0x07; // 设置权限
com[12] = 0x80; // 设置操作
com[13] = 0x69; // 设置结束标志
break;
case RFIDFunction::KeyB_Control_KeyA:
/*
控制如下:KEYA 可以读数据块 、减值 、查询余额
KEYB 可以读写数据块 、增值 、减值 、查询余额
KEYA 、KEYB 不可读,KEYA,KEYB 由 KEYB 修改
*/
com[10] = 0x08; // 设置KEYB控制KEYA
com[11] = 0x77; // 设置权限
com[12] = 0x8F; // 设置操作
com[13] = 0x69; // 设置结束标志
break;
default:
break;
}
memset(hexOut, 0, 32); // 清空hexOut
hexStrToByte(readPassword.toHex(), hexOut); // 将读密码转换为字节数组
memcpy(com + 14, hexOut, 6); // 将读密码添加到命令中
CheckSumOut(com, com[1]); // 计算校验和
QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x03) && (revData[1] == 0x08) && (revData[2] == 0xC3) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}
RFIDFunction::ErrorCode RFIDFunction::setEncryptedBlock(KeyType type, ControlBlock block)
{
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x01; // 命令头
com[1] = 0x08; // 数据长度
switch (type)//只有两种密码,A和B
{
case RFIDFunction::KEY_A:
com[2] = 0xA5; // 设置为KEY_A
break;
case RFIDFunction::KEY_B:
com[2] = 0x5A; // 设置为KEY_B
break;
default:
com[2] = 0xA5; // 默认设置为KEY_A
break;
}
com[3] = 0x20; // 额外数据
memcpy(com + 4, &block, 1); // 将加密块添加到命令中
com[5] = 0x01;//蜂鸣器开 0x00不开
com[6] = 0x00;//保留
CheckSumOut(com, com[1]); // 计算校验和
QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x01) && (revData[1] == 0x08) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}
RFIDFunction::ErrorCode RFIDFunction::writeDataToBlock(KeyType type, DataBlock block, const QByteArray& data)
{
if (data.isEmpty())
{
return Data_Is_Empty_Error; // 如果数据为空,返回错误
}
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x01; // 命令头
com[1] = 0x17; // 数据长度
switch (type)//只有两种密码,A和B
{
case RFIDFunction::KEY_A:
com[2] = 0xA4; // 设置为KEY_A
break;
case RFIDFunction::KEY_B:
com[2] = 0x5B; // 设置为KEY_B
break;
default:
com[2] = 0xA4; // 默认设置为KEY_A
break;
}
com[3] = 0x20; // 额外数据
memcpy(com + 4, &block, 1); // 将数据块添加到命令中
com[5] = 0x01;//蜂鸣器开 0x00不开
unsigned char hexOut[32] = { 0 }; // 存储转换后的十六进制数据
memset(hexOut, 0, 32); // 清空hexOut
if (!isValidHex(data)) // 检查数据是否合法
{
return Data_Is_Illegal_Error; // 数据非法
}
hexStrToByte(data, hexOut); // 将数据转换为字节数组
memcpy(com + 6, hexOut, 16); // 将数据添加到命令中
CheckSumOut(com, com[1]); // 计算校验和
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x01) && (revData[1] == 0x08) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}
RFIDFunction::ErrorCode RFIDFunction::readDataFromBlock(KeyType type, DataBlock block, QByteArray& data)
{
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x01; // 命令头
com[1] = 0x08; // 数据长度
switch (type)//只有两种密码,A和B
{
case RFIDFunction::KEY_A:
com[2] = 0xA3; // 设置为KEY_A
break;
case RFIDFunction::KEY_B:
com[2] = 0x5C; // 设置为KEY_B
break;
default:
com[2] = 0xA3; // 默认设置为KEY_A
break;
}
com[3] = 0x20; // 额外数据
memcpy(com + 4, &block, 1); // 将数据块添加到命令中
com[5] = 0x01;//蜂鸣器开 0x00不开
com[6] = 0x00;//保留
CheckSumOut(com, com[1]); // 计算校验和
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
//QByteArray AAA = readData.toHex(); // 转换为十六进制字符串
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x01) && (revData[1] == 0x16) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
data = QByteArray::fromHex(readData.mid(3,16));
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}
RFIDFunction::ErrorCode RFIDFunction::setWorkMode(WorkMode mode, DataBlock block, UploadMode uploadMode)
{
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x03; // 命令头
com[1] = 0x08; // 数据长度
com[2] = 0xC1; // 工作模式
com[3] = 0x20; // 设备号数据
memcpy(com + 4, &mode, 1); // 将工作模式添加到命令中
switch (mode)
{
case RFIDFunction::Command_Mode:
com[5] = 0x00;
com[6] = 0x00;
break;
case RFIDFunction::Auto_Read_Card_Num_Mode:
com[5] = 0x00;
com[6] = uploadMode;
break;
case RFIDFunction::Auto_Read_Data_Mode:
case RFIDFunction::Auto_Read_Card_Num_Data_Mode:
default:
com[5] = block;
com[6] = uploadMode;
break;
}
CheckSumOut(com, com[1]); // 计算校验和
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
QByteArray AAA = readData.toHex(); // 转换为十六进制字符串
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x03) && (revData[1] == 0x08) && (revData[2] == com[2]) && (revData[3] == 0x20)) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}
RFIDFunction::ErrorCode RFIDFunction::getReaderAddress(QByteArray& psw)
{
unsigned char com[32] = { 0 }; // 命令数组
com[0] = 0x02; // 命令头
com[1] = 0x08; // 数据长度
com[2] = 0xB0; // 命令类型
com[3] = 0x00; // 额外数据
com[4] = 0x00; // 额外数据
com[5] = 0x00; // 额外数据
com[6] = 0x00; // 额外数据
CheckSumOut(com, com[1]); // 计算校验和
QByteArray AAA = QByteArray((char*)com, com[1]).toHex(); // 转换为十六进制字符串
if (m_SerialPort->isOpen()) // 检查串口是否打开
{
qint64 len = m_SerialPort->write(QByteArray((char*)com, com[1])); // 发送命令
if (len != com[1]) // 检查发送长度
{
return Send_Data_Error; // 发送错误
}
// 等待请求完成
sleepMs(200);
QByteArray readData = m_SerialPort->readAll(); // 读取返回数据
unsigned char revData[32] = { 0 }; // 存储返回数据
memcpy(revData, readData.data(), readData.size()); // 复制返回数据
if ((revData[0] == 0x02) && (revData[1] == 0x08) && (revData[2] == com[2])) //判断是否为写数据返回的数据包
{
bool status = CheckSumIn(revData, revData[1]); //计算校验和
if (status)
{
if (revData[4] == 0x00) //写数据块成功
{
psw = QByteArray::fromHex(QByteArray(revData[5], 1));
return No_Error; // 返回无错误
}
}
else
{
return Received_Data_Check_Error; // 校验和错误
}
}
else
{
return Received_Data_Error; // 返回数据错误
}
}
return Serial_Error; // 串口错误
}