#include <cstdlib>
#include "VCDOurs.h"
#include "qlogging.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。这个任务应该交给VICC，VICC会返回错误通知用户；
// 用户可以在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*4, 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;
	}
}
