#include "type_a.h"

#define TAG         "type_a"

/******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/******************************************************************************
 * Local variable definitions ('static')                                      *
 ******************************************************************************/


/*****************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/

/*********************************************************************************************************
** Function name:       RightMoveBit        
** Descriptions:        该函数实现一个字节多少个1
** input parameters:    bitNum: 右边多少个1
** output parameters:   
** Returned value:      
*********************************************************************************************************/
uint8_t RightMoveBit(uint8_t bitNum)
{
    uint8_t temp,i;
    temp = 0x00;
    for (i=0; i < bitNum; i++) {
       temp >>=1;
       temp += 0x80;
    }
    return temp;
}

/*********************************************************************************************************
** Function name:       RightMoveBit        
** Descriptions:        该函数实现一个字节多少个1
** input parameters:    bitNum: 左边多少个1
** output parameters:   
** Returned value:      
*********************************************************************************************************/
uint8_t LeftMoveBit(uint8_t bitNum)
{
    uint8_t temp,i;
    temp = 0x00;
    for (i=0; i < bitNum; i++) {
        temp <<=1;
        temp += 0x01;
    }
    return temp;
}

/*********************************************************************************************************
** Function name:       CollSaveUID        
** Descriptions:        通过前一次冲突位置和后一次冲突位置保存UID
** input parameters:    preColl:前一次冲突位置
                        nowColl:后一次冲突位置
                        uid:保存UID指针
** output parameters:   void
** Returned value:      
*********************************************************************************************************/
void CollSaveUID(uint8_t preColl, uint8_t nowColl, uint8_t *buff, uint8_t *uid)
{
    uint8_t i,j,preBytes,preBits,nowBytes,nowBits;
    uint8_t temp;
    preBytes = preColl / 8;
    preBits  = preColl % 8;
    nowBytes = nowColl / 8;
    nowBits  = nowColl % 8;
    
    if(preColl == 0) {                                                    /* 之前没有冲突位，直接保存     */
        for(i=0; i < nowBytes; i++)
            uid[i] = buff[i];          
        uid[nowBytes] = buff[nowBytes] & LeftMoveBit(nowBits);
    } else {                                                              /* 之前有冲突                   */
        if(nowBytes > preBytes) {
            temp = RightMoveBit(8 - preBits);
            temp = buff[0] & temp;
            uid[preBytes] |= temp;
            if(nowBytes > (preBytes+1)) {                                 /* 保存完整字节uid              */
                for(i=1, j=0; j < (nowBytes-preBytes-1); i++, j++)
                    uid[preBytes+i] = buff[i];  
            }
            if(nowBits) {                                                 /* 保存位UID                   */
                uid[nowBytes] = buff[nowBytes] & LeftMoveBit(nowBits);
            }
        } else {
              temp = buff[0] & LeftMoveBit(nowBits);           
              uid[preBytes] |= temp;
        }
    }
}

/*********************************************************************************************************
** Function name:       Save_UID        
** Descriptions:        该函数实现保存卡片收到的序列号 
** input parameters:    Bytes: 产生冲突的字节    
**                      Bits: 产生冲突的位    
**                      length: 接収到的UID数据长度 
**                      buff:读回来的UID信息
** output parameters:   picc_uid：需要保存的UID信息
** Returned value:      void
*********************************************************************************************************/
void TypeA_Save_UID(uint8_t Bytes,uint8_t Bits,uint8_t length,             
                      uint8_t *buff,uint8_t *card_uid)
{
    uint8_t i, temp1, temp2;
    
    temp1 = card_uid[Bytes - 1];                                        /* ?为何减1？前一次接收到的最后一个有效UID*/
    temp2 = buff[0];                                                    /* 后一次接收到的第一个有效UID  */
    
    switch (Bits) {
      
    case 0:
        temp1 = 0x00;
        Bytes = Bytes + 1;                                             /* +1是为了抵消140行处的-1操作，且新收的temp2为准，所以temp2为0x00 */
        break;
    case 1:
        temp1 = temp1 & 0x01;
        temp2 = temp2 & 0xFE;
        break;
    case 2:
        temp1 = temp1 & 0x03;
        temp2 = temp2 & 0xFC;
        break;
    case 3:
        temp1 = temp1 & 0x07;
        temp2 = temp2 & 0xF8;
        break;
    case 4:
        temp1 = temp1 & 0x0F;
        temp2 = temp2 & 0xF0;
        break;
    case 5:
        temp1 = temp1 & 0x1F;
        temp2 = temp2 & 0xE0;
        break;
    case 6:
        temp1 = temp1 & 0x3F;
        temp2 = temp2 & 0xC0;
        break;
    case 7:
        temp1 = temp1 & 0x7F;
        temp2 = temp2 & 0x80;
        break;
    default:
        break;
    }
    card_uid[Bytes - 1] = temp1 | temp2;                                /* 结合前后两部分               */
    for (i = 1; i < length; i++) {
        card_uid[Bytes - 1 + i] = buff[i];
    }
}

/*********************************************************************************************************
** Function name:       Set_BitFraming        
** Descriptions:        该函数实现对收到的卡片的序列号的判断
** input parameters:    bytes: 已知的UID字节数  
**                      bits: 额外的已知UIDbits        
**                      length: 接収到的UID数据长度 
** output parameters:   NVB:防冲突种类
** Returned value:      void
*********************************************************************************************************/
void TypeA_Set_BitFraming(uint8_t collBit,uint8_t *NVB)
{
    uint8_t bytes,bits;
    bytes = collBit/8;
    bits = collBit%8;
    switch(bytes) {
        case 0: 
            *NVB = 0x20;
            break;
        case 1:
            *NVB = 0x30;
            break;
        case 2:
            *NVB = 0x40;
            break;
        case 3:
            *NVB = 0x50;
            break;
        case 4:
            *NVB = 0x60;
            break;
        case 5:
            *NVB = 0x70;                                                      
            break;
        default:
            break;
    }    
    switch(bits) {
        case 0:
            Write_Reg(BitFramingReg,0x00);
            break;
        case 1:
            Write_Reg(BitFramingReg,0x11);
            *NVB = (*NVB | 0x01);
            break;
        case 2:
            Write_Reg(BitFramingReg,0x22);
            *NVB = (*NVB | 0x02);
            break;
        case 3:
            Write_Reg(BitFramingReg,0x33);
            *NVB = (*NVB | 0x03);
            break;
        case 4:
            Write_Reg(BitFramingReg,0x44);
            *NVB = (*NVB | 0x04);
            break;
        case 5:
            Write_Reg(BitFramingReg,0x55);
            *NVB = (*NVB | 0x05);
            break;
        case 6:
            Write_Reg(BitFramingReg,0x66);
            *NVB = (*NVB | 0x06);
            break;
        case 7:
            Write_Reg(BitFramingReg,0x77);
            *NVB = (*NVB | 0x07);
            break;
        default:
            break;
    }
}

/*********************************************************************************************************
** Function name:       TypeA_Request        
** Descriptions:        TypeA_Request卡片寻卡    
** input parameters:    N/A
** output parameters:   picc_cid
** Returned value:      true：操作成功 ERROR：操作失败    
*********************************************************************************************************/
bool TypeA_Request(uint8_t *pTagType)
{
    uint8_t result, send_buff[1], rece_buff[2];
    uint32_t  rece_bitlen;
    Clear_BitMask(TxModeReg,  0x80);                                     /* 关闭TX CRC                  */
    Clear_BitMask(RxModeReg,  0x80);                                     /* 关闭RX CRC                  */
    Set_BitMask(RxModeReg,    0x08);                                     /* 关闭位接收                  */
    Clear_BitMask(Status2Reg, 0x08);                                     /* 清除加密标志 使用明文通信   */                 
    Set_BitMask(BitFramingReg,0x07);                                     /* 最后一字节发送7位           */                  
    send_buff[0] = 0x26;                                                 /* 请求命令（1字节） 0x26      */               
    Pcd_SetTimer(1);                                                     /* 设置接收延时                */
    
    Clear_FIFO();
    result = Pcd_Comm(Transceive, send_buff, 1, rece_buff, &rece_bitlen);
    if ((result == true) && (rece_bitlen == 2 * 8)) {                    /* 正常接收到2字节返回信息  ATQA信息 高8位保留 低8位的bit6和bit7显示UID长度 */
        *pTagType       = rece_buff[0];
        *(pTagType + 1) = rece_buff[1];
    } else {
        result = false;
    }
    return result;
}

/*********************************************************************************************************
** Function name:       TypeA_Anticollision        
** Descriptions:        卡片防冲突    
** input parameters:    selcode：卡片选择编码 0x93，0x95，0x97    
**                      picc_uid：卡片UID号
** output parameters:   N/A
** Returned value:      true：操作成功 ERROR：操作失败    
*********************************************************************************************************/
bool TypeA_Anticollision(uint8_t selcode, uint8_t *uid)
{
    uint8_t send_buff[10];
    uint8_t rece_buff[5];
	  uint8_t result;
    uint8_t nBytes,preCollBit,nowCollBit;    
    uint32_t 	rece_bitlen;
    Clear_BitMask(TxModeReg,  0x80);                                        /* 关闭TX CRC                  */
    Clear_BitMask(RxModeReg,  0x80);                                        /* 关闭RX CRC                  */
    Clear_BitMask(Status2Reg, 0x08);                                        /* 清除验证标志，使用明文通信  */
    Write_Reg(BitFramingReg,  0x00);                                        /* 最后一字节发送8位           */
    Clear_BitMask(CollReg,    0x80);                                        /* 清除防冲突位                */
    
    memset(uid, 0x00, 5);
    memset(rece_buff, 0x00, 5);
    preCollBit = 0;
	  nowCollBit = 0;
    result = Anticollision; 
    while (result == Anticollision) {
        CollSaveUID(preCollBit,nowCollBit,&rece_buff[0],uid);					  
        preCollBit   = nowCollBit;
        send_buff[0] = selcode;                                             /* 防冲突命令                  */
        TypeA_Set_BitFraming(preCollBit, &send_buff[1]);                    /* 设置NVB发送                 */
        nBytes = (preCollBit / 8) + ((preCollBit % 8) ? 1:0);               /* 计算已有ID号长度              */
        memcpy(&send_buff[2], uid, nBytes);                                 /* 将有效字节拷贝到发送buff    */   
        Pcd_SetTimer(10);                                                   /* 设置定时器                  */
        Clear_FIFO();
        result = Pcd_Comm(Transceive, send_buff, 2 + nBytes, rece_buff, &rece_bitlen);
//				ESP_LOGI(TAG, " Pcd_Comm=0x%x\r\n",result);
				nowCollBit = (uint8_t)(rece_bitlen & 0xff);                         /* 保存当前冲突位置            */
//				ESP_LOGI(TAG, " nowCollBit=0x%x\r\n",nowCollBit);
//				ESP_LOGI(TAG, " rece_buff:0x%x 0x%x 0x%x 0x%x 0x%x\r\n",rece_buff[0],rece_buff[1],rece_buff[2],rece_buff[3],rece_buff[3]);
        if (result == true) {
            CollSaveUID(preCollBit, nowCollBit, rece_buff, uid);            /* 存下已得到的UID             */
        }
    }
//		ESP_LOGI(TAG, " UID:0x%x 0x%x 0x%x 0x%x\r\n",uid[0],uid[1],uid[2],uid[3]);
    if (uid[4] != (uid[0]^uid[1]^uid[2]^uid[3])) {                          /* 异或UID校验                 */  
        if (true == result) {
            result = false;
        }
    }
    return result;
}

/*********************************************************************************************************
** Function name:       TypeA_Select        
** Descriptions:        选择卡片
** input parameters:    selcode：卡片选择编码 0x93，0x95，0x97    
**                      pSnr：卡片UID号
**                      pSak：卡片选择应答
** output parameters:   N/A
** Returned value:      true：操作成功 ERROR：操作失败    
*********************************************************************************************************/
bool TypeA_Select(uint8_t selcode, uint8_t *pSnr, uint8_t *pSak)
{   
    uint8_t result,i, send_buff[7], rece_buff[5];
    uint32_t  rece_bitlen;
    Write_Reg(BitFramingReg, 0x00);
    Set_BitMask(TxModeReg, 0x80);                                       /* 打开TX CRC                   */
    Set_BitMask(RxModeReg, 0x80);                                       /* 打开RX CRC校验               */
    Clear_BitMask(Status2Reg, 0x08);                                    /* 清除验证标志位               */
    send_buff[0] = selcode;                                             /* select命令                   */
    send_buff[1] = 0x70;                                                /* NVB                          */
    for (i = 0; i < 5; i++) {
        send_buff[i+2] = *(pSnr+i);                                     /* 将接收到的UID写入，可能是4字节完整UID，也可能是CT连接字节+3字节UID */
    }
    send_buff[6] = pSnr[0]^pSnr[1]^pSnr[2]^pSnr[3];                     /* 尾部BCC字节 */
    Pcd_SetTimer(1);
    Clear_FIFO();
    result = Pcd_Comm(Transceive, send_buff, 7, rece_buff, &rece_bitlen);
    if (result == true) {
        *pSak = rece_buff[0]; 
    }
    return result;
}

/*********************************************************************************************************
** Function name:       TypeA_CardActive        
** Descriptions:        函数实现寻卡防冲突和选择卡
** input parameters:    pTagType: 卡片类型 ATQA
**                      pSnr: 卡片UID
**                      pSak: 卡片应答数据 SAK
** output parameters:   N/A
** Returned value:      true：操作成功 ERROR：操作失败    
*********************************************************************************************************/
bool TypeA_CardActive(uint8_t *pTagType, uint8_t *pSnr, uint8_t *pSak)
{
    uint8_t result;
    result = TypeA_Request(pTagType);                                   /* 寻卡 Standard                */
    if (result != true) {
		    return false;
		}
	  if ( (pTagType[0] & 0xC0) == 0x00 ) {                               /* M1卡,高两位（b7和b6）为00，ID号只有4位  */
        result = TypeA_Anticollision(0x93, pSnr);
        if (result != true) {
            return false;
        }
        result = TypeA_Select(0x93, pSnr, pSak);                        /* 选择UID                      */
        if (result != true) {
            return false;
        }
    }
    if ( (pTagType[0] & 0xC0) == 0x40 ) {                               /* 高两位（b7和b6）为01，ID号有7位         */
        result = TypeA_Anticollision(0x93, pSnr);
        if (result != true) {
            return false;
        }
        result = TypeA_Select(0x93, pSnr, pSak);
        if (result != true) {
            return false;
        }
        result = TypeA_Anticollision(0x95, pSnr + 5);
        if (result != true) {
            return false;
        }
        result = TypeA_Select(0x95, pSnr + 5, pSak + 1);
        if (result != true) {
            return false;
        }
    }
		
    if( (pTagType[0] & 0xC0) == 0x80 ) {                                /* 高两位（b7和b6）为10，ID号有10位       */
        result = TypeA_Anticollision(0x93, pSnr);
        if (result != true) {
            return false;
        }
        result = TypeA_Select(0x93, pSnr, pSak);
        if (result != true) {
             return false;
        }
        result = TypeA_Anticollision(0x95, pSnr + 5);
        if (result != true) {
            return false;
        }
        result = TypeA_Select(0x95, pSnr + 5, pSak + 1);
        if (result != true) {
            return false;
        }
        result = TypeA_Anticollision(0x97, pSnr + 10);
        if (result != true) {
            return false;
        }
        result = TypeA_Select(0x97, pSnr + 10, pSak + 2);
        if (result != true) {
            return false;
        }
    }
    return result;
}

/*********************************************************************************************************
** Function name:       TypeA_Halt        
** Descriptions:        卡片睡眠
** input parameters:    AnticollisionFlag 休眠验证标志 
**                      AnticollisionFlag = 0 没有验证，使用明文通信，需要清除验证标志
**                      AnticollisionFlag = 1 密码验证函数通过，使用密文通信，不需要清除验证标志
** output parameters:   N/A
** Returned value:      true：操作成功 ERROR：操作失败    
*********************************************************************************************************/
bool TypeA_Halt(uint8_t AnticollisionFlag)
{
    uint8_t result, send_buff[2], rece_buff[1];
    uint32_t rece_bitlen;
    send_buff[0] = 0x50;
    send_buff[1] = 0x00; 

    Write_Reg(BitFramingReg, 0x00);                                      /* 最后发送一字节8位            */
    Set_BitMask(TxModeReg, 0x80);                                        /* 打开TX CRC                   */
    Set_BitMask(RxModeReg, 0x80);                                        /* 打开RX CRC                   */
    if (!AnticollisionFlag) {
        Clear_BitMask(Status2Reg, 0x08);
    }
    Pcd_SetTimer(1);
    Clear_FIFO();
    result = Pcd_Comm(Transmit, send_buff, 2, rece_buff, &rece_bitlen);
    return result;
}

/*********************************************************************************************************
** Function name:       TypeA_WakeUp        
** Descriptions:        卡片唤醒
** input parameters:    N/A
** output parameters:   pTagType[0],pTagType[1] =ATQA 
** Returned value:      true：操作成功 ERROR：操作失败    
*********************************************************************************************************/
bool TypeA_WakeUp(uint8_t *pTagType)
{
    uint8_t result,send_buff[1],rece_buff[2];
    uint32_t rece_bitlen;  
    Clear_BitMask(TxModeReg,  0x80);                                    /* 关闭TX CRC                   */
    Clear_BitMask(RxModeReg,  0x80);                                    /* 关闭RX CRC                   */
    Set_BitMask(RxModeReg,    0x08);                                    /* 不接收小于4bit的数据         */
    Clear_BitMask(Status2Reg, 0x08);                                    /* 清除加密标志，使用明文通信    */
    Write_Reg(BitFramingReg,  0x07);                                    /* 最后一字节发送7位            */
    send_buff[0] = 0x52;
    Pcd_SetTimer(1);

    result = Pcd_Comm(Transceive, send_buff, 1, rece_buff, &rece_bitlen);
    if ((result == true) && (rece_bitlen == 2 * 8)) {
        *pTagType     = rece_buff[0];
        *(pTagType+1) = rece_buff[1];
    } else {
        result = false; 
    }
    return result;
}
