

/*************************************************
File:               BMZ00050.cpp
Author:             Tree
Description:        對倍創NFC模塊BMZ00050應用庫，進行函數功能進行具體描寫
History：            版本修改描述
  V1.00.1   -- initial version；2021-04-01；Arduino IDE :  ≥v1.8.13
**************************************************/


#include "Arduino.h"
#include "BMZ00050.h"
 /*************************************************
Description:        構造函數，使用硬件UART
Input:              @param  workmode SPI通信方式時的工作模式選擇：寄存器模式/透傳模式
Output:             
Return:             
Others:             
*************************************************/
BMZ00050::BMZ00050(uint8_t workmode)
{
  spi_dev = NULL;
  iic_dev = NULL;
   if(workmode==1)
   _nfcmode=1;
   else
   _nfcmode=0;
}

 /*************************************************
Description:        構造函數，使用硬件SPI
Input:              @param  irq  SPI通信方式時的int線選擇
                    @param  csc  SPI通信方式時的csc線選擇
                    @param  workmode SPI通信方式時的工作模式選擇：寄存器模式/透傳模式
Output:             
Return:             
Others:             
*************************************************/
BMZ00050::BMZ00050(uint8_t irq,uint8_t scs, uint8_t workmode)
{
    spi_dev = new BM_SPI_MASTER(scs,SPI_CLOCK_DIV128, MSBFIRST, SPI_MODE0,&SPI);
    _irq = irq;
    pinMode(_irq,INPUT);
    _ss=scs;
    iic_dev = NULL;
    if(workmode==1)
    _nfcmode=1;
    else
    _nfcmode=0;
}

 /*************************************************
Description:        構造函數，使用軟件SPI
Input:              @param  irq     SPI通信方式時的int線選擇
                    @param  clk     SPI通信方式時的clk線選擇
                    @param  miso    SPI通信方式時的miso線選擇
                    @param  mosi    SPI通信方式時的mosi線選擇
                    @param  csc     SPI通信方式時的csc線選擇
                    @param  workmode SPI通信方式時的工作模式選擇：寄存器模式/透傳模式 
Output:             
Return:             
Others:             
*************************************************/
BMZ00050::BMZ00050(uint8_t irq,uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t scs, uint8_t workmode)
{
    spi_dev = new BM_SPI_MASTER(scs,clk,miso,mosi,SPI_CLOCK_DIV64,MSBFIRST,SPI_MODE0);
    _irq = irq;
    pinMode(_irq,INPUT);
    _ss=scs;
    iic_dev = NULL;
    if(workmode==1)
    _nfcmode=1;
    else
    _nfcmode=0;
}

 /*************************************************
Description:        構造函數，使用硬件IIC
Input:              @param  irq   IIC通信方式時的int線選擇
                    @param  workmode SPI通信方式時的工作模式選擇：寄存器模式/透傳模式
Output:             
Return:             
Others:             
*************************************************/
BMZ00050::BMZ00050(uint8_t irq, uint8_t workmode)
{
    iic_dev = new BM_IIC(0x28);
    _irq = irq;
    pinMode(_irq,INPUT);
    spi_dev = NULL;
    if(workmode==1)
    _nfcmode=1;
    else
    _nfcmode=0;
}

 /*************************************************
Description:        構造函數，使用軟件IIC
Input:              @param  irq  IIC通信方式時的int線選擇
                    @param  scl  IIC通信方式時的scl線選擇
                    @param  sda  IIC通信方式時的sda線選擇
                    @param  workmode SPI通信方式時的工作模式選擇：寄存器模式/透傳模式 
Output:             
Return:             
Others:             
*************************************************/
BMZ00050::BMZ00050(uint8_t irq,uint8_t scl, uint8_t sda, uint8_t workmode)
{
    iic_dev = new BM_IIC(0x28,scl,sda);
    _irq = irq;
    pinMode(_irq,INPUT);
    spi_dev = NULL;
    if(workmode==1)
    _nfcmode=1;
    else
    _nfcmode=0;
}

 /*************************************************
Description:        初始化模塊
Input:              void
Output:             
Return:             void
Others:             
*************************************************/
void BMZ00050::begin(void )
{
    if (spi_dev != NULL)
    {
      spi_dev->begin();
    }
    else if (iic_dev != NULL)
    {
      iic_dev->begin();
    }
    else if ((iic_dev != NULL)&&(spi_dev != NULL))
    {
      Serial.begin(9600);
    }
    delay(10);
    _startime = millis(); //readpacket時使用
}

 /*************************************************
Description:        工作模式選擇模式：寄存器模式/透傳模式
Input:              @param  workingmode  REGISTER，寄存器模式
                                         TRANSMISSION，透傳模式
Output:             
Return:             void
Others:             
*************************************************/
void BMZ00050::setWorkMode(uint8_t workmode)
{
   
   if(workmode==1)
   {
      _nfcmode=1;
   }
   else
   {
      _nfcmode=0;
   }
}

 /*************************************************
Description:        寫命令，私有函數
Input:              @param  *cmd    要發送的命令正常信息幀數組
                    @param  cmdlen  要發送的字節長度
                    @param  *keep   返回的數據存儲數組（除ACK外）
                    @param  keeplen 返回的數據存儲數據個數（除ACK外）
Output:             keep數組存儲長度為keeplen的值
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::sendCommand(uint8_t *cmdbuff, uint8_t cmdlen, uint8_t *keepbuff, uint8_t keeplen)
{
    _flag=0;      //_flag=0
    uint8_t i=0;

////寄存器模式
    if(_nfcmode==1)      //寄存器模式
    {
    uint8_t TFI =cmdbuff[5];
    uint8_t command =cmdbuff[6];
    
////spi模式、寄存器模式
    if(spi_dev != NULL)
    {
        uint8_t cmd2[cmdlen+1]={SPI_DATA_WRITE};
        for(i=0;i<cmdlen;i++)
        {
           cmd2[i+1]=cmdbuff[i];
        }
        spi_dev->writeBytes(cmd2, cmdlen+1);                 //發送命令
        unsigned int star_timer=millis();
        unsigned int now_timer;
        while(digitalRead(_irq)==1)
        {
             now_timer=millis();
             if((now_timer-star_timer)>=spi_timeout)
             {
              _flag=EER_TIMEOUT;   //超時檢測
              return _flag;
              }
        }
        digitalWrite(_ss, LOW);
        spi_dev->transfer(SPI_DATA_READ);
        delayMicroseconds(25);
        spi_dev->readBytes(BMZ00050_keep_ackpacket, 6);     //讀取ACK
        star_timer=millis();
        while(digitalRead(_irq)==1)
        {
            now_timer=millis();
            if((now_timer-star_timer)>=spi_timeout)
            {
                _flag=EER_TIMEOUT;   //超時檢測
                return _flag;
            }
        }
        digitalWrite(_ss, LOW);
        spi_dev->transfer(SPI_DATA_READ);
        delayMicroseconds(25);
        spi_dev->readBytes(keepbuff, keeplen);                   //讀取CMD
        if(0 != memcmp((int8_t *)BMZ00050_keep_ack, (int8_t *)BMZ00050_keep_ackpacket, 6))
        {
            _flag=EER_INVALID_ACK;     //錯誤ACK檢測
            return _flag;
        }
        if((BMZ00050_keep_cmdpacket[5]!=(TFI+1))||(BMZ00050_keep_cmdpacket[6]!=(command+1)))
        {
            _flag=EER_INVALID_FRAME;     //錯誤幀檢測
            return _flag;
        }
    }
////iic模式、寄存器模式
    else if(iic_dev != NULL)
    {
        iic_dev->writeBytes(cmdbuff, cmdlen,1);                 //發送命令
        unsigned int star_timer=millis();
        unsigned int now_timer;
        while(digitalRead(_irq)==1)
        {
             now_timer=millis();
             if((now_timer-star_timer)>=iic_timeout)
             {
              _flag=EER_TIMEOUT;   //超時檢測
              return _flag;
              }
        }
        iic_dev->readBytes(BMZ00050_keep_ackpacket,7,1);     //讀取ACK
        star_timer=millis();
        while(digitalRead(_irq)==1)
        {
            now_timer=millis();
            if((now_timer-star_timer)>=iic_timeout)
            {
                _flag=EER_TIMEOUT;   //超時檢測
                return _flag;
            }
        }
        iic_dev->readBytes(keepbuff, keeplen+1,1);                   //讀取CMD
        
        for(i=0;i<6;i++)
        {
          BMZ00050_keep_ackpacket[i]=BMZ00050_keep_ackpacket[i+1];  //iic寄存器多讀一個RDY
        }
        if(0 != memcmp((int8_t *)BMZ00050_keep_ack, (int8_t *)BMZ00050_keep_ackpacket, 6))
        {
            _flag=EER_INVALID_ACK;     //錯誤ACK檢測
            return _flag;
        }
        for(i=0;i<keeplen;i++)
        {
          BMZ00050_keep_cmdpacket[i]=BMZ00050_keep_cmdpacket[i+1];  //iic寄存器多讀一個RDY
        }
        if((BMZ00050_keep_cmdpacket[5]!=(TFI+1))||(BMZ00050_keep_cmdpacket[6]!=(command+1)))
        {
            _flag=EER_INVALID_FRAME;     //錯誤幀檢測
            return _flag;
        }
    }
////uart模式、寄存器模式
   else if((spi_dev == NULL)&&(iic_dev == NULL))
    {
        unsigned char Uselessvalue;
        while(Serial.available()!=0)
        {
           Uselessvalue=Serial.read();
        }
        
        Serial.write(cmdbuff, cmdlen);                 //發送命令
        unsigned int star_timer=millis();
        unsigned int now_timer;
        while(Serial.available()<15)
        {
            now_timer=millis();
            if((now_timer-star_timer)>=uart_timeout)
            {
                _flag=EER_TIMEOUT;   //超時檢測
                return _flag;
            }
        }

        Serial.readBytes(BMZ00050_keep_ackpacket,6);                   //讀取ACK
        Serial.readBytes(keepbuff,keeplen);                   //讀取CMD
        if(0 != memcmp((int8_t *)BMZ00050_keep_ack, (int8_t *)BMZ00050_keep_ackpacket, 6))
        {
            _flag=EER_INVALID_ACK;     //錯誤ACK檢測
            return _flag;
        }
        if((BMZ00050_keep_cmdpacket[5]!=(TFI+1))||(BMZ00050_keep_cmdpacket[6]!=(command+1)))
        {
            _flag=EER_INVALID_FRAME;     //錯誤幀檢測
            return _flag;
        }
    }
    }
    
////透传模式
    else       //透传模式
    {   
        uint8_t T_header =cmdbuff[0];
        uint8_t T_cmd =cmdbuff[1];
        
////spi模式、透传模式
        if(spi_dev != NULL)
        {
            uint8_t spi_write_data=0x80|cmdlen;
            uint8_t cmd3[cmdlen+1]={spi_write_data};
            for(i=0;i<cmdlen;i++)
            {
               cmd3[i+1]=cmdbuff[i];
            }
            spi_dev->writeBytes(cmd3, cmdlen+1);                 //發送命令
            unsigned int star_timer=millis();
            unsigned int now_timer;
            while(digitalRead(_irq)==1)
            {
                 now_timer=millis();
                 if((now_timer-star_timer)>=spi_timeout)
                 {
                     _flag=EER_TIMEOUT;   //超時檢測
                     return _flag;
                 }
             }
             delay(1);
             digitalWrite(_ss, LOW);
             uint8_t spi_read_data=0x40|keeplen;
             spi_dev->transfer(spi_read_data);
             spi_dev->readBytes(keepbuff, keeplen);                   //讀取CMD
             if(T_header!=0x22)
             {
             if((BMZ00050_keep_cmdpacket[0]!=(T_header+1))||(BMZ00050_keep_cmdpacket[1]!=(T_cmd+1)))
             {
                  _flag=EER_INVALID_FRAME;     //錯誤幀檢測
                  return _flag;
             }
             }
        }
////iic模式、透传模式
        else if(iic_dev != NULL)
        {
            iic_dev->writeBytes(cmdbuff, cmdlen,1);                 //發送命令
            unsigned int star_timer=millis();
            unsigned int now_timer;
            while(digitalRead(_irq)==1)
            {
                 now_timer=millis();
                 if((now_timer-star_timer)>=iic_timeout)
                 {
                     _flag=EER_TIMEOUT;   //超時檢測
                     return _flag;
                 }
             }
             iic_dev->readBytes(keepbuff, keeplen,1);                   //讀取CMD
             if(T_header!=0x22)
             {
             if((BMZ00050_keep_cmdpacket[0]!=(T_header+1))||(BMZ00050_keep_cmdpacket[1]!=(T_cmd+1)))
             {
                  _flag=EER_INVALID_FRAME;     //錯誤幀檢測
                  return _flag;
             }
             }
        }
////uart模式、透传模式
   else if((spi_dev == NULL)&&(iic_dev == NULL))
    {
        unsigned char Uselessvalue;
        while(Serial.available()!=0)
        {
           Uselessvalue=Serial.read();
        }
        
        Serial.write(cmdbuff, cmdlen);                 //發送命令
        unsigned int star_timer=millis();
        unsigned int now_timer;
        while(Serial.available()<2)
        {
            now_timer=millis();
            if((now_timer-star_timer)>=uart_timeout)
            {
                _flag=EER_TIMEOUT;   //超時檢測
                return _flag;
            }
        }
        Serial.readBytes(keepbuff,keeplen);                   //讀取CMD
        if(T_header!=0x22)
        {
        if((BMZ00050_keep_cmdpacket[0]!=(T_header+1))||(BMZ00050_keep_cmdpacket[1]!=(T_cmd+1)))
        {
             _flag=EER_INVALID_FRAME;     //錯誤幀檢測
             return _flag;
        }
        }
    }

    }
}

 /*************************************************
Description:        发送命令并等待指定的时间段以等待确认ACK
Input:              @param  *cmd    要發送的命令存儲的數組
                    @param  cmdlen  要發送的長度
                    @param  timeout 等待时间
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::sendCommandCheckAck(uint8_t *cmdbuff, uint8_t cmdlen, unsigned int timeout)
{
    spi_timeout = timeout;
    iic_timeout = timeout;
    uart_timeout = timeout;
    sendCommand(cmdbuff,cmdlen,BMZ00050_keep_cmdpacket,250);
    spi_timeout = SPI_TIMEOUT;
    iic_timeout = IIC_TIMEOUT;
    uart_timeout = UART_TIMEOUT;
    return _flag;
}

 /*************************************************
Description:        用於讀取 BMZ00050 NFC 模塊固件版本號
Input:              void
Output:             
Return:             有錯誤時返回int16_t _flag，無錯誤時返回int16_t savever
Others:             
*************************************************/
int8_t BMZ00050::getFWVer(uint16_t &savever)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t FWVer_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x00,0xff-0xd4-0x00+1,0x00};
        sendCommand(FWVer_RR, 9, BMZ00050_keep_cmdpacket, 11);
        unsigned int response = (BMZ00050_keep_cmdpacket[7]<<8)+BMZ00050_keep_cmdpacket[8];
        savever=response;
    }
    else            //透传模式
    {
        uint8_t FWVer_TR[]={0x20,0x00};
        sendCommand(FWVer_TR, 2, BMZ00050_keep_cmdpacket, 5);
        unsigned int response = (BMZ00050_keep_cmdpacket[3]<<8)+BMZ00050_keep_cmdpacket[4];
        savever=response;
    }
       return _flag;
}

 /*************************************************
Description:        用於讀取 BMZ00050 NFC 模塊產品號
Input:              void
Output:             
Return:             有錯誤時返回int16_t _flag，無錯誤時返回int16_t savepid
Others:             
*************************************************/
int8_t BMZ00050::getPID(uint16_t &savepid)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t PID_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x02,0xff-0xd4-0x02+1,0x00};
        sendCommand(PID_RR, 9, BMZ00050_keep_cmdpacket, 11);
        unsigned int response = (BMZ00050_keep_cmdpacket[7]<<8)+BMZ00050_keep_cmdpacket[8];
        savepid=response;
    }
    else            //透传模式
    {
        uint8_t PID_TR[]={0x20,0x02};
        sendCommand(PID_TR, 2, BMZ00050_keep_cmdpacket, 5);
        unsigned int response = (BMZ00050_keep_cmdpacket[3]<<8)+BMZ00050_keep_cmdpacket[4];
        savepid=response;
    }
       return _flag;
}

 /*************************************************
Description:        用於讀取 BMZ00050 NFC 模塊製造商 ID
Input:              void
Output:             
Return:             有錯誤時返回int16_t _flag，無錯誤時返回int16_t savevid
Others:             
*************************************************/
int8_t BMZ00050::getVID(uint16_t &savevid)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t VID_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x04,0xff-0xd4-0x04+1,0x00};
        sendCommand(VID_RR, 9, BMZ00050_keep_cmdpacket, 11);
        unsigned int response = (BMZ00050_keep_cmdpacket[7]<<8)+BMZ00050_keep_cmdpacket[8];
        savevid=response;
    }
    else            //透传模式
    {
        uint8_t VID_TR[]={0x20,0x04};
        sendCommand(VID_TR, 2, BMZ00050_keep_cmdpacket, 5);
        unsigned int response = (BMZ00050_keep_cmdpacket[3]<<8)+BMZ00050_keep_cmdpacket[4];
        savevid=response;
    }
       return _flag;
}

 /*************************************************
Description:        用於讀取產品的資訊，包括產品生產時間、流水號等
Input:              @param  buff[ ]  buff[ ]為存儲儲存的位置，在buff[0-8]。
Output:             buff[0-8]存儲產品的資訊
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::getSN (uint8_t *buff)
{
    uint8_t i;
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t SN_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x06,0xff-0xd4-0x06+1,0x00};
        sendCommand(SN_RR, 9, BMZ00050_keep_cmdpacket, 15);
        for(i=0;i<6;i++)
        {
            buff[i] = BMZ00050_keep_cmdpacket[7+i];
        }
    }
    else            //透传模式
    {
        uint8_t SN_TR[]={0x20,0x06};
        sendCommand(SN_TR, 2, BMZ00050_keep_cmdpacket, 9);
        for(i=0;i<6;i++)
        {
            buff[i] = BMZ00050_keep_cmdpacket[3+i];
        }
    }
    return _flag;
}

 /*************************************************
Description:        用於獲取 BMZ00050 NFC 模塊支援的協定標準
Input:              @param  buff[ ]  buff[ ]為協定標準儲存的位置，在buff[0-8]。
Output:             buff[0-8]存儲協定標準
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::getNFCProtocol(uint8_t *buff)
{
    uint8_t i;
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t ISO14443A_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x08,0xff-0xd4-0x08+1,0x00};
        sendCommand(ISO14443A_RR, 9, BMZ00050_keep_cmdpacket, 18);
        for(i=0;i<9;i++)
        {
            buff[i] = BMZ00050_keep_cmdpacket[7+i];
        }
    }
    else            //透传模式
    {
        uint8_t ISO14443A_TR[]={0x20,0x08};
        sendCommand(ISO14443A_TR, 2, BMZ00050_keep_cmdpacket, 12);
        for(i=0;i<9;i++)
        {
            buff[i] = BMZ00050_keep_cmdpacket[3+i];
        }
    }
    return _flag;
}

 /*************************************************
Description:        用於獲取 BMZ00050 模塊狀態寄存器，查詢 BMZ00050 的工作狀態
Input:              void
Output:             
Return:             有錯誤時返回int8_t _flag，無錯誤時返回int8_t savestatus
Others:             
*************************************************/
int8_t BMZ00050::getStatusRegister(uint8_t &savestatus)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t Status_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x0a,0xff-0xd4-0x0a+1,0x00};
        sendCommand(Status_RR, 9, BMZ00050_keep_cmdpacket, 10);
        uint8_t response = BMZ00050_keep_cmdpacket[7];
        savestatus=response;
    }
    else            //透传模式
    {
        uint8_t Status_TR[]={0x20,0x0a};
        sendCommand(Status_TR, 2, BMZ00050_keep_cmdpacket, 4);
        uint8_t response = BMZ00050_keep_cmdpacket[3];
        savestatus=response;
    }
       return _flag;
}


 /*************************************************
Description:        用於配置 BMZ00050 NFC 模塊低電壓檢測使能/除能，以及低電壓檢測門限值
Input:              @param   lvden   lvden為:
                              ENABLE，低電壓檢測使能
                              DISABLE，低電壓檢測除能

                    @param   lvdvolage   lvdvolage為：
                              LVD_1V8，選擇LVD電壓為1.8V
                              LVD_2V，選擇LVD電壓為2.0V
                              LVD_2V4，選擇LVD電壓為2.4V
                              LVD_2V7，選擇LVD電壓為2.7V
                              LVD_3V，選擇LVD電壓為3.0V
                              LVD_3V3，選擇LVD電壓為3.3V
                              LVD_3V6，選擇LVD電壓為3.6V
                              LVD_4V，選擇LVD電壓為4.0V
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::setLVD (uint8_t lvden, uint8_t lvdvolage )
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t DCS = 0xff-0xd4-0x0c-lvdvolage+0x01;
        uint8_t LVD_RR[]={0x00,0x00,0xff,0x03,0xff-0x03+1,0xd4,0x0c,lvdvolage,DCS,0x00};
        sendCommand(LVD_RR, 10, BMZ00050_keep_cmdpacket, 9);
    }
    else            //透传模式
    {
        uint8_t LVD_TR[]={0x25,0x0c,0x01,lvdvolage};
        sendCommand(LVD_TR, 4, BMZ00050_keep_cmdpacket, 2);
    }
    return _flag;
}

 /*************************************************
Description:        用於查詢 BMZ00050 NFC 模塊低電壓檢測使能/除能，以及低電壓檢測門限值
Input:              void
Output:             
Return:             有錯誤時返回int8_t _flag，無錯誤時返回int8_t savelvdr
Others:             
*************************************************/
int8_t BMZ00050::getLVD(uint8_t &savelvd)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t DCS = 0xff-0xd4-(0x0e) + 1;
        uint8_t LVD_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x0e,DCS,0x00};
        sendCommand(LVD_RR, 9, BMZ00050_keep_cmdpacket, 10);
        uint8_t response = BMZ00050_keep_cmdpacket[7];
        savelvd=response;
    }
    else            //透传模式
    {
        uint8_t LVD_TR[]={0x20,0x0e};
        sendCommand(LVD_TR, 2, BMZ00050_keep_cmdpacket, 4);
        uint8_t response = BMZ00050_keep_cmdpacket[3];
        savelvd=response;
    }
       return _flag;
}

 /*************************************************
Description:        用於配置 BMZ00050 NFC 模塊的 UART 通信介面的串行傳輸速率
Input:              @param  baudrate：
                       BAUD_1200，設置串行傳輸速率為1200
                       BAUD _2400，設置串行傳輸速率為2400
                       BAUD _4800，設置串行傳輸速率為4800
                       BAUD _9600，設置串行傳輸速率為9600
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::setBaudRate (uint8_t baudrate)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t DCS = 0xff-0xd4-0x10-baudrate+1;
        uint8_t LVD_RR[]={0x00,0x00,0xff,0x03,0xff-0x03+1,0xd4,0x10,baudrate,DCS,0x00};
        sendCommand(LVD_RR, 10, BMZ00050_keep_cmdpacket, 9);
    }
    else            //透传模式
    {
        uint8_t LVD_TR[]={0x25,0x10,0x01,baudrate};
        sendCommand(LVD_TR, 4, BMZ00050_keep_cmdpacket, 2);
    }
    if(baudrate==0x00)
    {
       Serial.begin(1200);
       _baudflag = 8;
    }
    else if(baudrate==0x01)
    {
       Serial.begin(2400);
       _baudflag = 4;
    }
    else if(baudrate==0x02)
    {
      Serial.begin(4800);
      _baudflag = 2;
    }
    else if(baudrate==0x03)
    {
      Serial.begin(9600);
      _baudflag = 1;
    }
    return _flag;
}

 /*************************************************
Description:        用於查詢 BMZ00050 NFC 模塊的 UART 通信介面的串行傳輸速率
Input:              void
Output:             
Return:             有錯誤時返回int8_t _flag，無錯誤時返回int8_t savebaudrate
Others:             
*************************************************/
int8_t BMZ00050::getBaudRate(uint8_t &savebaud)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t Baud_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x12,0xff-0xd4-0x12+1,0x00};
        sendCommand(Baud_RR, 9, BMZ00050_keep_cmdpacket, 10);
        uint8_t response = BMZ00050_keep_cmdpacket[7];
        savebaud=response;
    }
    else            //透传模式
    {
        uint8_t Baud_TR[]={0x20,0x12};
        sendCommand(Baud_TR, 2, BMZ00050_keep_cmdpacket, 4);
        uint8_t response = BMZ00050_keep_cmdpacket[3];
        savebaud=response;
    }
       return _flag;
}

 /*************************************************
Description:        用於配置 BMZ00050 模塊的 INT 線的觸發狀態
Input:              @param  irqactivemode為：
                        INT_HIGH，設置INT 線初始狀態為 High
                        INT_LOW，設置INT 線初始狀態為 Low 
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::setIRQactiveMode(uint8_t irqactivemode )
{
    if(_nfcmode==1)  //寄存器模式
    {   
        uint8_t DCS = 0xff-0xd4-0x14-irqactivemode + 1;
        
        uint8_t INTR_RR[]={0x00,0x00,0xff,0x03,0xff-0x03+1,0xd4,0x14,irqactivemode,DCS,0x00};
        sendCommand(INTR_RR, 10, BMZ00050_keep_cmdpacket, 9);
    }
    else            //透传模式
    {
        uint8_t INTR_TR[]={0x25,0x14,0x01,irqactivemode};
        sendCommand(INTR_TR, 4, BMZ00050_keep_cmdpacket, 2);
    }
    return _flag;
}

 /*************************************************
Description:        用於重定 BMZ00050 NFC 模塊。將模塊參數恢復為出廠狀態，包括模塊工作模式、INT 線狀態、NFC 存儲區 Page0~Page3
Input:              void
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::resetModule (void )
{
    if(_nfcmode==1)  //寄存器模式
    {   
        uint8_t AA = 0xaa;
        uint8_t DCS = 0xff-0xd4-0x16-AA+1;
        uint8_t INTR_RR[]={0x00,0x00,0xff,0x03,0xff-0x03+1,0xd4,0x16,0xaa,DCS,0x00};
        sendCommand(INTR_RR, 10, BMZ00050_keep_cmdpacket, 9);
    }
    else            //透传模式
    {
        uint8_t INTR_TR[]={0x25,0x16,0x01,0xaa};
        sendCommand(INTR_TR, 4, BMZ00050_keep_cmdpacket, 2);
    }
    return _flag;
}

 /*************************************************
Description:        用於設置BMZ00050 NFC 模塊的休眠模式
Input:              @param  sleepmode  sleepmode e為:
                                     NORMAL_SLEEP，普通休眠模式
                                     DEEP_SLEEP，   深度休眠模式
                                     NO_SLEEP，     不休眠

                    @param  wdttime    wdttime為：
                                     WDT_8ms,    WDT溢出週期為8ms
                                     WDT _32ms,   WDT溢出週期為32ms
                                     WDT _128ms,  WDT溢出週期為128ms 
                                     WDT _512ms,  WDT溢出週期為512ms
                                     WDT _1024ms, WDT溢出週期為1024ms
                                     WDT _2048ms，WDT溢出週期為2048ms
                                     WDT _4096ms，WDT溢出週期為4096ms
                                     WDT _8192ms，WDT溢出週期為8192ms
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::setOperationMode(uint8_t sleepmode, uint8_t wdttime )
{
    uint8_t HM=0x00;
    HM=sleepmode|wdttime;
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t DCS = 0xff-0xd4-0x18-HM+1;
        uint8_t HaltMode_RR[]={0x00,0x00,0xff,0x03,0xff-0x03+1,0xd4,0x18,HM,DCS,0x00};
        sendCommand(HaltMode_RR, 10, BMZ00050_keep_cmdpacket, 9);
    }
    else            //透传模式
    {
        uint8_t HaltMode_TR[]={0x25,0x18,0x01,HM};
        sendCommand(HaltMode_TR, 4, BMZ00050_keep_cmdpacket, 2);
    }
    return _flag;
}

 /*************************************************
Description:        用於查詢 BMZ00050 NFC 模塊的休眠模式
Input:              void
Output:             
Return:             有錯誤時返回int8_t _flag，無錯誤時返回int8_t savehm
Others:             
*************************************************/
int8_t BMZ00050::getOperationMode(uint8_t &savehm)
{
    if(_nfcmode==1)  //寄存器模式
    {
        uint8_t HaltMode_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x1a,0xff-0xd4-0x1a+1,0x00};
        sendCommand(HaltMode_RR, 9, BMZ00050_keep_cmdpacket, 10);
        uint8_t response = BMZ00050_keep_cmdpacket[7];
        savehm=response;
    }
    else            //透传模式
    {
        uint8_t HaltMode_TR[]={0x20,0x1a};
        sendCommand(HaltMode_TR, 2, BMZ00050_keep_cmdpacket, 4);
        uint8_t response = BMZ00050_keep_cmdpacket[3];
        savehm=response;
    }
       return _flag;
}

 /*************************************************
Description:        用於對 BMZ00050 NFC 模塊的 NFC 記憶體 EEPROM 區寫入4個數據
Input:              @param  pageaddr                         pageaddr為寫入的頁地址，範圍為0x04~0x3F
                    @param  databuff[ ]                      databuff[]為寫入的數據(4bytes)
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::writePage(uint8_t pageaddr,uint8_t *databuff,uint8_t memory)
{
     delayMicroseconds(25);
     writePages(pageaddr,databuff,0x01,memory);
     return _flag;
}

 /*************************************************
Description:        用於對 BMZ00050 NFC 模塊的 NFC 記憶體 EEPROM 區寫入pagelen頁數據
Input:              @param  pageaddr      pageaddr為寫入的頁地址，範圍為0x04~0x3F
                    @param  databuff[ ]   寫的數據存儲在數組databuff中
                    @param  pagelen       寫入的頁數
Output:             
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::writePages(uint8_t pageaddr,uint8_t *databuff, uint8_t pagelen,uint8_t memory)
{
      delayMicroseconds(25);
      if(memory==EEPROM_MEMORY) //寫EEPROM_MEMORY
      {
        if((pageaddr+pagelen)>0x40)
        {
            _flag=EER_INSUFFICIENT_BUFFER;
            return _flag;
        }
        uint8_t i = 0;
        uint8_t data_len=4*pagelen;
        uint8_t LEN = 0x04+data_len;
        uint8_t LCS = 0xff-LEN+1;
        uint8_t TFI = 0xd4;
        uint8_t command = 0x1c;
        uint8_t DCS = 0xff-TFI-command-pageaddr-pagelen+1;
        for(i=0;i<data_len;i++)
        {
           DCS-=databuff[i];
        }
        uint8_t EEPROM_W[250]={0x00,0x00,0xff,LEN,LCS,0xd4,0x1c,pageaddr,pagelen};
        for(i=0;i<data_len;i++)
        {
            EEPROM_W[i+9]=databuff[i];
        }
        EEPROM_W[data_len+9] = DCS;
        EEPROM_W[data_len+9+1] = 0x00;
        sendCommand(EEPROM_W, data_len+9+2, BMZ00050_keep_cmdpacket,7);
    }
    
    else                      //寫SRAM_MEMORY
    {
        if((pageaddr+pagelen)>0x50||pagelen>0x10)
        {
            _flag=EER_INSUFFICIENT_BUFFER;
            return _flag;
        }
        uint8_t i = 0;
        uint8_t data_len=4*pagelen;
        uint8_t LEN = 0x04+data_len;
        uint8_t LCS = 0xff-LEN+1;
        uint8_t TFI = 0xd4;
        uint8_t command = 0x20;
        uint8_t DCS = 0xff-TFI-command-pageaddr-pagelen+1;
        for(i=0;i<data_len;i++)
        {
           DCS-=databuff[i];
        }
        uint8_t SRAM_W[250]={0x00,0x00,0xff,LEN,LCS,0xd4,0x20,pageaddr,pagelen};
        for(i=0;i<data_len;i++)
        {
            SRAM_W[i+9]=databuff[i];
        }
        SRAM_W[data_len+9] = DCS;
        SRAM_W[data_len+9+1] = 0x00;
        sendCommand(SRAM_W, data_len+9+2, BMZ00050_keep_cmdpacket, 7);
    }

    return _flag;
}

 /*************************************************
Description:        用於對 BMZ00050 NFC 模塊的 NFC 記憶體 EEPROM 區讀取pagelen頁資料
Input:              @param  pageaddr     pageaddr為讀取的頁地址，範圍為0x04~0x3F
                    @param  databuff[ ]  讀取的數據存儲在數組databuff[ ]
                    @param  讀取的頁數     讀取的頁數
Output:             databuff[ ]存儲讀的數據
Return:             int8_t _flag
Others:             
*************************************************/
int8_t BMZ00050::readPages(uint8_t pageaddr,uint8_t *databuff,uint8_t pagelen,uint8_t memory)
{
    delayMicroseconds(25);
    if(memory==EEPROM_MEMORY)  //讀EEPROM_MEMORY
    {
        uint8_t i = 0;
        if((pageaddr+pagelen)>0x40)
        {
            _flag=EER_INSUFFICIENT_BUFFER;
            return _flag;
        }
        uint8_t data_len=4*pagelen;
        uint8_t DCS = 0xff-0xd4-(0x1e) - pageaddr-pagelen+1;
        uint8_t EEPROM_R[250]={0x00,0x00,0xff,0x04,0xff-0x04+1,0xd4,0x1e,pageaddr,pagelen,DCS,0x00};
        sendCommand(EEPROM_R, 11, BMZ00050_keep_cmdpacket, data_len+9);
        for(i=0;i<data_len;i++)
        {
            databuff[i] = BMZ00050_keep_cmdpacket[i+9];
        }
    }
    else if(memory==SRAM_MEMORY)                        //讀SRAM_MEMORY
    {
        uint8_t i = 0;
       if((pageaddr+pagelen)>0x50)
        {
            _flag=EER_INSUFFICIENT_BUFFER;
            return _flag;
        }
        uint8_t data_len=4*pagelen;
        uint8_t LEN = 0x04;
        uint8_t LCS = 0xff-LEN+1;
        uint8_t DCS = 0xff-0xd4-(0x22)-pageaddr-pagelen+1;
        uint8_t SRAM_R[250]={0x00,0x00,0xff,LEN,LCS,0xd4,0x22,pageaddr,pagelen,DCS,0x00};
        sendCommand(SRAM_R, 11, BMZ00050_keep_cmdpacket, data_len+9);
        for(i=0;i<data_len;i++)
        {
            databuff[i] = BMZ00050_keep_cmdpacket[i+9];
        }
    }
    return _flag;
}

 /*************************************************
Description:        用於對 BMZ00050 NFC 模塊讀取外部 NFC 設備最後寫 NFC 存儲器的頁位址
Input:              
Output:             
Return:             有錯誤時返回int8_t _flag，無錯誤時返回int8_t savelastpageaddr
Others:             
*************************************************/
int8_t BMZ00050::readNFCWRA(uint8_t &savelastpageaddr)
{
        uint8_t LVD_RR[]={0x00,0x00,0xff,0x02,0xff-0x02+1,0xd4,0x24,0xff-0xd4-0x24+1,0x00};
        sendCommand(LVD_RR, 9, BMZ00050_keep_cmdpacket, 10);
        uint8_t response = BMZ00050_keep_cmdpacket[7];
        savelastpageaddr=response;
           return _flag;
}

 /*************************************************
Description:        用於對 BMZ00050 NFC 模塊的 NFC 記憶體 SRAM 區寫入數據
Input:              @param  datalen       datalen為想寫入的數據個數，範圍為0x00-0x3c
                    @param  databuff[ ]   databuff[ ]為寫入的數據
Output:             
Return:             void
Others:             
*************************************************/
void BMZ00050::writeDataPacket(uint8_t *databuff,uint8_t datalen)
{
        if(datalen>0x3c)
        {
            _flag=EER_INSUFFICIENT_BUFFER;
        }
        uint8_t i = 0;
        uint8_t Packet_TW[250]={0x22,datalen};
        for(int i=0;i<datalen;i++)
        {
           Packet_TW[i+2]=databuff[i];
        }
        sendCommand(Packet_TW, datalen+2, BMZ00050_keep_cmdpacket, 1);
}

 /*************************************************
Description:        用於讀取 BMZ00050 NFC 模塊的 NFC 記憶體 SRAM 區數據
Input:              @param  databuff[0] 為讀取的數據個數，databuff[1-n ] 為存儲讀取的數據
                    
Output:             
Return:             return 1表示有外界NFC寫入，否則return 0
Others:             
*************************************************/
int8_t BMZ00050::readDataPacket(uint8_t *databuff)
{
     int8_t readdata_header=0;
     int8_t readdata_length=0;
     if(spi_dev != NULL)
     {
        if(digitalRead(_irq) == 0)  
        { 
            digitalWrite(_ss, LOW);    
            spi_dev->transfer(0x40+0x3c+0x02); 
          
            delayMicroseconds(20); 
            readdata_header = spi_dev->transfer(0xff);  //header
            if(readdata_header!=0x22)
            {
                return 0;
            }
            delayMicroseconds(20); 
            readdata_length = spi_dev->transfer(0xff);  //length
            databuff[0]=readdata_length;
            for (uint8_t i = 0; i <readdata_length; i++)
            {   
              delayMicroseconds(20);  
              databuff[i+1] = spi_dev->transfer(0xff);
            }   
         return 1;         
         } 
         else 
             return 0;

      }
     else if(iic_dev != NULL)
     {
          if(digitalRead(_irq) == 0)  
         {   
            iic_dev->requestFrom(0x28,0x3c+2,1); 
            
                readdata_header = iic_dev->read();  //header
                if(readdata_header!=0x22)
                {
                   return 0;
                }
                
                readdata_length = iic_dev->read();  //length
                databuff[0]=readdata_length;
                for (uint8_t i = 0; i <readdata_length; i++)
                {
                    databuff[i+1] = iic_dev->read();      
                }         
             
          return 1;   
          }
          else
                 return 0;
     }
     else if((spi_dev == NULL)&&(iic_dev == NULL))
     {
         uint8_t len = Serial.available();
         if(len!=0)
         {
            if(_headerflag == 0)
            {
               if(len>=2)
               {
                  readdata_header = Serial.read();       //讀取一次數據
                  if(readdata_header == 0x22)
                  {
                     readdata_length=Serial.read();      //讀第二個數
                     databuff[0] = readdata_length;
                     _headerflag = 2;
                  }
                  else
                  {
                     while(Serial.available()!=0)  //清空緩存區
                     {
                        Serial.read();
                     }
                     return 0;     
                  }
               }
               else
               {
                  _latertime = millis();
                  if((_latertime-_startime)>(_baudflag*2))                 //超時判定每個字節時間間隔<_baudflag*2ms
                  {
                     while(Serial.available()!=0)   //清空緩存區
                     {
                        Serial.read();
                     }
                     return 0;
                  }
               }
            }
            if(_headerflag == 2)
            {
               if(len>=databuff[0])  //等待接收readdata_length字節數據
               {
                  for(uint8_t i=0;i<databuff[0];i++)
                  {
                     databuff[i+1] = Serial.read();
                  }
                  while(Serial.available()!=0)
                  {
                     Serial.read();
                  }
                  _headerflag = 0;  //重新
                  return 1;
               }
               else
               {
                  _latertime = millis();
                  if(_latertime-_startime>(_baudflag*2*databuff[0]))  //超時判定完整數據包 間隔<_baudflag*2*databuff[0],ms
                  {
                     while(Serial.available()!=0)   //清空緩存區
                     {
                        Serial.read();
                     }
                     return 0;
                  }
               }
            }
         }
         else
         {
            _startime = millis();  //記錄第一筆數的時間
            return 0;
         }
     }
}

 /*************************************************
Description:        以普通字符打印十六进制值打印格式的字符為00
                                                    00
                                                    00
                                                    00
                                                      ......
Input:              @param  *data    要打印的數據存儲數組
                    @param  numBytes 打印的個數
Output:             
Return:             void
Others:             
*************************************************/
void BMZ00050::PrintHex(uint8_t *data, uint8_t num_first, uint8_t num_last)
{
    uint8_t i = 0;
    for(i=(num_first-1);i<num_last;i++)
    {
        Serial.println(data[i],HEX);
    }
    Serial.println(' ');
}

 /*************************************************
Description:        以普通字符打印十六进制值。打印格式的字符為00 00 00 00 00 00 ......
Input:              @param  *data    要打印的數據存儲數組
                    @param  numBytes 打印的個數
Output:             
Return:             void
Others:             
*************************************************/
void BMZ00050::PrintHexChar(uint8_t *data, uint8_t num_first, uint8_t num_last)
{
    uint8_t i = 0;
    for(i=(num_first-1);i<num_last;i++)
    {
        Serial.print(data[i],HEX);
        Serial.print(' ');
    }
    Serial.println(' ');
}
