重构各页面代码,从h文件改为cpp文件;

添加硬件接口并添加,readerAPI使用硬件接口获取invenory信息和connect;
完成开卡初始页面,获取卡号和学号。
This commit is contained in:
Jingfan Ke 2024-07-29 11:24:26 +08:00
parent f229cd4a28
commit 4b8460f4ce
17 changed files with 1411 additions and 157 deletions

View File

@ -9,18 +9,26 @@ CONFIG += c++17
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
VCD.cpp \
VCDOurs.cpp \
databaseAPI.cpp \
deviceAPI.cpp \
main.cpp \
mainwindow.cpp
mainwindow.cpp \
newCardPage.cpp \
quitAppPage.cpp \
readerAPI.cpp \
settingPage.cpp
HEADERS += \
HF15693.h \
HLog.h \
VCD.h \
VCDOurs.h \
databaseAPI.h \
deviceAPI.h \
mainwindow.h \
newCardPage.h \
quitAppPage.h \
readerAPI.h \
settingPage.h
readerAPI.h
FORMS += \
mainwindow.ui

63
HLog.h Normal file
View File

@ -0,0 +1,63 @@
//#pragma once
#ifndef _H_LOG_H_
#define _H_LOG_H_
#include <stdio.h>
typedef unsigned char uchar_t;
class CHLog
{
public:
CHLog(void)
{
m_fp = fopen( "hfsim.log", "w");
}
~CHLog(void)
{
if( m_fp )
{
fclose( m_fp );
}
}
public:
void logstr( char *str )
{
if( m_fp )
{
fprintf( m_fp, "%s\n", str );
}
}
void logDIM( int len, uchar_t aucDat[] )
{
int n = len/16;
int k = 0;
if( m_fp )
{
fprintf( m_fp, "hex----------------\n");
for( int i = 0; i < n; i++ )
{
for( int j = 0; j < 16; j++ )
{
fprintf( m_fp, "%02x ", aucDat[k++]);
}
fprintf( m_fp, "\n" );
}
for( int j = 0; j < len%16; j++ )
{
fprintf( m_fp, "%02x ", aucDat[k++]);
}
fprintf( m_fp, "\n" );
fprintf( m_fp, "hex----------------\n");
}
}
protected:
FILE *m_fp;
};
#endif

56
VCD.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "VCD.h"
#define POLYNOMIAL 0x8408 // x^16 + x^12 + x^5 + 1
#define PRESET_VALUE 0xFFFF
#define CHECK_VALUE 0xF0B8
#define CALC_CRC 1
#define CHECK_CRC 0
void CVCD::CRC16( int buflen, uchar_t buf[], uchar_t *pucCRCL, uchar_t *pucCRCH )
{
unsigned int current_crc_value;
unsigned char *array_of_databytes;
int number_of_databytes;
int i, j;
number_of_databytes = buflen;
array_of_databytes = buf;
current_crc_value = PRESET_VALUE;
for (i = 0; i < number_of_databytes; i++)
{
current_crc_value = current_crc_value ^ ((unsigned int)array_of_databytes[i]);
for (j = 0; j < 8; j++)
{
if (current_crc_value & 0x0001)
{
current_crc_value = (current_crc_value >> 1) ^ POLYNOMIAL;
}
else
{
current_crc_value = (current_crc_value >> 1);
}
}
}
current_crc_value = ~current_crc_value;
*pucCRCL = current_crc_value & 0xFF;
*pucCRCH = (current_crc_value >> 8) & 0xFF;
}
void CVCD::ISO15693_getCRC16( int buflen, uchar_t buf[], uchar_t *pucCRCL, uchar_t *pucCRCH )
{
CRC16( buflen, buf, pucCRCL, pucCRCH );
}
bool CVCD::ISO15693_checkCRC16( int buflen, uchar_t buf[] )
{
uchar_t ucCRCL, ucCRCH;
CRC16( buflen-2, buf, &ucCRCL, &ucCRCH );
if( ucCRCL == buf[buflen-2] && ucCRCH == buf[buflen-1] )
{
return true;
}
else
{
return false;
}
}

438
VCD.h Normal file
View File

@ -0,0 +1,438 @@
//-----------------------------------------
// 关于类说明
// 类 CVCD 用于 描述 VCD
// 应用软件调用类的成员函数可以对VICC进行访问
//
// 派生类CVCD_Sim 用软件仿真VCD通过transponderEnter函数仿真VICC进入了射频场
// class CVCD_Sim : public CVCD
//
// 派生类CVCD_Ours 封装了Ours的reader.
// class CVCD_Ours : public CVCD
//
//
//#pragma once
#ifndef _VCD_H_
#define _VCD_H_
#include "HLog.h"
#include <cstring>
//
// 并部分实现函数的部分功能
// 比如select request寻址模式一定是address mode
//
// 有些命令,可以由用户确定寻址模式
// 00: 所有的卡都应答
// 01: 被选择卡应答
// 02: 特定地址的卡应答
// else: 不支持;
//
//---------------------------------------------------
// 下面定义了reader成员函数的返回结果
//
// 比如一个addressed的命令收到多个应答或者没有应答
// 注意此处没有应答不指VICC没有影带有些场景VICC不应答也是正确的
// 比如stay quiet收不到任何响应其实是正确的。
// 此处没有应答指VICC应该应答而没有应答
//
#define ISO15693_READER_OK 0xA0
#define ISO15693_READER_ER_LESS_ANSWER 0xA1 // 没有应答
#define ISO15693_READER_ER_MORE_ANSWERS 0xA2 // 收到多个应答
#define ISO15693_READER_ER_FRAME 0xA3 // 收到frame格式错可能发生了冲突软件表示frame错误.
// 副载波0: for single subcarrier / 1: for double subcarrier
#define ISO15693_REQ_FLAG_SUB_CARRIER_S 0
#define ISO15693_REQ_FLAG_SUB_CARRIER_D 1
// 速率, 0: for low data rate / 1: for high data rate
#define ISO15693_REQ_FLAG_DATA_RATE_H 0
#define ISO15693_REQ_FLAG_DATA_RATE_H 1
// 编码方式0: for 1/4 / 1 for 1/256;
#define ISO15693_CODING_1_FROM_4 0
#define ISO15693_CODING_1_FROM_256 1
#define ISO15693_RSP_ERR_NO 0
#define MAX_TRANSPONDERS 16
#define MAX_PKT_LEN 1024
// 寻址模式
// 除inventory命令外其他都涉及到寻址模式.
#define ISO15693_INVENTORY_NO_VICC 0x00
#define ISO15693_INVENTORY_ONE_VICC 0x01
#define ISO15693_INVENTORY_MORE_VICCS 0x02
// VCD的射频场最多支持的VICC数
// 定义为16个是因为inventory采用16slots的情况下最多一次可以清晰收到16个VICC的应答。
// 如果发生了碰撞,或者访问清晰收到的,或者继续寻找碰撞的。
#define MAX_NUM_VICCS 16
typedef unsigned char uchar_t;
typedef enum
{
mode_all,
mode_select,
mode_addressed
}ISO15693_MODE_E;
// VICC的部分信息.
typedef struct tag_VICCInfo
{
uchar_t aucUID[8];
uchar_t ucValid; // 0 for unvalid, 1 for valid.
uchar_t ucDSFID;
uchar_t ucAFI;
uchar_t ucBlockNum;
uchar_t ucBlockSize;
uchar_t ucICRef;
}VICCInfo;
class CVCD
{
public:
CVCD(void)
{
m_ucSubCarrier = ISO15693_REQ_FLAG_SUB_CARRIER_D; // 默认双载波
m_ucDataRate = ISO15693_REQ_FLAG_DATA_RATE_H; // 默认高速率
m_ucDataCoding = ISO15693_CODING_1_FROM_4;
m_ucSlots = 16;
m_pLog = NULL;
for( int i = 0; i < MAX_NUM_VICCS; i++ )
{
m_astVICCs[i].ucValid = 0;
}
}
virtual ~CVCD(void)
{
}
public:
// 正式执行inventory前设置这些参数
int set( uchar_t ucSubCarrier, uchar_t ucDataRate, uchar_t ucSlots )
{
m_ucSubCarrier = ucSubCarrier;
m_ucDataRate = ucDataRate;
m_ucSlots = ucSlots;
}
int setSubCarrier( uchar_t ucSubCarrier )
{
m_ucSubCarrier = ucSubCarrier;
}
int setDataRate( uchar_t ucDataRate )
{
m_ucDataRate = ucDataRate;
}
int setSlots( uchar_t ucSlots )
{
m_ucSlots = ucSlots;
}
void setDataCoding_1from4()
{
m_ucDataCoding = ISO15693_CODING_1_FROM_4;
}
void setDataCoding_1from256()
{
m_ucDataCoding = ISO15693_CODING_1_FROM_256;
}
void setLog( CHLog *plog )
{
m_pLog = plog;
}
// 如何设置和VCD/Reader的连接
// 串口.
virtual int connectReader()
{
return 1;
}
virtual int disconnectReader( )
{
return 1;
}
/*
virtual int connectReaderByCOM( int comno )
{
return 1;
}
*/
// 在执行了inventory后用户可以获得芯片的信息。
// 其中获得的blocksize和blocknum在readblocks()和write block()时,有用.
VICCInfo getVICCInfo( uchar_t aucUID[8] )
{
VICCInfo vicc;
memset( (uchar_t *)&vicc, 0x00, sizeof(vicc));
int k = getVICC( aucUID );
if( k != -1 )
{
return m_astVICCs[k];
}
return vicc;
}
public:
// 协议命令
// 返回:>0表示读到的Transponder数量;
//
virtual int inventory(
bool bAFIUsed,
uchar_t ucAFI,
int nViccNum, // 应用层可以接收的UID数量;
uchar_t aucDSFID[],
uchar_t aucUID[][8] )
{
m_bAFIUsed = bAFIUsed;
if( m_bAFIUsed )
{
m_ucAFI = ucAFI;
}
return ISO15693_RSP_ERR_NO;
}
//------------------------------------------
// 状态转换
// stayquiet
// cmd=0x02;
// 寻址方式:只能是地址模式, UID必须;
virtual int stayQuiet( uchar_t *pucUID )
{
return ISO15693_RSP_ERR_NO;
}
// select命令
// cmd=0x25
// 寻址方式一定是地址模式, UID必须;
virtual int select( uchar_t *pucUID )
{
return ISO15693_RSP_ERR_NO;
}
// reset to ready
// cmd=0x26
// 可以使地址模式,也可以是选择模式
virtual int resetToReady( uchar_t *pucUID )
{
return ISO15693_RSP_ERR_NO;
}
//------------------------------------------
// 操作
// 操作类命令寻址模式只能地址或者select
//
// 0x20
virtual int readSingleBlock(
uchar_t *pucUID, // NULL表示select模式
uchar_t optional_flag, // optional bit = 1, 要求返回block的安全状态
uchar_t ucBlkno, // blockno
uchar_t buf[], // 返回读取的数据
uchar_t *pucSecurity // 如果optional_flag = 1, 返回该block的安全状态1表示locked.
)
{
return ISO15693_RSP_ERR_NO;
}
// 0x21
virtual int writeSingleBlock(
uchar_t *pucUID, // NULL表示select模式
uchar_t ucBlkno, //
uchar_t ucBlksize,
uchar_t buf[] )
{
return ISO15693_RSP_ERR_NO;
}
// 0x22
virtual int lockBlock(
uchar_t *pucUID, // NULL表示select模式
int blockno )
{
return ISO15693_RSP_ERR_NO;
}
// 0x23
virtual int readMultipleBlocks(
uchar_t *pucUID, // NULL表示select模式
uchar_t optional_flag, // optional bit = 1, 要求返回block的安全状态
uchar_t ucBlkno, // 开始block no
uchar_t blocknum, // 实际读的block是blocknum+1;
uchar_t buf[], // 返回读取的数据
uchar_t aucSecurity[] // 如果optional_flag = 1, 返回该block的安全状态1表示locked.
)
{
return ISO15693_RSP_ERR_NO;
}
// 0x24
virtual int writeMultipleBlocks(
uchar_t *pucUID, // NULL表示select模式
uchar_t ucBlkno, // 开始block no
uchar_t blocknum, // 实际写的block是blocknum+1;
uchar_t ucBlksize,
uchar_t buf[] )
{
return ISO15693_RSP_ERR_NO;
}
//----------------------------------------------------------
// AFI & DSFID
//
// CMD: 0x27
// optional 不处理.
virtual int writeAFI(
uchar_t *pucUID, // NULL表示select模式
uchar_t ucAFI )
{
return ISO15693_RSP_ERR_NO;
}
//
// CMD: 0x28
// optional 不处理.
virtual int lockAFI(
uchar_t *pucUID // NULL表示select模式
)
{
return ISO15693_RSP_ERR_NO;
}
//
// CMD: 0x29
// optional 不处理.
virtual int writeDSFID(
uchar_t *pucUID, // NULL表示select模式
uchar_t ucDSFID )
{
return ISO15693_RSP_ERR_NO;
}
//
// CMD: 0x2A
// optional 不处理.
virtual int lockDSFID(
uchar_t *pucUID // NULL表示select模式
)
{
return ISO15693_RSP_ERR_NO;
}
// CMD: 0x2B
//
virtual int getSystemInfo(
uchar_t *pucUID,
uchar_t *pinfoFlag,
uchar_t *pDSFID, uchar_t *pAFI, uchar_t *pBlockNum, uchar_t *pBlockSize, uchar_t *pICRef
)
{
return ISO15693_RSP_ERR_NO;
}
protected:
void CRC16( int buflen, uchar_t buf[], uchar_t *pucCRCL, uchar_t *pucCRCH );
bool ISO15693_checkCRC16( int buflen, uchar_t buf[] );
void ISO15693_getCRC16( int buflen, uchar_t buf[], uchar_t *pucCRCL, uchar_t *pucCRCH );
/**
* inventory后VICC的systeminfo
* CVICC.
* blocksize & blocknum read,write命令用
* pucUID. 8UID.
*/
virtual bool setVICC( uchar_t aucUID[8] )
{
uchar_t infoFlag;
uchar_t ucDSFID, ucAFI, ucBlockNum, ucBlockSize;
uchar_t ucICRef;
if( getSystemInfo( aucUID, &infoFlag, &ucDSFID, &ucAFI, &ucBlockNum, &ucBlockSize, &ucICRef ) != ISO15693_RSP_ERR_NO )
{
return false;
}
// OK.
for( int i = 0; i < MAX_NUM_VICCS; i++ )
{
if( m_astVICCs[i].ucValid == 0 )
{
m_astVICCs[i].ucValid = 1;
if( infoFlag & (1 << 0) )
{
m_astVICCs[i].ucDSFID = ucDSFID;
}
else if( infoFlag & ( 1 << 1 ))
{
m_astVICCs[i].ucAFI = ucAFI;
}
else if( infoFlag & ( 1 << 2 ) )
{
m_astVICCs[i].ucBlockNum = ucBlockNum;
m_astVICCs[i].ucBlockSize = ucBlockSize;
}
else if( infoFlag & ( 1 << 3 ))
{
m_astVICCs[i].ucICRef = ucICRef;
}
memcpy( m_astVICCs[i].aucUID, aucUID, 8 );
return true;
}
}
return false;
}
int getVICC( uchar_t aucUID[8] )
{
for( int i = 0; i < MAX_NUM_VICCS; i++ )
{
if( memcmp(m_astVICCs[i].aucUID, aucUID, 8 ) == 0 )
{
return i;
}
}
return -1;
}
protected:
void log( char *str )
{
if( m_pLog )
{
m_pLog->logstr( str );
}
}
void logDIM( int len, uchar_t aucDat[] )
{
if( m_pLog )
{
m_pLog->logDIM( len, aucDat );
}
}
protected:
// 全局性配置
// VCD自己的选择
uchar_t m_ucDataCoding; // 编码方式0: for 1/4 / 1 for 1/256;
uchar_t m_ucSlots; // 016 slots or 1 slots;
// VCD对VICC的要求
uchar_t m_ucSubCarrier; // 副载波0: for single subcarrier / 1: for double subcarrier
uchar_t m_ucDataRate; // 速率, 0: for low data rate / 1: for high data rate
// 执行防碰撞循环时可能多次发送inventory request每个都涉及是否使用AFI
// 因此设置为成员变量;
//
uchar_t m_ucAFI;
bool m_bAFIUsed;
// 记录日志.
CHLog* m_pLog;
// 通过inventory命令后发现的viccs.
VICCInfo m_astVICCs[MAX_NUM_VICCS];
};
#endif

493
VCDOurs.cpp Normal file
View File

@ -0,0 +1,493 @@
#include <cstdlib>
#include "VCDOurs.h"
CVCDOurs::CVCDOurs(void)
{
m_bComOpened = false;
}
CVCDOurs::~CVCDOurs(void)
{
if( m_bComOpened )
{
t15portClose();
}
}
// 使用串口和建立连接
int CVCDOurs::connectReaderByCOM( int comno )
{
if(t15portOpen(comno))
{
t15bSubCarrier=m_ucSubCarrier;
t15bDataCoding=m_ucDataCoding;
t15bFullPower=1;
t15bDataRate=m_ucDataRate;
m_bComOpened = true;
if( t15setProtocol() == 0 )
{
return 1;
}
}
return 0;
}
void CVCDOurs::disconnectReaderByCOM( )
{
if( m_bComOpened )
{
t15portClose( );
}
}
int CVCDOurs::inventory(
bool bAFIUsed,
uchar_t ucAFI,
int nViccNum, // 应用层的接收的UID数量;
uchar_t aucDSFID[],
uchar_t aucUID[][8] )
{
t15bInventory=1;
// t15bAddress & t15bSelect在inventory=1的情况下表示: AFI 和 NBSlots
// 而NBSlots为16取值为0.
t15bAddress=0; // 本来就没有用
t15bOption=0; // 没用用.
if( bAFIUsed )
{
t15bSelect=1; // 此处的含义是没有AFI其实可以有
sprintf( t15AFI, "%02x", ucAFI );
}
char* strUID[16];
for( int i = 0; i < 16; i++ )
{
strUID[i] = new char[50];
}
int n = doInventory( strUID );
n = ( n >= nViccNum ) ? nViccNum : n;
// 开始解析.
for( int i = 0; i < n; i++ )
{
StringToHex( strUID[i], aucUID[i] );
}
for( int i = 0; i < 16; i++ )
{
delete []strUID[i];
}
return n;
}
// Ours
// 1. 执行inventory时因为t15bSelect=0因此没有AFI flag.
// 2. 没有处理返回的DSFID.
//
int CVCDOurs::inventory( char *pTagUID[] )
{
t15bInventory=1;
// t15bAddress & t15bSelect在inventory=1的情况下表示: AFI 和 NBSlots
// 而NBSlots为16取值为0.
t15bAddress=0; // 本来就没有用
t15bSelect=0; // 此处的含义是没有AFI其实可以有
t15bOption=0; // 没用用.
return doInventory( pTagUID );
}
int CVCDOurs::doInventory( char *pTagUID[] )
{
// 对返回的UID
// 每个[]一个UID
// []表示分配的slot数
// [z,40]中, 'z'表示发生了冲突
// 返回的序列是防冲突过程中的全部序列。
//
char cmdsend[CMD_LEN],reply[CMD_LEN]/*="23[,40][2343334239,55][,49][abcderfdsdfs0d,30]"*/;
t15execute(INVENTORY,cmdsend,reply);
int k = 0;
char *p,*q,tstr[50]={0};
p=reply;
while (1)
{
p = strchr(p,'[');
if (NULL == p)
break ;
q = strchr(p+1,',');
if (NULL == q)
break ;
// 'z'表示冲突
if (q != (p+1) && *(p+1) != 'z' )
{
t15changeByteOrder(tstr,p+1,q-p-1); //返回的数据是低字节在前,调整字节序
strcpy( pTagUID[k++], tstr );
// 获取某个Tag的详细信息call GetSystemInfo().
setVICCStr( pTagUID[k-1] );
}
p = q+1;
}
return k;
}
//已经通过UID获得了VICC的信息.
int CVCDOurs::getSystemInfo(
uchar_t *pucUID,
uchar_t *pinfoFlag,
uchar_t *pDSFID, uchar_t *pAFI, uchar_t *pBlockNum, uchar_t *pBlockSize, uchar_t *pICRef
)
{
char str[100];
t15bOption = 0;
t15bInventory = 0;
if( pucUID )
{
t15bAddress=1;
t15bSelect = 0;
HexToString( pucUID, 8, str );
t15changeByteOrder( t15UID, str, 16 );
t15UID[16]=0;
}
else
{
t15bAddress=0;
t15bSelect =1;
}
//执行命令
char cmdstr[CMD_LEN] = {0},reply[CMD_LEN] = {0};
if (!t15execute(T15SYSTEM_INFO,cmdstr,reply))
{
return 0;
}
// 开始解释数据.
char *p;
char tflag[5], iflag, rflag;
{
if (! (p = strchr (reply, '[') ) )
return 0;
p++;
if (*p && (*p == ']' || *p == 'z' || *p == 'Z') )
return 0;
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
rflag=(char)strtol(tflag,NULL,16);
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
if( rflag != 0x00) //Err-Flag is set
{
return rflag;
}
else
{
iflag=(char)strtol(tflag,NULL,16);
*pinfoFlag = iflag;
p += 16;
if( iflag & 0x01 )
{
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
*pDSFID =(char)strtol(tflag,NULL,16);
}
if( iflag & 0x02 )
{
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
*pAFI =(char)strtol(tflag,NULL,16);
}
if( iflag & 0x04 )
{
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
*pBlockNum =(char)strtol(tflag,NULL,16);
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
*pBlockSize = ((char)strtol(tflag,NULL,16))&0x1F;
}
if( iflag & 0x08 )
{
tflag[0]=*p++;
tflag[1]=*p++;
tflag[2]='\0';
*pICRef = ((char)strtol(tflag,NULL,16))&0x1F;
}
}
}
return rflag;
}
// VCD不处理一些参数的合法性判断比如nFirstBlock等
// 因为1. VCD没有必要保留2.射频场中可能存在不同的VICC从而导致参数不同;
// 3. 不要说VCD知道每个UID的参数所以判断。虽然可以但不合理即使pucUID=NULL即处理SELECT模式的VICC时虽然
// VCD的确知道是哪个VICC。这个任务应该交给VICCVICC会返回错误通知用户
// 用户可以在inventory后使用get system info获取需要的信息;
int CVCDOurs::readBlocks( int nFirstBlock, int nBlockNum, uchar_t *pDat, uchar_t *pSecurity, uchar_t *pucUID )
{
// m_nBlockNum想表示 VICC 的可用block数。
// 可以不做这种判断毕竟m_nBlockNum不是VCD的参数而是VICC的属性应该由VICC判断并返回.
char str[100];
t15bOption = 0;
t15bInventory = 0;
if( pucUID )
{
t15bSelect = 0;
t15bAddress=1;
HexToString( pucUID, 8, str );
t15changeByteOrder( t15UID, str, 16 );
t15UID[16]=0;
}
else
{
t15bSelect = 1;
t15bAddress =0;
}
sprintf( t15FirstBN, "%02d", nFirstBlock );
sprintf( t15NumBl, "%02d", nBlockNum - 1 );
//执行命令
char cmdstr[CMD_LEN] = {0},reply[CMD_LEN] = {0};
int cmdno = ( nBlockNum == 1 )?READ_SB:READ_MB;
if (!t15execute(cmdno,cmdstr,reply))
{
return false;
}
//处理返回数据
char *p,*q,tstr[CMD_LEN];
p=strchr(reply,'[')+1;
if(NULL == p)
return 0;
q=strchr(p,']');
if(NULL == q)
return 0;
*q=0;
// if('z' == *p )
// 2023/7/4修改:
// 返回的reply出现过如下的值: “[]”
// 此时*q=0,导致']'被0替换
// 后续代码 tf[0/1] = *p++,导致 p > q;
// 再调用t15changeByteOrder()时q-p = -2 < 0;
// 而t15changeByteOrder()函数定义如下:
/*
HF15693_API void t15changeByteOrder(char *pout, const char *pin,int lenbytes)
{
int i;
for (i = 0; i < lenbytes; i += 2)
{
pout[lenbytes-2-i] = pin[i];
pout[lenbytes-1-i] = pin[i+1];
}
pout[lenbytes] = 0;
}
*/
// 在 lenbytes =-2 < 0的情况下直接访问了pout[-2],导致程序直接崩溃!
// 修改如下:
if('z' == *p || p == q )
{
return 0;
}
// 同时放开该判断!
if(2 < q-p)
{
char tf[3];
tf[0]=*p++;
tf[1]=*p++;
tf[2]=0;
int tfi=strtoul(tf,NULL,10);
// 因为代码:*q = 0导致tf是空串
// 因此tfi=0, 所以下述语句起不到判断作用;
if(OP_RESPONSE_FLAG_ERROR & tfi) //检查标志位,是否发生错误
return 0;
if(READ_SB == cmdno)
{
t15changeByteOrder(tstr,p,q-p);
}
else
{
int i=strtoul(t15NumBl,NULL,10)+1;
t15changeByteOrder_MB(tstr,p,i);
}
StringToHex( tstr, pDat );
return strlen( tstr )/2;
}
return 0;
}
int CVCDOurs::getValueFromChar( char c )
{
if( c >= '0' && c <= '9' )
{
return c-'0';
}
else if( c >= 'a' && c <= 'f' )
{
return c-'a' + 10;
}
else if( c >= 'A' && c <= 'F' )
{
return c - 'A' + 10;
}
else
{
return -1;
}
}
// 返回UID的字节长度
// 如果不是偶数把str最后一个字符丢弃
int CVCDOurs::StringToHex( char *str, uchar_t aucUID[] )
{
int k = 0;
int t1, t2;
int len = strlen( str )/2;
for( int i = 0; i < len; i++ )
{
t1 = getValueFromChar(str[k++]);
t2 = getValueFromChar(str[k++]);
aucUID[i] = ( t1 << 4 ) + t2;
}
return len;
}
void CVCDOurs::HexToString( uchar_t aucDat[], int len, char *str )
{
int k = 0;
int t;
for( int i = 0; i < len; i++ )
{
t = aucDat[i] >> 4;
if( t <= 9 )
{
str[k++] = t + '0';
}
else
{
str[k++] = t - 10 + 'A';
}
t = aucDat[i] & 0x0F;
if( t <= 9 )
{
str[k++] = t + '0';
}
else
{
str[k++] = t - 10 + 'A';
}
}
str[k] = '\0';
}
int CVCDOurs::writeBlocks( int nFirstBlock, int nBlockNum, uchar_t *pDat, uchar_t *pucUID )
{
int k = 0;
for( int i = 0; i < nBlockNum; i++ )
{
k += writeBlock( nFirstBlock + i, pDat+i*8, pucUID );
}
return k;
}
int CVCDOurs::writeBlock( int nFirstBlock, uchar_t *pDat, uchar_t *pucUID )
{
char str[100];
t15bOption = 0;
t15bInventory = 0;
t15bSelect = 0;
if( pucUID )
{
t15bAddress = 1;
HexToString( pucUID, 8, str );
t15changeByteOrder( t15UID, str, 16 );
t15UID[16]=0;
}
else
{
t15bAddress = 0;
}
sprintf( t15FirstBN, "%02d", nFirstBlock );
sprintf( t15NumBl, "00" );
// 此处4是blocksize.
HexToString( pDat, 4, str );
t15changeByteOrder( t15Data, str, 8 );
t15Data[8]=0;
strcpy( str, t15Data );
char cmdstr[CMD_LEN] = {0}, reply[CMD_LEN] = {0};
if (!t15execute(WRITE_SB,cmdstr,reply))
{
// MessageBox("执行错误,可能参数错误", 0, MB_ICONSTOP);
return 0 ;
}
char *p,*e;
if (! (p = strchr (reply, '[') ) )
return 0;
p++;
//if (*p && (*p == ']' || *p == 'z' || *p == 'Z') ) return 2;
if (! (e = strchr(p, ']')))
return 0;
if (e == p)
return 0;
// if( 2 <= e-p)
{
char tf[3];
tf[0] = *p++;
tf[1] = *p++;
tf[2] = '\0';
char tfi=(char)strtol(tf,NULL,16);//
if (OP_RESPONSE_FLAG_ERROR & tfi)
return 0;
else
return 1;
}
}

146
VCDOurs.h Normal file
View File

@ -0,0 +1,146 @@
//#pragma once
#ifndef _VCD_OURS_H_
#define _VCD_OURS_H_
#include "VCD.h"
#include "HF15693.h"
class CVCDOurs :
public CVCD
{
public:
CVCDOurs(void);
~CVCDOurs(void);
public:
virtual int connectReaderByCOM( int comno );
virtual void disconnectReaderByCOM( );
public:
int inventory( char *pTagUID[] );
// 执行inventory!
// ours reader: 支持AFI
// 但不返回DSFID.
//
virtual int inventory(
bool bAFIUsed,
uchar_t ucAFI,
int nViccNum, // 应用层的接收的UID数量;
uchar_t aucDSFID[],
uchar_t aucUID[][8] );
// 通过该命令或者VICC信息
//
virtual int getSystemInfo(
uchar_t *pucUID,
uchar_t *pinfoFlag,
uchar_t *pDSFID, uchar_t *pAFI, uchar_t *pBlockNum, uchar_t *pBlockSize, uchar_t *pICRef
);
//------------------------------------------
// 操作
// 操作类命令寻址模式只能地址或者select
//
// 0x20
virtual int readSingleBlock(
uchar_t *pucUID, // NULL表示select模式
uchar_t optional_flag, // optional bit = 1, 要求返回block的安全状态
uchar_t ucBlkno, // blockno
uchar_t buf[], // 返回读取的数据
uchar_t *pucSecurity // 如果optional_flag = 1, 返回该block的安全状态1表示locked.
)
{
// 没有处理optional-flag
//
t15bOption = optional_flag;
return readBlocks( ucBlkno, 1, buf, pucSecurity, pucUID );
}
// 0x21
virtual int writeSingleBlock(
uchar_t *pucUID, // NULL表示select模式
uchar_t ucBlkno, //
uchar_t ucBlksize,
uchar_t buf[] )
{
return writeBlocks( ucBlkno, 1, buf, pucUID );
}
// 0x23
virtual int readMultipleBlocks(
uchar_t *pucUID, // NULL表示select模式
uchar_t optional_flag, // optional bit = 1, 要求返回block的安全状态
uchar_t ucBlkno, // 开始block no
uchar_t blocknum, // 实际读的block是blocknum+1;
uchar_t buf[], // 返回读取的数据
uchar_t aucSecurity[] // 如果optional_flag = 1, 返回该block的安全状态1表示locked.
)
{
t15bOption = optional_flag;
return readBlocks( ucBlkno, blocknum+1, buf, aucSecurity, pucUID );
}
// 0x24
virtual int writeMultipleBlocks(
uchar_t *pucUID, // NULL表示select模式
uchar_t ucBlkno, // 开始block no
uchar_t blocknum, // 实际写的block是blocknum+1;
uchar_t ucBlksize,
uchar_t buf[] )
{
return writeBlocks( ucBlkno, blocknum, buf, pucUID );
}
// 返回UID的长度
int StringToHex( char *str, uchar_t aucUID[] );
bool opened( )
{
return m_bComOpened;
}
protected:
int doInventory( char *pTagUID[] );
// CMD: 0x2B
//
protected:
void HexToString( uchar_t aucDat[], int len, char *str );
int getValueFromChar( char c );
// 数据保存方式:
// block从 L->H
// 每个block中从byte 0 - byte N-1
// 返回:<0 失败
// block序号从0开始.
// pTagUID = NULL表示采用select模式。
// nBlockNum: 1...
int readBlocks( int nFirstBlock, int nBlockNum, uchar_t *pDat, uchar_t *pSecurity, uchar_t *pucTagUID = NULL );
int writeBlocks( int nFirstBlock, int nBlockNum, uchar_t *pDat,uchar_t *pucTagUID = NULL );
// nxp dosn't support write multiblocks;
int writeBlock( int nFirstBlock, uchar_t *pDat,uchar_t *pucTagUID = NULL );
int getVICCstr( char *szUID )
{
uchar_t aucUID[8];
if( StringToHex( szUID, aucUID ))
{
return getVICC( aucUID );
}
return -1;
}
bool setVICCStr( char *szUID )
{
uchar_t aucUID[8];
if( StringToHex( szUID, aucUID ))
{
return setVICC( aucUID );
}
return false;
}
protected:
bool m_bComOpened;
};
#endif;

64
databaseAPI.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "databaseAPI.h"
Database::Database(QSqlDatabase database)
{
db = database;
db.setDatabaseName(databaseName);
db.setUserName(userName);
}
Database::Database(QSqlDatabase database, QString hostName, int port, QString password)
{
db = database;
db.setDatabaseName(databaseName);
db.setUserName(userName);
db.setHostName(hostName);
db.setPort(port);
db.setPassword(password);
}
QSqlDatabase Database::getDatabase()
{
return db;
}
void Database::setHostName(QString hostName)
{
db.setHostName(hostName);
}
QString Database::getHostName()
{
return db.hostName();
}
void Database::setPort(int port)
{
db.setPort(port);
}
int Database::getPort()
{
return db.port();
}
void Database::setPassword(QString password)
{
db.setPassword(password);
}
bool Database::is_connected()
{
return connected;
}
bool Database::open()
{
connected = db.open();
return connected;
}
Database::~Database()
{
db.close();
}

View File

@ -15,68 +15,17 @@ private:
QString userName = QString("cardManageSystem");
public:
Database(QSqlDatabase database)
{
db = database;
db.setDatabaseName(databaseName);
db.setUserName(userName);
}
Database(QSqlDatabase database, QString hostName, int port, QString password)
{
db = database;
db.setDatabaseName(databaseName);
db.setUserName(userName);
db.setHostName(hostName);
db.setPort(port);
db.setPassword(password);
}
QSqlDatabase getDatabase()
{
return db;
}
void setHostName(QString hostName)
{
db.setHostName(hostName);
}
QString getHostName()
{
return db.hostName();
}
void setPort(int port)
{
db.setPort(port);
}
int getPort()
{
return db.port();
}
void setPassword(QString password)
{
db.setPassword(password);
}
bool is_connected()
{
return connected;
}
bool open()
{
connected = db.open();
return connected;
}
~Database()
{
db.close();
}
Database(QSqlDatabase database);
Database(QSqlDatabase database, QString hostName, int port, QString password);
QSqlDatabase getDatabase();
void setHostName(QString hostName);
QString getHostName();
void setPort(int port);
int getPort();
void setPassword(QString password);
bool is_connected();
bool open();
~Database();
};

41
deviceAPI.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "deviceAPI.h"
bool Device::is_connected()
{
return connected;
}
bool Device::is_depositAllowed()
{
return depositAllowed;
}
void Device::setDevice(QString name, Database *db)
{
QSqlQuery query(db->getDatabase());
QString sql = QString("select * from device where `name` = '%1';").arg(name);
query.exec(sql);
if (query.next())
{
connected = true;
this->name = name;
depositAllowed = query.value(2).toBool();
}
else
{
connected = false;
depositAllowed = false;
}
}
QString Device::getName()
{
if (connected) {
if (depositAllowed) return name + QString("(可充值)");
else return name + QString("(仅可消费)");
}
else return QString("未指定设备名");
}

View File

@ -13,42 +13,10 @@ private:
QString name = QString("未指定设备名");
public:
bool is_connected()
{
return connected;
}
bool is_depositAllowed()
{
return depositAllowed;
}
void setDevice(QString name, Database *db)
{
QSqlQuery query(db->getDatabase());
QString sql = QString("select * from device where `name` = '%1';").arg(name);
query.exec(sql);
if (query.next())
{
connected = true;
this->name = name;
depositAllowed = query.value(2).toBool();
}
else
{
connected = false;
depositAllowed = false;
}
}
QString getName()
{
if (connected) {
if (depositAllowed) return name + QString("(可充值)");
else return name + QString("(仅可消费)");
}
else return QString("未指定设备名");
}
bool is_connected();
bool is_depositAllowed();
void setDevice(QString name, Database *db);
QString getName();
};
#endif // DEVICEAPI_H

View File

@ -1,8 +1,8 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingPage.h"
#include "quitAppPage.h"
#include "newCardPage.h"
#include "settingPage.cpp"
#include "quitAppPage.cpp"
#include "newCardPage.cpp"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@ -36,6 +36,12 @@ MainWindow::MainWindow(QWidget *parent)
deviceLabel = new QLabel(device.getName());
ui->statusBar->addWidget(deviceLabel);
// 清空部分输入框
ui->userIdBox->clear();
// 设置启动页面
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}

View File

@ -277,7 +277,7 @@
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox">
<widget class="QSpinBox" name="userIdBox">
<property name="minimumSize">
<size>
<width>200</width>
@ -290,6 +290,12 @@
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>1000</number>
</property>
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
<item row="0" column="1">

View File

@ -1,6 +1,3 @@
#ifndef NEWCARDPAGE_H
#define NEWCARDPAGE_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
@ -14,7 +11,10 @@ void MainWindow::on_NewCardAction_triggered()
if (!ready())
{
QMessageBox::warning(this, QString("提示"), QString("读卡器或数据库未连接,请设置。"));
ui->stackedWidget->setCurrentWidget(ui->settingPage);
if (ui->stackedWidget->currentWidget() != ui->settingPage)
{
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}
return;
}
@ -28,8 +28,7 @@ void MainWindow::on_NewCardAction_triggered()
*/
void MainWindow::on_inventoryButton_clicked()
{
QStringList cardIdList = reader.inventory(10); // 最多显示10张卡
ui->cardIdBox->clear();
ui->cardIdBox->addItems(cardIdList);
}
#endif // NEWCARDPAGE_H

View File

@ -1,6 +1,3 @@
#ifndef QUITAPPPAGE_H
#define QUITAPPPAGE_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
@ -23,6 +20,3 @@ void MainWindow::on_confirmQuitButton_clicked()
{
this->close();
}
#endif // QUITAPPPAGE_H

46
readerAPI.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "readerAPI.h"
bool Reader::is_connected()
{
return comNumber > 0;
}
bool Reader::connect()
{
if (CVCDOurs::connectReaderByCOM(comNumber))
{
return true;
}
else
{
comNumber = -1;
return false;
}
}
void Reader::setComNumber(int comNumber)
{
this->comNumber = comNumber;
}
int Reader::getComNumber()
{
return comNumber;
}
QStringList Reader::inventory(int maxViccNum)
{
uchar_t (*aucUID)[8] = (uchar_t (*)[8])malloc(maxViccNum * sizeof(*aucUID));;
int receivedViccNum = CVCDOurs::inventory(false, '\0', maxViccNum, nullptr, aucUID);
QStringList uidList;
for (int i = 0; i < receivedViccNum; ++i)
{
char uidStr[8];
CVCDOurs::HexToString(aucUID[i], 8, uidStr);
uidList.push_back(QString::fromStdString(uidStr));
}
free(aucUID);
return uidList;
}

View File

@ -2,42 +2,25 @@
#define READERAPI_H
#include <HF15693.h>
#include <cstdio>
#include <cstring>
#include <QString>
#include <QStringList>
#include <VCDOurs.h>
typedef unsigned char uchar_t;
class Reader
class Reader : private CVCDOurs
{
private:
int comNumber = -1; // com口号若未连接为-1
public:
bool is_connected()
{
return comNumber > 0;
}
bool connectReader()
{
if (t15portOpen(comNumber))
{
return true;
}
else
{
comNumber = -1;
return false;
}
}
void setComNumber(int comNumber)
{
this->comNumber = comNumber;
}
int getComNumber()
{
return comNumber;
}
bool is_connected();
bool connect();
void setComNumber(int comNumber);
int getComNumber();
QStringList inventory(int maxViccNum);
};
#endif // READERAPI_H

View File

@ -1,6 +1,3 @@
#ifndef SETTINGPAGE_H
#define SETTINGPAGE_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
@ -45,7 +42,7 @@ void MainWindow::on_connectReaderButton_clicked()
{
int comNumber = ui->comNumberBox->value();
reader.setComNumber(comNumber);
bool connectSuccess = reader.connectReader();
bool connectSuccess = reader.connect();
if (!connectSuccess) {
QString warningMessage = QString("COM") + QString::number(comNumber);
@ -105,6 +102,3 @@ bool MainWindow::ready()
if (!device.is_connected()) return false;
return true;
}
#endif // SETTINGPAGE_H