1. 程式人生 > >20141227 【 RFID 2.4GHz 讀寫器及標籤程式碼 】

20141227 【 RFID 2.4GHz 讀寫器及標籤程式碼 】

結構:

AppDemo /* 讀寫器及標籤應用功能實現 */

    RFID_2.4GHz_Reader_Demo.c // RFID2.4G讀寫器應用程式

    RFID_2.4GHz_Tag_Demo.c // RFID2.4G標籤應用程式

READER /* 讀寫器及標籤硬體驅動 */

    hal_2.4GHz_Reader.c // RFID2.4G讀寫器硬體層驅動

    hal_2.4GHz_Tag.c // RFID2.4G標籤硬體層驅動

SYSCLK /* 系統時鐘 */

    SYSCLK.c // MCU時鐘選擇

UART0 /* 串列埠通訊UART0驅動 */

    UART0.c // CC2530

UART0驅動

/*******************************************************************************
 * 檔名稱:RFID_2.4GHz_Reader_Demo.c
 * 功    能:RFID基礎實驗工程 --- 2.4GHz RFID 讀卡器演示
 *           將接收到的Tag資訊通過CC2530的UART0輸出,波特率為115200
 * 作    者:
 * 公    司:
 ******************************************************************************/

#if !defined ( TAG_FLAG )
/* 包含標頭檔案 */
/*************************************************************/
#include "hal_2.4GHz_Reader.h"  // RFID-2.4GHz-Reader硬體抽象層標頭檔案
#include "UART0.h"              // CC2530的UART0驅動的標頭檔案
#include "SYSCLK.h"             // CC2530的時鐘選擇標頭檔案
#include "stdlib.h"             // C語言標準庫檔案
#include "stdio.h"              // C語言標準輸入/輸出庫檔案
/*************************************************************/


/* RFID Reader的資料管道0接收地址為"READR" */
/*************************************************************/
unsigned char RFID_READER_ADDR_P0[] = {'R', 'D', 'A', 'E', 'R'};
/*************************************************************/


/* XXTEA加密塊數量 */
/*************************************************************/
#define TEA_ENCRYPTION_BLOCK_COUNT 4
/*************************************************************/


/* XXTEA金鑰 */
/*************************************************************/
const long XXTEA_KEY[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
/*************************************************************/


/* XXTEA演算法相關變數和巨集定義 */
/*************************************************************/
unsigned long z, y, sum, tmp, mx;
unsigned char e;
#define TEA_ROUNDS_COUNT (6+52/4)
#define MX ((((z>>5)^(y<<2))+((y>>3)^(z<<4)))^((sum^y)+(XXTEA_KEY[(p&3)^e]^z)))
#define DELTA 0x9E3779B9
/*************************************************************/


/* 資料包結構體型別 */
/*************************************************************/
typedef struct
{
  unsigned char len;        // 資料包的長度欄位(單位:位元組)
  unsigned char protocol;   // 資料包的協議型別欄位
  unsigned char flags;      // 資料包的標誌欄位(按下Tag上的按鍵,flag為0x02;否則為0x00)
  unsigned char txpower;    // 資料包的傳送功率欄位
  unsigned long seq;        // 資料包的序號欄位
  unsigned long oid;        // 資料包的物件識別符號欄位
  unsigned short reserved;  // 資料包的保留欄位
  unsigned short crc;       // 資料包的CRC欄位
}PKT;
/*************************************************************/


/* 加密資料包結構體型別 */
/*************************************************************/
typedef union
{
  PKT pkt;
  unsigned long dataUL[TEA_ENCRYPTION_BLOCK_COUNT];
  unsigned char dataB[TEA_ENCRYPTION_BLOCK_COUNT * sizeof (unsigned long)];
}ENCRYPTED_PKT;
/*************************************************************/


/* 用於Tag的加密資料包結構體變數 */
/*************************************************************/
static ENCRYPTED_PKT g_Tag;
/*************************************************************/


/* "打亂"功能巨集 — SHUFFLE */
/*************************************************************/
#define SHUFFLE(a,b) 	tmp = g_Tag.dataB[a];\
			g_Tag.dataB[a] = g_Tag.dataB[b];\
			g_Tag.dataB[b] = tmp;
/*************************************************************/


/*********************************************************************
 * 函式名稱:htonl
 * 功    能:將主機位元組順序表達的32位無符號長整形數轉換成網路位元組順序
 *           表達的32位無符號長整形數
 * 入口引數:hostlong  主機位元組順序表達的32位無符號長整形數
 * 出口引數:無
 * 返 回 值:網路位元組順序表達的32位無符號長整形數
 ********************************************************************/
static unsigned long htonl (unsigned long hostlong)
{
  unsigned long res;

  ((unsigned char *) &res)[0] = ((unsigned char *) &hostlong)[3];
  ((unsigned char *) &res)[1] = ((unsigned char *) &hostlong)[2];
  ((unsigned char *) &res)[2] = ((unsigned char *) &hostlong)[1];
  ((unsigned char *) &res)[3] = ((unsigned char *) &hostlong)[0];

  return res;
}


/*********************************************************************
 * 函式名稱:htons
 * 功    能:將主機位元組順序表達的16位無符號短整形數轉換成網路位元組順序
 *           表達的16位無符號短整形數
 * 入口引數:hostlong  主機位元組順序表達的16位無符號短整形數
 * 出口引數:無
 * 返 回 值:網路位元組順序表達的16位無符號短整形數
 ********************************************************************/
static unsigned short htons (unsigned short hostshort)
{
  unsigned short res;

  ((unsigned char *) &res)[0] = ((unsigned char *) &hostshort)[1];
  ((unsigned char *) &res)[1] = ((unsigned char *) &hostshort)[0];

  return res;
}


/*********************************************************************
 * 函式名稱:Shuffle_TX_ByteOrder
 * 功    能:"打亂"待發送資料的位元組順序
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
static void Shuffle_TX_ByteOrder (void)
{
  unsigned char tmp;

  SHUFFLE (0 + 0, 3 + 0);
  SHUFFLE (1 + 0, 2 + 0);
  SHUFFLE (0 + 4, 3 + 4);
  SHUFFLE (1 + 4, 2 + 4);
  SHUFFLE (0 + 8, 3 + 8);
  SHUFFLE (1 + 8, 2 + 8);
  SHUFFLE (0 + 12, 3 + 12);
  SHUFFLE (1 + 12, 2 + 12);
}


/*********************************************************************
 * 函式名稱:CRC16
 * 功    能:CRC16計算
 * 入口引數:buffer  指向儲存待進行CRC16計算的資料的緩衝區的指標
 *           size    待進行CRC16計算的資料的長度    
 * 出口引數:無
 * 返 回 值:CRC16計算結果
 * 注    意:CC2530自身帶有CRC計算功能,但為了提高程式碼的可移植性,我們
 *           不使用CC2530自身帶有的CRC計算功能,而使用該函式。
 ********************************************************************/
static unsigned short CRC16 (const unsigned char *buffer, unsigned char size)
{
  unsigned short crc = 0xFFFF;
  
  if(buffer)
  {
    while(size--)
    {
      crc = (crc >> 8) | (crc << 8);
      crc ^= *buffer++;
      crc ^= ((unsigned char) crc) >> 4;
      crc ^= crc << 12;
      crc ^= (crc & 0xFF) << 5;
    }
  }
  
  return crc;
}

/*********************************************************************
 * 函式名稱:MX_Update
 * 功    能:XXTEA演算法的MX更新
 * 入口引數:p
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
static void MX_Update (unsigned char p)
{
  mx = MX;
}


/*********************************************************************
 * 函式名稱:MX_Decode
 * 功    能:XXTEA演算法的MX解碼
 * 入口引數:p
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
static void MX_Decode (unsigned char p)
{
  MX_Update (p);
  y = tmp - mx;
}


/*********************************************************************
 * 函式名稱:MX_Decode
 * 功    能:XXTEA解碼
 * 入口引數:p
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void XXTEA_Decode (void)
{
  y = g_Tag.dataUL[0];
  sum = DELTA * TEA_ROUNDS_COUNT;

  while (sum != 0)
    {
      e = sum >> 2 & 3;

      z = g_Tag.dataUL[2];
      tmp = g_Tag.dataUL[3];
      MX_Decode (3);
      g_Tag.dataUL[3] = y;

      z = g_Tag.dataUL[1];
      tmp = g_Tag.dataUL[2];
      MX_Decode (2);
      g_Tag.dataUL[2] = y;

      z = g_Tag.dataUL[0];
      tmp = g_Tag.dataUL[1];
      MX_Decode (1);
      g_Tag.dataUL[1] = y;

      z = g_Tag.dataUL[3];
      tmp = g_Tag.dataUL[0];
      MX_Decode (0);
      g_Tag.dataUL[0] = y;

      sum -= DELTA;
    }
}

void changeToAscii (unsigned char *pUString, unsigned char teData)
{
  unsigned char temp8i;
  
  temp8i = teData >> 4;
  if ( temp8i < 0x0a)
    *pUString = temp8i + 0x30;
  else
    *pUString = temp8i + 0x37;
  
  pUString++;
  temp8i = teData & 0x0f;
  if ( temp8i < 0x0a)
    *pUString = temp8i + 0x30;
  else
    *pUString = temp8i + 0x37;
}
/*********************************************************************
 * 函式名稱:InitNRF4Reader
 * 功    能:針對RFID Reader功能初始化nRF24L01+
 * 入口引數:無    
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void InitNRF4Reader(void)
{
  hal_nrf_nop();
  
  hal_nrf_write_reg(CONFIG, 0x00);
  
  hal_nrf_write_reg(EN_AA, 0x00);
  
  hal_nrf_write_reg(SETUP_AW, 0x03);
  
  hal_nrf_set_address(HAL_NRF_PIPE0, RFID_READER_ADDR_P0);
  
  hal_nrf_write_reg(EN_RXADDR, 0x01);
  
  hal_nrf_write_reg(RX_PW_P0, 16);  
  
  hal_nrf_write_reg(RF_CH, 81);    
  
  hal_nrf_write_reg(STATUS, 0x70);
  
  hal_nrf_write_reg(CONFIG, 0x01);
}

/*********************************************************************
 * 函式名稱:calcFCS
 * 功    能:該函式用來驗證GPS資料FCS校驗和。
 * 入口引數:pBuf   指向被校驗的資料
 *           len    資料長度 
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
unsigned char calcFCS(unsigned char *pBuf, unsigned char len)
{
  unsigned char rtrn = 0;

  while (len--)
  {
    rtrn ^= *pBuf++;
  }

  return rtrn;
}

/*********************************************************************
 * 函式名稱:main
 * 功    能:2.4GHz RFID 讀卡器演示
 *           將接收到的Tag資訊通過CC2530的UART0輸出,波特率為115200
 * 入口引數:無    
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
int main(void)
{
  /* 定義相關變數 */
  unsigned char i;
  unsigned short crc;
  unsigned long oid;
  unsigned char uartString[64];
  
  /* 選擇32MHz晶體振盪器作為系統時鐘源(主時鐘源) */
  SystemClockSourceSelect(XOSC_32MHz);  

  /* RFID-2.4GHz-Reader硬體抽象層初始化 */
  hal_2G4Hz_Reader_Init();

  /* UART0初始化 */
  InitUART0();
    
  /* LED1和LED2閃爍指定次數 */
  for(i = 0; i <= 20; i++)
  {
    if(i & 1)
    {
      HAL_2G4Hz_LED1_TURN_ON();
      HAL_2G4Hz_LED2_TURN_ON();
    }
    else
    {
      HAL_2G4Hz_LED1_TURN_OFF();
      HAL_2G4Hz_LED2_TURN_OFF();    
    }
    CC2530SleepTimer_Delay(100);
  }
  
  /* 針對RFID Reader功能初始化nRF24L01+ */
  InitNRF4Reader();

  /* 永久迴圈 */
  while(1)
  {
    hal_nrf_set_power_mode(HAL_NRF_PWR_UP);
    
    CC2530SleepTimer_Delay(RF_POWER_UP_DELAY);    
    
    HAL_2G4Hz_CE = 1;
    
    SetCC2530PowerMode(2);
    
    /* 點亮LED1 */
    HAL_2G4Hz_LED1_TURN_ON();
      
    /* 讀取接收到的資料 */
    for(i = 0; i < 16; i++)
    {
      g_Tag.dataB[i] = Radio_Get_Pload_Byte(i);
    }
    
    /* 解碼接收到的資料 */
    Shuffle_TX_ByteOrder();
    XXTEA_Decode();
    Shuffle_TX_ByteOrder();
    
    /* 校驗接收到的資料 */ 
    crc = CRC16(g_Tag.dataB, sizeof(g_Tag.pkt) - sizeof (g_Tag.pkt.crc));
   
    /*  接收到的g_Tag資料包CRC16校驗錯誤 */
    if(htons(g_Tag.pkt.crc) != crc)
    {
      /* 使用者自行處理 */
    }
    /* 接收到的g_Tag資料包CRC16校驗正確 */
    else
    { /* 點亮LED2 */
      HAL_2G4Hz_LED2_TURN_ON();
      
      /* 從CC2530的UART0輸出接收到來自Tag的資訊 */
      oid = htonl(g_Tag.pkt.oid);
//      sprintf(uartString,"OID:%08lx\nTX power:%d\nButton push:%d\n\n", oid, g_Tag.pkt.txpower, g_Tag.pkt.flags);  
      uartString[0] = 0x5a;
      uartString[1] = 14;
      uartString[2] = 0;//g_Tag.dataB[7];
      uartString[3] = 0x01;
      uartString[4] = 0x0a;
      changeToAscii (&uartString[5], g_Tag.dataB[8]);
      changeToAscii (&uartString[7], g_Tag.dataB[9]);
      changeToAscii (&uartString[9], g_Tag.dataB[10]);
      changeToAscii (&uartString[11], g_Tag.dataB[11]);
      uartString[13] = g_Tag.dataB[2];
      uartString[14] = calcFCS(&uartString[1], 13);
      uartString[15] = 0xa5;
      uartString[16] = 0;
      UART0SendString((unsigned char *)uartString, 16);
    }
    
    /* 設定nrf24L01+的RF為IDLE */
    Radio_Set_Status(RF_IDLE);
  
    /* 熄滅LED1和LED2 */
    HAL_2G4Hz_LED1_TURN_OFF();
    HAL_2G4Hz_LED2_TURN_OFF();     
  }
}
#endif


/*******************************************************************************
 * 檔名稱:RFID_2.4GHz_Tag_Demo.c
 * 功    能:RFID基礎實驗工程 --- 2.4GHz RFID 的Tag
 * 作    者:
 * 公    司:
 ******************************************************************************/

#if defined ( TAG_FLAG )
/* 包含標頭檔案 */
/*************************************************************/
#include "hal_2.4GHz_Tag.h"  // RFID-2.4GHz-Tag硬體抽象層標頭檔案
#include "SYSCLK.h"             // CC2530的時鐘選擇標頭檔案
#include "stdlib.h"             // C語言標準庫檔案
#include "stdio.h"              // C語言標準輸入/輸出庫檔案
/*************************************************************/
unsigned char keyFlag;
unsigned int txNumber;

/* RFID Reader的資料管道0接收地址為"READR" */
/*************************************************************/
unsigned char RFID_READER_ADDR_P0[] = {'R', 'D', 'A', 'E', 'R'};
/*************************************************************/


/* XXTEA加密塊數量 */
/*************************************************************/
#define TEA_ENCRYPTION_BLOCK_COUNT 4
/*************************************************************/
#define DATA_LONG        0x10
#define DATA_PROTOCOL    0x01

/* XXTEA金鑰 */
/*************************************************************/
const long XXTEA_KEY[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
/*************************************************************/


/* XXTEA演算法相關變數和巨集定義 */
/*************************************************************/
unsigned long z, y, sum, tmp, mx;
unsigned char e;
#define TEA_ROUNDS_COUNT (6+52/4)
#define MX ((((z>>5)^(y<<2))+((y>>3)^(z<<4)))^((sum^y)+(XXTEA_KEY[(p&3)^e]^z)))
#define DELTA 0x9E3779B9
/*************************************************************/
#define KEYDELAY 80

/* 資料包結構體型別 */
/*************************************************************/
typedef struct
{
  unsigned char len;        // 資料包的長度欄位(單位:位元組)
  unsigned char protocol;   // 資料包的協議型別欄位
  unsigned char flags;      // 資料包的標誌欄位(按下Tag上的按鍵,flag為0x02;否則為0x00)
  unsigned char txpower;    // 資料包的傳送功率欄位
  unsigned long seq;        // 資料包的序號欄位
  unsigned long oid;        // 資料包的物件識別符號欄位
  unsigned short reserved;  // 資料包的保留欄位
  unsigned short crc;       // 資料包的CRC欄位
}PKT;
/*************************************************************/


/* 加密資料包結構體型別 */
/*************************************************************/
typedef union
{
  PKT pkt;
  unsigned long dataUL[TEA_ENCRYPTION_BLOCK_COUNT];
  unsigned char dataB[TEA_ENCRYPTION_BLOCK_COUNT * sizeof (unsigned long)];
}ENCRYPTED_PKT;
/*************************************************************/


/* 用於Tag的加密資料包結構體變數 */
/*************************************************************/
static ENCRYPTED_PKT g_Tag;
/*************************************************************/


/* "打亂"功能巨集 — SHUFFLE */
/*************************************************************/
#define SHUFFLE(a,b) 	tmp = g_Tag.dataB[a];\
			g_Tag.dataB[a] = g_Tag.dataB[b];\
			g_Tag.dataB[b] = tmp;
/*************************************************************/


/*********************************************************************
 * 函式名稱:Shuffle_TX_ByteOrder
 * 功    能:"打亂"待發送資料的位元組順序
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
static void Shuffle_TX_ByteOrder (void)
{
  unsigned char tmp;

  SHUFFLE (0 + 0, 3 + 0);
  SHUFFLE (1 + 0, 2 + 0);
  SHUFFLE (0 + 4, 3 + 4);
  SHUFFLE (1 + 4, 2 + 4);
  SHUFFLE (0 + 8, 3 + 8);
  SHUFFLE (1 + 8, 2 + 8);
  SHUFFLE (0 + 12, 3 + 12);
  SHUFFLE (1 + 12, 2 + 12);
}


/*********************************************************************
 * 函式名稱:CRC16
 * 功    能:CRC16計算
 * 入口引數:buffer  指向儲存待進行CRC16計算的資料的緩衝區的指標
 *           size    待進行CRC16計算的資料的長度    
 * 出口引數:無
 * 返 回 值:CRC16計算結果
 * 注    意:CC2530自身帶有CRC計算功能,但為了提高程式碼的可移植性,我們
 *           不使用CC2530自身帶有的CRC計算功能,而使用該函式。
 ********************************************************************/
static unsigned short CRC16 (const unsigned char *buffer, unsigned char size)
{
  unsigned short crc = 0xFFFF;
  
  if(buffer)
  {
    while(size--)
    {
      crc = (crc >> 8) | (crc << 8);
      crc ^= *buffer++;
      crc ^= ((unsigned char) crc) >> 4;
      crc ^= crc << 12;
      crc ^= (crc & 0xFF) << 5;
    }
  }
  
  return crc;
}

/*********************************************************************
 * 函式名稱:XXTEA_Encode
 * 功    能:XXTEA編碼
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void XXTEA_Encode (void)
{
  long n = 4;
  long p, q ;
  
  z=g_Tag.dataUL[n-1], y=g_Tag.dataUL[0], sum=0;
  
  q = 6 + 52/n;
  while (q-- > 0)
  {
    sum += DELTA;
    e = (sum >> 2) & 3;
    for (p=0; p<n-1; p++)
    y = g_Tag.dataUL[p+1], z = g_Tag.dataUL[p] += MX;
    y = g_Tag.dataUL[0];
    z = g_Tag.dataUL[n-1] += MX;
  }
}


/*********************************************************************
 * 函式名稱:InitNRF4Reader
 * 功    能:針對RFID Reader功能初始化nRF24L01+
 * 入口引數:無    
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void InitNRF4Reader(void)
{
  hal_nrf_nop();
  hal_nrf_write_reg(CONFIG, 0x20);  //使用與nRF2401/ nRF2402/ nRF24E1/ nRF24E2 相同的CRC 配置 
                                    //設定PRIM_RX 位為0 
  hal_nrf_write_reg(EN_AA, 0x00);
  hal_nrf_write_reg(SETUP_RETR, 0); //設定自動重發計數器為0 禁止自動重發功能
  hal_nrf_write_reg(SETUP_AW, 0x03);//與nRF2401/ nRF2402/ nRF24E1/ nRF24E2 使用相同的地址寬度 

  hal_nrf_set_address(HAL_NRF_PIPE0, RFID_READER_ADDR_P0);
  hal_nrf_set_address(HAL_NRF_TX, RFID_READER_ADDR_P0);
  hal_nrf_write_reg(RF_CH, 81);     //與nRF2401/ nRF2402/ nRF24E1/ nRF24E2 使用相同的頻道
 
  hal_nrf_write_reg(EN_RXADDR, 0x00);
  hal_nrf_set_power_mode(HAL_NRF_PWR_UP);//設定PWR_UP 為高
}

void delay65ms(unsigned int microSecs)
{
  while(microSecs--)
  {
   /*  32 NOPs == 1 usecs */
    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
    asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
    asm("nop"); asm("nop");
  }
}

void keyScan ()
{
  unsigned char keyCount,temp8i;
  
  keyCount = 0;
  temp8i = 0;
  while ( temp8i < KEYDELAY )
  {
    delay65ms(500);
    if ( P2_0 == 1 )
      keyCount++;
    else
      keyCount = 0;
    temp8i++;
  }
  if ( keyCount >= KEYDELAY)
    keyFlag = 0x31;
  else
    keyFlag = 0x30;
}

unsigned char secondAddr[8];

void HalFlashRead()
{
  // Calculate the offset into the containing flash bank as it gets mapped into XDATA.
  unsigned char memctr = MEMCTR;  // Save to restore.
  unsigned char i;

  // Calculate and map the containing flash bank into XDATA.
  MEMCTR = (MEMCTR & 0xF8) | 7;
  
  asm("push DPH");
  asm("push DPL");
  asm("push A");
  asm("push B");
  asm("mov DPH,#0xff");
  asm("mov DPL,#0xe8");
  i = 0;
  while (i < 8)
  {
    asm("movx A,@DPTR");
    asm("mov B,A");
    secondAddr[i] = B;
    asm("inc DPTR");
    i++;
  }
  asm("pop B");
  asm("pop A");
  asm("pop DPL");
  asm("pop DPH");

  MEMCTR = memctr;
}
/*********************************************************************
 * 函式名稱:main
 * 功    能:2.4GHz RFID 讀卡器演示
 *           將接收到的Tag資訊通過CC2530的UART0輸出,波特率為115200
 * 入口引數:無    
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
int main(void)
{
  /* 定義相關變數 */
  unsigned char i;
  unsigned short crc;
  
  /* 選擇32MHz晶體振盪器作為系統時鐘源(主時鐘源) */
  SystemClockSourceSelect(XOSC_32MHz);  

  /* RFID-2.4GHz-Reader硬體抽象層初始化 */
  hal_2G4Hz_Tag_Init();
  
  /* 使能P2.0為通用I/O,且為輸入 */
  P2SEL = P2SEL & 0xfe;
  P2DIR = P2DIR & 0xfe;
  /* P2.0為下拉模式 */
  P2INP = P2INP  & 0xfe;
  P2INP = P2INP  | 0x80;

  /* LED1和LED2閃爍指定次數 */
  for(i = 0; i <= 20; i++)
  {
    if(i & 1)
    {
      HAL_2G4Hz_LED1_TURN_ON();
      HAL_2G4Hz_LED2_TURN_ON();
    }
    else
    {
      HAL_2G4Hz_LED1_TURN_OFF();
      HAL_2G4Hz_LED2_TURN_OFF();    
    }
    CC2530SleepTimer_Delay(100);
  }
  
  /* 針對RFID Tag功能初始化nRF24L01+ */
  InitNRF4Reader();
  
  do
  {
    HalFlashRead ();
    delay65ms(60000);
    P1_1 = !P1_1;
  }while ( (secondAddr[0] == 0xff) && (secondAddr[1] == 0xff) && (secondAddr[2] == 0xff) && (secondAddr[3] == 0xff) );
  P1_1 = 0;

  /* 永久迴圈 */
  while(1)
  {
    g_Tag.dataB[0] = DATA_LONG;
    g_Tag.dataB[1] = DATA_PROTOCOL;
    g_Tag.dataB[4] = 0x00;
    g_Tag.dataB[5] = 0x3a;
    g_Tag.dataB[8] = secondAddr[3];//0x08;
    g_Tag.dataB[9] = secondAddr[2];//0x86;
    g_Tag.dataB[10] = secondAddr[1];//0x00;
    g_Tag.dataB[11] = secondAddr[0];//0x4d;
    g_Tag.dataB[12] = 0x0;
    g_Tag.dataB[13] = 0x0;
    
    /* 點亮LED1 */
    HAL_2G4Hz_LED1_TURN_ON();

    g_Tag.dataB[2] = keyFlag;
    
    g_Tag.dataB[3] = hal_nrf_get_output_power ();
    g_Tag.dataB[3]++;
    if ( g_Tag.dataB[3] >= 0x04 )
    {
      g_Tag.dataB[3] = 0;
      txNumber++;
    }
    hal_nrf_set_output_power(g_Tag.dataB[3]);
    
    g_Tag.dataB[6] = (char)(txNumber >> 8);
    g_Tag.dataB[7] = (char)txNumber;
    
    crc = CRC16(g_Tag.dataB, sizeof(g_Tag.pkt) - sizeof (g_Tag.pkt.crc));
    g_Tag.dataB[14] = (char)(crc >> 8);
    g_Tag.dataB[15] = (char)crc;
    
    /* 編碼接收到的資料 */
    Shuffle_TX_ByteOrder();
    XXTEA_Encode();
    Shuffle_TX_ByteOrder();
    
    hal_nrf_write_tx_pload(g_Tag.dataB, DATA_LONG);
    /* RF傳送 */
    HAL_2G4Hz_CE_PULSE();
    
    /* 熄滅LED1和LED2 */
    HAL_2G4Hz_LED1_TURN_OFF();
    HAL_2G4Hz_LED2_TURN_OFF();     
    
    keyScan ();
  }
}
#endif


/*******************************************************************************
 * 檔名稱:hal_2.4GHz_Tag.c
 * 功    能:RFID-2.4GHz-Reader硬體抽象層
 * 作    者:蟲蟲
 * 公    司:
 ******************************************************************************/

#if !defined ( TAG_FLAG )
/* 包含標頭檔案 */
/********************************************************************/
#include "ioCC2530.h"           // CC2530的標頭檔案,包含對CC2530的暫存器、中斷向量等的定義
#include "hal_2.4GHz_Reader.h"  // RFID-2.4GHz-Reader硬體抽象層標頭檔案
/********************************************************************/



/* 
   通過RF傳送的資料載荷。也包含接收資料。 
   使用Radio_Get_Pload_Byte()函式讀取
*/
/********************************************************************/
static unsigned char pload[16];
/********************************************************************/


/* 
   RF的當前狀態 
   使用Radio_Set_Status函式來設定該變數;
   使用Radio_Get_Status函式來讀取該變數。
*/
/********************************************************************/
static radio_status_t status;
/********************************************************************/


/*********************************************************************
 * 函式名稱:SetCC2530SleepTime
 * 功    能:設定CC2530睡眠時間,即設定CC2530的睡眠定時器的比較值。
 * 入口引數:ms  處於功耗模式IDLE、PM0、PM1或PM2的時間。
 * 出口引數:無
 * 返 回 值:無
 * 注    意:使用外部32.768KHz晶體
 ********************************************************************/
static void 
SetCC2530SleepTime(unsigned short ms)
{
  unsigned long sleeptime = 0;
  
  /* 讀取睡眠定時器的當前計數值 */
  sleeptime |= ST0;
  sleeptime |= (unsigned long)ST1 <<  8;
  sleeptime |= (unsigned long)ST2 << 16;
  
  /* 根據指定的睡眠時間計算出應設定的比較值 */
  sleeptime += (ms * (unsigned long)(32768 / 1000));
  
  /* 設定比較值 */
  while((STLOAD & 0x01) == 0);  // 等待允許載入新的比較值
  ST2 = (unsigned char)(sleeptime >> 16);
  ST1 = (unsigned char)(sleeptime >> 8);
  ST0 = (unsigned char) sleeptime;  
}


/*********************************************************************
 * 函式名稱:SetCC2530PowerMode
 * 功    能:設定CC2530功耗模式
 * 入口引數:pm : 0     空閒模式
 *                1     功耗模式PM1
 *                2     功耗模式PM2
 *                3     功耗模式PM3
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
SetCC2530PowerMode(unsigned char pm)
{

  if(pm == 0)
  {
    SLEEPCMD &= ~0x03;
  }
  else if(pm == 3)
  {
    SLEEPCMD |= ~0x03;
  }
  else
  {
    SLEEPCMD &= ~0x03;
    SLEEPCMD |= pm;
  }

  /* 進入所選擇的功耗模式 */
  PCON |= 0x01;                            
  
  asm("NOP");    
}


/*********************************************************************
 * 函式名稱:CC2530SleepTimer_Delay
 * 功    能:延時函式,延時過程中CC2530處於PM2模式。
 * 入口引數:nMs  延時時長
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void CC2530SleepTimer_Delay(unsigned nMs)
{

  SetCC2530SleepTime(nMs);
  

  IRCON &= ~0x80;
  

  IEN0 |= (0x01 << 5);
  

  SetCC2530PowerMode(2);
}


/*********************************************************************
 * 函式名稱:ST_ISR
 * 功    能:CC2530睡眠定時器中斷服務函式
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
#pragma vector=ST_VECTOR
__interrupt void ST_ISR(void)
{
  /* 清除CC2530睡眠定時器中斷標誌 */
  IRCON &= ~0x80;
  
  /* 禁止CC2530睡眠定時器中斷 */
  IEN0 &= ~(0x01 << 5);
}


/*********************************************************************
 * 函式名稱:SW_SPI_RW
 * 功    能:CC2530模擬SPI匯流排傳送1位元組資料並從SPI匯流排讀取1位元組資料。
 * 入口引數:value  待發送的1位元組資料
 * 出口引數:無
 * 返 回 值:讀回的1位元組資料
 ********************************************************************/
unsigned char
SW_SPI_RW(unsigned char value)
{
  unsigned char i;
   	
  for(i = 0; i < 8; i++)         
  {
    HAL_2G4Hz_MOSI = (value & 0x80)? 1 : 0;   
    value <<= 1;             
    HAL_2G4Hz_SCK = 1;                
    value |= HAL_2G4Hz_MISO;       	
    HAL_2G4Hz_SCK = 0;            	
  }
  HAL_2G4Hz_MOSI = 0; 
  return(value);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_irq_mode
 * 功    能:使能或禁止nRF24L01+的指定中斷源
 * 入口引數:int_source  nRF24L01+的指定中斷源
 *           irq_state   使能或禁止
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void hal_nrf_set_irq_mode(hal_nrf_irq_source_t int_source, bool irq_state)
{
  if(irq_state)
  {
    hal_nrf_write_reg(CONFIG, hal_nrf_read_reg(CONFIG) & ~SET_BIT(int_source));
  }
  else
  {
    hal_nrf_write_reg(CONFIG, hal_nrf_read_reg(CONFIG) | SET_BIT(int_source));
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_clear_irq_flags
 * 功    能:獲取並清除nRF24L01+的中斷標誌
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:中斷標誌
 *               0x10  最大重傳次數中斷
 *               0x20  TX資料傳送中斷
 *               0x40  RX資料接收中斷
 ********************************************************************/
unsigned char
hal_nrf_get_clear_irq_flags(void)
{
  return hal_nrf_write_reg(STATUS, (BIT_6|BIT_5|BIT_4)) & (BIT_6|BIT_5|BIT_4);
}


/*********************************************************************
 * 函式名稱:hal_nrf_clear_irq_flag
 * 功    能:清除nRF24L01+的指定中斷標誌
 * 入口引數:int_source  指定中斷源
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_clear_irq_flag(hal_nrf_irq_source_t int_source)
{
  hal_nrf_write_reg(STATUS, SET_BIT(int_source));
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_irq_mode
 * 功    能:獲取指定中斷的模式
 * 入口引數:int_type  指定中斷源
 * 出口引數:無
 * 返 回 值:FALSE 禁止
 *           TRUE  使能
 ********************************************************************/
bool 
hal_nrf_get_irq_mode(unsigned char int_type)
{
  if(hal_nrf_read_reg(CONFIG) & SET_BIT(int_type))
    return false;
  else
    return true;
}


/*********************************************************************
 * 函式名稱:hal_nrf_nop
 * 功    能:呼叫該函式接收nRF24L01+的狀態暫存器
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:狀態暫存器的值
 ********************************************************************/
unsigned char
hal_nrf_nop(void)
{
  return hal_nrf_write_reg(NOP,0);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_irq_flags
 * 功    能:獲取nRF24L01+的中斷標誌
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:中斷標誌
 *               0x10  最大重傳次數中斷
 *               0x20  TX資料傳送中斷
 *               0x40  RX資料接收中斷
 ********************************************************************/
unsigned char
hal_nrf_get_irq_flags(void)
{
  return hal_nrf_nop() & (BIT_6|BIT_5|BIT_4);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_crc_mode
 * 功    能:設定nRF24L01+的CRC模式
 * 入口引數:crc_mode  禁止
 *                     1位元組
 *                     2位元組
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_crc_mode(hal_nrf_crc_mode_t crc_mode)
{
  hal_nrf_write_reg(CONFIG, (hal_nrf_read_reg(CONFIG) & ~(BIT_3|BIT_2)) | 
                    (UINT8(crc_mode)<<2));
}


/*********************************************************************
 * 函式名稱:hal_nrf_open_pipe
 * 功    能:開啟nRF24L01+的1個或所有管道,並設定帶有/不帶自動ACK特性。
 * 入口引數:pipe_num  管道號
 *           auto_ack  自動ACK特性開/關
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_open_pipe(hal_nrf_address_t pipe_num, bool auto_ack)
{
  switch(pipe_num)
  {
    case HAL_NRF_PIPE0:
    case HAL_NRF_PIPE1:
    case HAL_NRF_PIPE2:
    case HAL_NRF_PIPE3:
    case HAL_NRF_PIPE4:
    case HAL_NRF_PIPE5:
      hal_nrf_write_reg(EN_RXADDR, hal_nrf_read_reg(EN_RXADDR) | SET_BIT(pipe_num));

      if(auto_ack)
        hal_nrf_write_reg(EN_AA, hal_nrf_read_reg(EN_AA) | SET_BIT(pipe_num));
      else
        hal_nrf_write_reg(EN_AA, hal_nrf_read_reg(EN_AA) & ~SET_BIT(pipe_num));
      break;

    case HAL_NRF_ALL:
      hal_nrf_write_reg(EN_RXADDR, ~(BIT_7|BIT_6));

      if(auto_ack)
        hal_nrf_write_reg(EN_AA, ~(BIT_7|BIT_6));
      else
        hal_nrf_write_reg(EN_AA, 0);
      break;
      
    default:
      break;
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_close_pipe
 * 功    能:關閉nRF24L01+的1個或所有管道
 * 入口引數:pipe_num  管道號
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_close_pipe(hal_nrf_address_t pipe_num)
{
  switch(pipe_num)
  {
    case HAL_NRF_PIPE0:
    case HAL_NRF_PIPE1:
    case HAL_NRF_PIPE2:
    case HAL_NRF_PIPE3:
    case HAL_NRF_PIPE4:
    case HAL_NRF_PIPE5:
      hal_nrf_write_reg(EN_RXADDR, hal_nrf_read_reg(EN_RXADDR) & ~SET_BIT(pipe_num));
      hal_nrf_write_reg(EN_AA, hal_nrf_read_reg(EN_AA) & ~SET_BIT(pipe_num));
      break;
    
    case HAL_NRF_ALL:
      hal_nrf_write_reg(EN_RXADDR, 0);
      hal_nrf_write_reg(EN_AA, 0);
      break;
      
    default:
      break;
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_address
 * 功    能:設定RX或TX地址
 * 入口引數:address  設定哪個地址
 *           addr     指向儲存地址值的緩衝區的指標
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_address(hal_nrf_address_t address, unsigned char *addr)
{
  switch(address)
  {
    case HAL_NRF_TX:
    case HAL_NRF_PIPE0:
    case HAL_NRF_PIPE1:
      hal_nrf_write_multibyte_reg((unsigned char) address, addr, 0);
      break;

    case HAL_NRF_PIPE2:
    case HAL_NRF_PIPE3:
    case HAL_NRF_PIPE4:
    case HAL_NRF_PIPE5:
      hal_nrf_write_reg(RX_ADDR_P0 + (unsigned char) address, *addr);
      break;

    default:
      break;
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_auto_retr
 * 功    能:設定重傳次數和重傳延時
 * 入口引數:retr   重傳次數
 *           delay  重傳延時(單位:us)
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_auto_retr(unsigned char retr, unsigned short delay)
{
  hal_nrf_write_reg(SETUP_RETR, (((delay/250)-1)<<4) | retr);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_address_width
 * 功    能:設定地址寬度
 * 入口引數:address_width  地址寬度
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_address_width(hal_nrf_address_width_t address_width)
{
  hal_nrf_write_reg(SETUP_AW, (UINT8(address_width) - 2));
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_rx_pload_width
 * 功    能:設定指定管道上期望接收的資料長度(單位:位元組)
 * 入口引數:pipe_num     管道
 *           pload_width  期望接收的位元組數量
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_rx_pload_width(unsigned char pipe_num, unsigned char pload_width)
{
  hal_nrf_write_reg(RX_PW_P0 + pipe_num, pload_width);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_crc_mode
 * 功    能:獲取所使用的CRC模式
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  無CRC
 *           0x02  CRC-8
 *           0x03  CRC-16
 ********************************************************************/
unsigned char
hal_nrf_get_crc_mode(void)
{
  return (hal_nrf_read_reg(CONFIG) & (BIT_3|BIT_2)) >> CRCO;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_pipe_status
 * 功    能:獲取指定管道的狀態
 * 入口引數:pipe_num  管道號
 * 出口引數:無
 * 返 回 值:0x00  管道關閉,自動ACK禁止
 *           0x01  管道開啟,自動ACK禁止
 *           0x03  管道開啟,自動ACK開啟
 ********************************************************************/
unsigned char
hal_nrf_get_pipe_status(unsigned char pipe_num)
{
  unsigned char en_rx, en_aa;

  en_rx = hal_nrf_read_reg(EN_RXADDR) & (1<<pipe_num);
  en_aa = hal_nrf_read_reg(EN_AA) & (1<<pipe_num);

  en_rx >>= pipe_num;
  en_aa >>= pipe_num;

  return (en_aa << 1) + en_rx;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_address
 * 功    能:獲取指定管道的地址
 * 入口引數:address  要獲取哪一種地址,PIPE或TX地址
 *           addr     獲取到得地址資料將寫入該指標指向的緩衝區
 * 出口引數:無
 * 返 回 值:地址寬度(單位:位元組)
 ********************************************************************/
unsigned char 
hal_nrf_get_address(unsigned char address, unsigned char *addr)
{
  switch(address)
  {
    case HAL_NRF_PIPE0:
    case HAL_NRF_PIPE1:
    case HAL_NRF_TX:
      return hal_nrf_read_multibyte_reg(address, addr);

    default:
      *addr = hal_nrf_read_reg(RX_ADDR_P0 + address);
      return hal_nrf_get_address_width();
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_auto_retr_status
 * 功    能:獲取自動重傳引數,即重傳次數和重傳延時。
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:高4位  重傳延時
 *           低4位  重傳次數
 ********************************************************************/
unsigned char
hal_nrf_get_auto_retr_status(void)
{
  return hal_nrf_read_reg(OBSERVE_TX);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_packet_lost_ctr
 * 功    能:獲取丟包計數器的值
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:丟包計數器的值
 ********************************************************************/
unsigned char 
hal_nrf_get_packet_lost_ctr(void)
{
  return (hal_nrf_read_reg(OBSERVE_TX) & (BIT_7|BIT_6|BIT_5|BIT_4)) >> 4;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_rx_pload_width
 * 功    能:獲取所指定管道上所期望接收的資料寬度(單位:位元組)
 * 入口引數:pipe_num  管道號
 * 出口引數:無
 * 返 回 值:資料寬度(單位:位元組)
 ********************************************************************/
unsigned char  
hal_nrf_get_rx_pload_width(unsigned char  pipe_num)
{
  return hal_nrf_read_reg(RX_PW_P0 + pipe_num);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_operation_mode
 * 功    能:進入 PTX (primary TX) 或 PRX (primary RX)模式
 * 入口引數:op_mode  執行模式
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_operation_mode(hal_nrf_operation_mode_t op_mode)
{
  if(op_mode == HAL_NRF_PRX)
  {
    hal_nrf_write_reg(CONFIG, (hal_nrf_read_reg(CONFIG) | (1<<PRIM_RX)));
  }
  else
  {
    hal_nrf_write_reg(CONFIG, (hal_nrf_read_reg(CONFIG) & ~(1<<PRIM_RX)));
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_power_mode
 * 功    能:上電或掉電RF
 * 入口引數:pwr_mode  POWER_UP 或 POWER_DOWN  
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_power_mode(hal_nrf_pwr_mode_t pwr_mode)
{
  if(pwr_mode == HAL_NRF_PWR_UP)
  {
    hal_nrf_write_reg(CONFIG, (hal_nrf_read_reg(CONFIG) | (1<<PWR_UP)));
  }
  else
  {
    hal_nrf_write_reg(CONFIG, (hal_nrf_read_reg(CONFIG) & ~(1<<PWR_UP)));
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_rf_channel
 * 功    能:選擇所使用的RF通道
 * 入口引數:channel  RF通道  
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_rf_channel(unsigned char channel)
{
  hal_nrf_write_reg(RF_CH, channel);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_output_power
 * 功    能:選擇RF TX輸出功率
 * 入口引數:power  RF TX輸出功率 
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_output_power(hal_nrf_output_power_t power)
{
  hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) & 
                    ~((1<<RF_PWR1)|(1<<RF_PWR0))) | (UINT8(power)<<1));
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_datarate
 * 功    能:設定無線通訊資料速率
 * 入口引數:datarate  無線通訊資料速率 
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_datarate(hal_nrf_datarate_t datarate)
{
  if(datarate == HAL_NRF_1MBPS)
  {
    hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) & ~(1<<RF_DR)));
  }
  else
  {
    hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) | (1<<RF_DR)));
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_operation_mode
 * 功    能:獲取執行模式
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  Primary RX (PRX) 
 *           0x01  Primary TX (PTX) 
 ********************************************************************/
unsigned char
hal_nrf_get_operation_mode(void)
{
  return (hal_nrf_read_reg(CONFIG) & (1<<PRIM_RX)) >> PRIM_RX;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_power_mode
 * 功    能:獲取功耗模式
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  POWER_DOWN  
 *           0x01  POWER_UP   
 ********************************************************************/
unsigned char 
hal_nrf_get_power_mode(void)
{
  return (hal_nrf_read_reg(CONFIG) & (1<<PWR_UP)) >> PWR_UP;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_rf_channel
 * 功    能:獲取所使用的RF通道
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:RF通道
 ********************************************************************/
unsigned char  
hal_nrf_get_rf_channel(void)
{
  return hal_nrf_read_reg(RF_CH);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_output_power
 * 功    能:獲取所使用的RF TX輸出功率
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  -18dBm
 *           0x01  -12dBm
 *           0x02  -6dBm
 *           0x03  0dBm
 ********************************************************************/
unsigned char  
hal_nrf_get_output_power(void)
{
  return (hal_nrf_read_reg(RF_SETUP) & ((1<<RF_PWR1)|(1<<RF_PWR0))) >> RF_PWR0;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_datarate
 * 功    能:獲取所使用的無線通訊資料速率
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  1Mbps 
 *           0x01  2Mbps
 ********************************************************************/
unsigned char
hal_nrf_get_datarate(void)
{
  return (hal_nrf_read_reg(RF_SETUP) & (1<<RF_DR)) >> RF_DR;
}


/*********************************************************************
 * 函式名稱:hal_nrf_rx_fifo_empty
 * 功    能:檢查RX FIFO是否為空
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FALSE  RX FIFO 不空   
 *           TRUE   RX FIFO 空
 ********************************************************************/
bool 
hal_nrf_rx_fifo_empty(void)
{
 if(hal_nrf_get_rx_data_source()==7)
  {
    return true;
  }
  else
  {
    return false;
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_rx_fifo_full
 * 功    能:檢查RX FIFO是否為滿
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FALSE  RX FIFO 不滿   
 *           TRUE   RX FIFO 滿
 ********************************************************************/
bool 
hal_nrf_rx_fifo_full(void)
{
  return (bool)((hal_nrf_read_reg(FIFO_STATUS) >> RX_EMPTY) & 1);
}


/*********************************************************************
 * 函式名稱:hal_nrf_tx_fifo_empty
 * 功    能:檢查TX FIFO是否為空
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FALSE  TX FIFO 不空   
 *           TRUE   TX FIFO 空
 ********************************************************************/
bool 
hal_nrf_tx_fifo_empty(void)
{
  return (bool)((hal_nrf_read_reg(FIFO_STATUS) >> TX_EMPTY) & 1);
}


/*********************************************************************
 * 函式名稱:hal_nrf_tx_fifo_full
 * 功    能:檢查TX FIFO是否為滿
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FALSE  TX FIFO 不滿  
 *           TRUE   TX FIFO 滿
 ********************************************************************/
bool 
hal_nrf_tx_fifo_full(void)
{
  return (bool)((hal_nrf_read_reg(FIFO_STATUS) >> TX_FIFO_FULL) & 1);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_tx_fifo_status
 * 功    能:檢查TX FIFO的狀態
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  TX FIFO 不空, 也不滿    
 *           0x01  TX FIFO 空
 *           0x02  TX FIFO 滿
 ********************************************************************/
unsigned char
hal_nrf_get_tx_fifo_status(void)
{
  return ((hal_nrf_read_reg(FIFO_STATUS) & 
           ((1<<TX_FIFO_FULL)|(1<<TX_EMPTY))) >> 4);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_rx_fifo_status
 * 功    能:檢查RX FIFO的狀態
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:0x00  RX FIFO 不空, 也不滿    
 *           0x01  RX FIFO 空
 *           0x02  RX FIFO 滿
 ********************************************************************/
unsigned char
hal_nrf_get_rx_fifo_status(void)
{
  return (hal_nrf_read_reg(FIFO_STATUS) & ((1<<RX_FULL)|(1<<RX_EMPTY)));
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_fifo_status
 * 功    能:檢查FIFO狀態
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FIFO狀態暫存器的值
 ********************************************************************/
unsigned char 
hal_nrf_get_fifo_status(void)
{
  return hal_nrf_read_reg(FIFO_STATUS);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_transmit_attempts
 * 功    能:獲取重傳嘗試的次數和丟包數量
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:重傳嘗試計數器的值
 ********************************************************************/
unsigned char 
hal_nrf_get_transmit_attempts(void)
{
  return hal_nrf_read_reg(OBSERVE_TX) & (BIT_3|BIT_2|BIT_1|BIT_0);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_carrier_detect
 * 功    能:獲取載波檢測標誌
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FALSE  未檢測到載波
 *           TRUE   檢測到載波
 ********************************************************************/
bool 
hal_nrf_get_carrier_detect(void)
{
  return hal_nrf_read_reg(CD) & 1;
}


/*********************************************************************
 * 函式名稱:hal_nrf_write_tx_pload
 * 功    能:寫資料包的資料載荷部分到RF
 * 入口引數:tx_pload  指向儲存資料載荷的緩衝區的指標
 *           length    資料載荷的長度(單位:位元組)
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_write_tx_pload(unsigned char *tx_pload, unsigned char length)
{
  hal_nrf_write_multibyte_reg(UINT8(HAL_NRF_TX_PLOAD), tx_pload, length);
}


/*********************************************************************
 * 函式名稱:hal_nrf_setup_dyn_pl
 * 功    能:設定接收管道的動態資料負載特性。
 * 入口引數:setup  管道特性位掩碼
 *                  例如:bit0設定為1時,管道0使用ACK資料負載。
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_setup_dyn_pl(unsigned char setup)
{
  hal_nrf_write_reg(DYNPD, setup & ~0xC0); 
}


/*********************************************************************
 * 函式名稱:hal_nrf_enable_dynamic_pl
 * 功    能:使能動態資料負載特性。
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_enable_dynamic_pl(void)
{
  hal_nrf_write_reg(FEATURE, (hal_nrf_read_reg(FEATURE) | 0x04));   
}


/*********************************************************************
 * 函式名稱:hal_nrf_disable_dynamic_pl
 * 功    能:禁止動態資料負載特性。
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_disable_dynamic_pl(void)
{
  hal_nrf_write_reg(FEATURE, (hal_nrf_read_reg(FEATURE) & ~0x04));   
}


/*********************************************************************
 * 函式名稱:hal_nrf_enable_ack_pl
 * 功    能:使能ACK資料負載特性。
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_enable_ack_pl(void)
{
  hal_nrf_write_reg(FEATURE, (hal_nrf_read_reg(FEATURE) | 0x02));   
}


/*********************************************************************
 * 函式名稱:hal_nrf_disable_ack_pl
 * 功    能:禁止ACK資料負載特性。
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_disable_ack_pl(void)
{
  hal_nrf_write_reg(FEATURE, (hal_nrf_read_reg(FEATURE) & ~0x02));   
}


/*********************************************************************
 * 函式名稱:hal_nrf_enable_dynamic_ack
 * 功    能:使能no-ack特性
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_enable_dynamic_ack(void)
{
  hal_nrf_write_reg(FEATURE, (hal_nrf_read_reg(FEATURE) | 0x01));   
}


/*********************************************************************
 * 函式名稱:hal_nrf_disable_dynamic_ack
 * 功    能:禁止no-ack特性
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_disable_dynamic_ack(void)
{
  hal_nrf_write_reg(FEATURE, (hal_nrf_read_reg(FEATURE) & ~0x01));   
}


/*********************************************************************
 * 函式名稱:hal_nrf_write_ack_pload
 * 功    能:給指定管道寫入帶ACK特性的資料負載。
 * 入口引數:pipe      管道號
 *           tx_pload  指向儲存待寫入資料的緩衝區的指標
 *           length    待寫入資料的長度(單位:位元組)
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_write_ack_pload(unsigned char pipe, unsigned char *tx_pload, 
                        unsigned char length)
{
  HAL_2G4Hz_CSN = 0;

  SW_SPI_RW(WR_ACK_PLOAD | pipe);
  while(length--)
  {
    SW_SPI_RW(*tx_pload++);
  }

  HAL_2G4Hz_CSN = 1;
}


/*********************************************************************
 * 函式名稱:hal_nrf_read_rx_pl_w
 * 功    能:讀取接收到的ACK資料負載的寬度
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:接收到的ACK資料負載的寬度
 ********************************************************************/
unsigned char 
hal_nrf_read_rx_pl_w()
{
  unsigned char temp;
  
  HAL_2G4Hz_CSN = 0;

  SW_SPI_RW(RD_RX_PLOAD_W);
  temp = SW_SPI_RW(0);
  
  HAL_2G4Hz_CSN = 1;

  return temp;
}


/*********************************************************************
 * 函式名稱:hal_nrf_lock_unlock
 * 功    能:給nRF24L01+傳送ACTIVATE命令
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_lock_unlock()
{
  HAL_2G4Hz_CSN = 0;

  SW_SPI_RW(LOCK_UNLOCK);             
  SW_SPI_RW(0x73);

  HAL_2G4Hz_CSN = 1;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_rx_data_source
 * 功    能:獲取當前哪一個管道接收的資料包是當前最高級別資料包
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:管道號
 ********************************************************************/
unsigned char 
hal_nrf_get_rx_data_source(void)
{
  return ((hal_nrf_nop() & (BIT_3|BIT_2|BIT_1)) >> 1);
}


/*********************************************************************
 * 函式名稱:hal_nrf_read_reg
 * 功    能:讀取nRF24L01+的暫存器內容
 * 入口引數:reg  要讀取的暫存器
 * 出口引數:無
 * 返 回 值:讀出的暫存器內容
 ********************************************************************/
unsigned char
hal_nrf_read_reg(unsigned char reg)
{
  unsigned char temp;
  
  HAL_2G4Hz_CSN = 0;
  SW_SPI_RW(reg);
  temp = SW_SPI_RW(0);
  HAL_2G4Hz_CSN = 1;
  
  return temp;
}


/*********************************************************************
 * 函式名稱:hal_nrf_read_rx_pload
 * 功    能:讀取RX FIFO中可用的最高級別資料載荷
 * 入口引數:rx_pload  指向儲存讀出資料的緩衝區的指標
 * 出口引數:無
 * 返 回 值:高8位  管道號
 *           低8位  資料長度(單位:位元組)
 *           資料長度為0且管道號為7意味著FIFO為空
 ********************************************************************/
unsigned short 
hal_nrf_read_rx_pload(unsigned char *rx_pload)
{
  return hal_nrf_read_multibyte_reg(UINT8(HAL_NRF_RX_PLOAD), rx_pload);
}


/*********************************************************************
 * 函式名稱:hal_nrf_reuse_tx
 * 功    能:設定RF使用最後一次傳送的資料載荷作為下一個資料包
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_reuse_tx(void)
{
  hal_nrf_write_reg(REUSE_TX_PL, 0);
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_reuse_tx_status
 * 功    能:檢查reuse_tx功能的狀態
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:FALSE  未啟用
 *           TRUE   啟用
 ********************************************************************/
bool 
hal_nrf_get_reuse_tx_status(void)
{
  return (bool)((hal_nrf_get_fifo_status() & (1<<TX_REUSE)) >> TX_REUSE);
}


/*********************************************************************
 * 函式名稱:hal_nrf_flush_rx
 * 功    能:清空RX FIFO
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_flush_rx(void)
{
  hal_nrf_write_reg(FLUSH_RX, 0);
}


/*********************************************************************
 * 函式名稱:hal_nrf_flush_tx
 * 功    能:清空TX FIFO
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_flush_tx(void)
{
  hal_nrf_write_reg(FLUSH_TX, 0);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_pll_mode
 * 功    能:LOCK或UNLOCK RF PLL
 * 入口引數:pll_mode  PLL locked: TRUE 或 FALSE 
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_pll_mode(hal_nrf_pll_mode_t pll_mode)
{
  if(pll_mode == HAL_NRF_PLL_LOCK)
  {
    hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) | (1<<PLL_LOCK)));
  }
  else
  {
    hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) & ~(1<<PLL_LOCK)));
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_pll_mode
 * 功    能:獲取 RF PLL的當前模式
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:RF PLL的當前模式
 ********************************************************************/
hal_nrf_pll_mode_t 
hal_nrf_get_pll_mode(void)
{
  return (hal_nrf_pll_mode_t)((hal_nrf_read_reg(RF_SETUP) & 
                               (1<<PLL_LOCK)) >> PLL_LOCK);
}


/*********************************************************************
 * 函式名稱:hal_nrf_set_lna_gain
 * 功    能:設定RF使用的LNA增益模式
 * 入口引數:lna_gain  LNA增益模式
 * 出口引數:無
 * 返 回 值:無
 ********************************************************************/
void 
hal_nrf_set_lna_gain(hal_nrf_lna_mode_t lna_gain)
{
  if(lna_gain == HAL_NRF_LNA_HCURR)
  {
    hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) | (1<<LNA_HCURR)));
  }
  else
  {
    hal_nrf_write_reg(RF_SETUP, (hal_nrf_read_reg(RF_SETUP) & ~(1<<LNA_HCURR)));
  }
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_lna_gain
 * 功    能:獲取RF當前使用的LNA增益模式
 * 入口引數:lna_gain  LNA增益模式
 * 出口引數:無
 * 返 回 值:0  LNA 低電流
 *           1  LNA 高電流
 ********************************************************************/
hal_nrf_lna_mode_t 
hal_nrf_get_lna_gain(void)
{
  return (hal_nrf_lna_mode_t) ( (hal_nrf_read_reg(RF_SETUP) & 
                                 (1<<LNA_HCURR)) >> LNA_HCURR );
}


/*********************************************************************
 * 函式名稱:hal_nrf_read_multibyte_reg
 * 功    能:從nRF24L01+的指定暫存器讀取多位元組資料
 * 入口引數:reg    nRF24L01+的指定暫存器
 *           pbuf   指向儲存讀出資料的緩衝區的指標
 * 出口引數:無
 * 返 回 值:高8位:接收資料的管道號(用於hal_nrf_read_rx_pload函式)
 *           低8位:讀取資料的長度(用於hal_nrf_read_rx_pload 或hal_nrf_get_address函式)
 ********************************************************************/
unsigned short
hal_nrf_read_multibyte_reg(unsigned char reg, unsigned char *pbuf)
{
  unsigned char ctr, length;
  switch(reg)
  {
    case HAL_NRF_PIPE0:
    case HAL_NRF_PIPE1:
    case HAL_NRF_TX:
      length = ctr = hal_nrf_get_address_width();
      HAL_2G4Hz_CSN = 0;
      SW_SPI_RW(RX_ADDR_P0 + reg);
      break;
      
    case HAL_NRF_RX_PLOAD:
      if( (reg = hal_nrf_get_rx_data_source()) < 7)
      {
        length = ctr = hal_nrf_read_rx_pl_w();

        HAL_2G4Hz_CSN = 0;
        SW_SPI_RW(RD_RX_PLOAD);
      }
      else
      {
       ctr = length = 0;
      }
      break;

    default:
      ctr = length = 0;
      break;
  }

  while(ctr--)
  {
    *pbuf++ = SW_SPI_RW(0);
  }

    HAL_2G4Hz_CSN = 1;

  return (((unsigned short) reg << 8) | length);
}


/*********************************************************************
 * 函式名稱:hal_nrf_write_reg
 * 功    能:寫一個新值到nRF24L01+的指定暫存器
 * 入口引數:reg    待寫入新值的暫存器
 *           value  待寫入的新值
 * 出口引數:無
 * 返 回 值:1位元組返回值
 ********************************************************************/
unsigned char
hal_nrf_write_reg(unsigned char reg, unsigned char value)
{
  unsigned char retval;
  
  HAL_2G4Hz_CSN = 0;

  if(reg < WRITE_REG)
  {
    retval = SW_SPI_RW(WRITE_REG + reg);
    SW_SPI_RW(value);
  }

  else
  {
    if(!(reg == FLUSH_TX) && !(reg == FLUSH_RX) && !(reg == REUSE_TX_PL) && !(reg == NOP))
    {
      retval = SW_SPI_RW(reg);
      SW_SPI_RW(value);
    }

    else
    {
      retval = SW_SPI_RW(reg);
    }
  }
  HAL_2G4Hz_CSN = 1;

  return retval;
}


/*********************************************************************
 * 函式名稱:hal_nrf_get_address_width
 * 功    能:獲取nRF24L01+射頻使用的地址寬度,包括RX和TX
 * 入口引數:無
 * 出口引數:無
 * 返 回 值:地址寬度(單位:位元組)
 ********************************************************************/
unsigned char
hal_nrf_get_address_width(void)
{
  return (hal_nrf_read_reg(SETUP_AW) + 2);
}


/*********************************************************************
 * 函式名稱:hal_nrf_write_multibyte_reg
 * 功    能:寫多個位元組資料