MfRc500uC.c
上传用户:liao421
上传日期:2013-06-13
资源大小:35k
文件大小:92k
源码类别:

RFID编程

开发平台:

C/C++

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //    Copyright (c), Philips Semiconductors Gratkorn
  3. //
  4. //                  (C)PHILIPS Electronics N.V.2000
  5. //                     All rights are reserved. 
  6. //  Philips reserves the right to make changes without notice at any time.
  7. // Philips makes no warranty, expressed, implied or statutory, including but
  8. // not limited to any implied warranty of merchantibility or fitness for any
  9. //particular purpose, or that the use will not infringe any third party patent,
  10. // copyright or trademark. Philips must not be liable for any loss or damage
  11. //                          arising from its use.
  12. ///////////////////////////////////////////////////////////////////////////////
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include "RICReg.H"
  16. #include "MfRc500.h"
  17. #include "PICCCmdConst.h"
  18. #include "MfErrNo.h"
  19. /* 
  20. * Projekt: MF EV X00 Firmware
  21. *
  22. * $Workfile:: MfRc500uC.c                                               $ 
  23. * $Modtime:: 24.06.02 15:41                                             $ 
  24. * $Author:: Hb                                                          $
  25. * $Revision:: 8                                                         $
  26. *
  27. * This library modul is written for a C166 microcontroller derivative.
  28. * The source can be ported to other platforms very easily. 
  29. * In our case the reader module is 
  30. * connected via memory mapped io at base address 0x100000.
  31. * The interrupt pin of the reader IC is assumed to be connected to 
  32. * the fast external interrupt pin INT0# (active low) and the reset
  33. * pin of the reader IC should be connected to a dedicated port pin
  34. * (Port: P1 Pin: 9).
  35. * In this configuration, a reset of the reader module is independend
  36. * from the reset of the microcontroller.
  37. * All protocoll 
  38. * relevant timing constraints are generated
  39. * by the internal timer of the reader module.
  40. * Some explanations to the programming method of this library.
  41. * There are three kind of functions coded in this module.
  42. *
  43. *  ---- internal functions, which have no prototypes in a header
  44. *       file. This kind of functions are not intended to be used 
  45. *       outside of this file
  46. *  ---- commands, which are intended for the reader module itself
  47. *  ---- commands, which are intended for any tag in the rf field.
  48. *       These commands are send to the reader and the reader module
  49. *       transmitts the data to the rf interface.
  50. *
  51. * Commands for the reader and for the tag have the appropriate 
  52. * prefix (PCD for Proximity Coupled Device or reader module
  53. * PICC for Proximity Integrated Circuit Card or tag)
  54. * and their protypes are defined in the header file.
  55. * Certainly, each command for a PICC consists of an instruction to the PCD. 
  56. * Therefore
  57. * the function PcdSingleResponseCmd is very important for the understanding
  58. * of the communication.
  59. * The basic functionality is provided by the interrupt service
  60. * routine (SingleResponseCmd), which closely works together with the function
  61. * PcdSingleResponseCmd. All kinds of interrupts are serviced by the 
  62. * same ISR. 
  63. */
  64. ///////////////////////////////////////////////////////////////////////////////
  65. //             M O D U L   V A R I A B L E S 
  66. ///////////////////////////////////////////////////////////////////////////////
  67. // interrupt vector number for interrupt of the RIC
  68. // select the appropriate value corresponding to the microcontroller in use
  69. #define READER_INT       // e. g. 0x18 
  70. // disable reader interrupt
  71. // select the appropriate value corresponding to the microcontroller in use
  72. #define READER_INT_DISABLE    // e. g. EXICON &= ~0x0002
  73. // enable reader interrupt
  74. // select the appropriate value corresponding to the microcontroller in use
  75. #define READER_INT_ENABLE     // e. g. EXICON |= 0x0002
  76. // initialize reset pin and change port direction
  77. // select the appropriate value corresponding to the microcontroller in use
  78. #define READER_INIT_RESET    // e. g. P6 |= 0x20; DP6 |= 0x20
  79. // set reset pin
  80. // select the appropriate value corresponding to the microcontroller in use
  81. #define READER_RESET         // e. g. P6 |= 0x20
  82. // clear reset pin
  83. // select the appropriate value corresponding to the microcontroller in use
  84. #define READER_CLEAR_RESET    // e. g. P6 &= ~0x20
  85. // memory base address corresponding to the previous set address select register
  86. // select the appropriate value corresponding to the microcontroller in use
  87. #define MEMORY_BASE_ADDRESS    0x100000
  88. // the RIC has only 3 address lines - page select is necessary
  89. #define GetRegPage(addr) (0x80 | (addr>>3))
  90. /* ISO14443 Support Properties
  91. * Some of the protokoll functions of ISO14443 needs information about
  92. * the capability of the reader device, which are provided by this
  93. * constants.
  94. */
  95. //{
  96. #define TCLFSDSNDMAX   8   ///< max. frame size send
  97. #define TCLFSDRECMAX   8   ///< max. frame size rcv
  98. #define TCLDSMAX       3   ///< max. baudrate divider PICC --> PCD
  99. #define TCLDRMAX       3   ///< max. baudrate divider PCD --> PICC
  100. #define TCLDSDFLT      0   ///< default baudrate divider PICC --> PCD
  101. #define TCLDRDFLT      0   ///< default baudrate divider PCD --> PICC
  102. //}
  103. /* ISR communication structures
  104. * All parameters are passed to the ISR via this structure.
  105. */
  106. //{
  107. // struct definition for a communication channel between function and ISR
  108. typedef struct 
  109.          {
  110.             unsigned char  cmd;           //!< command code 
  111.             char           status;        //!< communication status
  112.             unsigned short nBytesSent;    //!< how many bytes already sent
  113.             unsigned short nBytesToSend;  //!< how many bytes to send
  114.             unsigned short nBytesReceived;//!< how many bytes received
  115.             unsigned long  nBitsReceived; //!< how many bits received
  116.             unsigned char  irqSource;     //!< which interrupts have occured
  117.             unsigned char  collPos;       /*!< at which position occured a
  118.                                           collision*/
  119.             unsigned char  errFlags;      //!< error flags
  120.             unsigned char  saveErrorState;//!< accumulated error flags for
  121.                                           //!< multiple responses
  122.             unsigned char  RxAlignWA;     //!< workaround for RxAlign = 7
  123.             unsigned char  DisableDF;     //!< disable disturbance filter
  124.          } MfCmdInfo;
  125. // Convinience function for initialising the communication structure.
  126. #define ResetInfo(info)    
  127.             info.cmd            = 0; 
  128.             info.status         = MI_OK;
  129.             info.irqSource      = 0; 
  130.             info.nBytesSent     = 0; 
  131.             info.nBytesToSend   = 0; 
  132.             info.nBytesReceived = 0; 
  133.             info.nBitsReceived  = 0; 
  134.             info.collPos        = 0; 
  135.             info.errFlags       = 0; 
  136.             info.saveErrorState = 0; 
  137.             info.RxAlignWA      = 0; 
  138.             info.DisableDF      = 0;
  139. // In order to exchange some values between the ISR and the calling function,
  140. // a struct is provided. 
  141. volatile MfCmdInfo     MInfo;                  
  142. // communication info stucture
  143. static   volatile MfCmdInfo     *MpIsrInfo = 0; 
  144. // ISR send buffer
  145. static   volatile unsigned char *MpIsrOut = 0; 
  146. // ISR receive buffer
  147. static   volatile unsigned char *MpIsrIn = 0;   
  148. //}
  149. // storage of the last selected serial number including check byte.
  150. // For multi level serial numbers, only the first 4 bytes are stored.
  151. unsigned char MLastSelectedSnr[5];
  152. // storage buffer for receive and transmit routines
  153. //{
  154. #define MEMORY_BUFFER_SIZE    300
  155. volatile unsigned char MemPool[MEMORY_BUFFER_SIZE];
  156. volatile unsigned char *MSndBuffer = MemPool; // pointer to the transmit buffer
  157. volatile unsigned char *MRcvBuffer = MemPool; // pointer to the receive buffer
  158. //}
  159. /* Higher Baudrate Control
  160. * attention: RegDecoderControl is modified in CascAnticoll
  161. * Because of standard baudrate usage during anticollision, the 
  162. * register can be written. For general purpose usage, only some bits 
  163. * should be set.         
  164. *
  165. * Please pay attention, that the location of the configuration array is
  166. * in ROM space, that means that on 16 bit microcontroller the access 
  167. * should be word aligned.
  168. */
  169. //{
  170. typedef struct 
  171.          {
  172.             unsigned short  SubCarrierPulses; ///< RegRxControl1
  173.             unsigned short  RxCoding;         ///< RegDecoderControl
  174.             unsigned short  RxThreshold;      ///< RegRxThreshold
  175.             unsigned short  BPSKDemControl;   ///< RegBPSKDemControl
  176.          } t_DSCfg;
  177. typedef struct 
  178.          {
  179.             unsigned short  CoderRate;        ///< RegCoderControl
  180.             unsigned short  ModWidth;         ///< RegModWidth
  181.          } t_DRCfg;
  182.      
  183. const t_DSCfg  MDSCfg[4] = {{0x73,0x08,0x88,0x00}     // Manchaster 106 kBaud
  184.                             ,{0x53,0x09,0x50,0x0C}     // BPSK 212 kBaud
  185.                             ,{0x33,0x09,0x50,0x0C}     // BPSK 424 kBaud
  186.                             ,{0x13,0x09,0x50,0x0C}};   // BPSK 848 kBaud
  187. const t_DRCfg  MDRCfg[4] = {{0x19,0x13}          // Miller 106 kBaud
  188.                             ,{0x11,0x07}          // Miller 212 kBaud
  189.                             ,{0x09,0x03}          // Miller 424 kBaud
  190.                             ,{0x01,0x01}};        // Miller 848 kBaud
  191. // data send baudrate divider PICC --> PCD
  192. static unsigned char MDSI = TCLDSDFLT;    
  193. // data send baudrate divider PCD --> PICC
  194. static unsigned char MDRI = TCLDRDFLT;   
  195. //}
  196. // Write one byte to the reader IC address space
  197. /*!
  198. * -o  address  (IN) reader ic register address
  199. * -o  value    (IN) 8 bit value
  200. * return: none
  201. *
  202. * Function for writting one char to the reader module
  203. *
  204. * The reader module is connected to a 16 bit demultiplexed bus,
  205. * therefore the address pin of the reader module is mapped as
  206. * follows: n
  207. * uC             Reader n
  208. * A1               A0   n
  209. * A2               A1   n
  210. * A3               A2   n
  211. *
  212. * In order to get the correct address, the original address need to 
  213. * be multiplied by 2.
  214. */
  215. #define WriteRawRC(addr,value) *(gpcRCBaseAddress + addr) = value;
  216. //! Read one byte from the reader IC address space
  217. /*!
  218. * -o  address  (IN) reader ic register address
  219. * -o  value    (IN) 8 bit value
  220. * return: none
  221. *
  222. * Function for reading one char from the reader module
  223. *
  224. * The reader module is connected to a 16 bit demultiplexed bus,
  225. * therefore the address pin of the reader module is mapped as
  226. * follows: n
  227. * uC             Reader n
  228. * A1               A0   n
  229. * A2               A1   n
  230. * A3               A2   n
  231. *
  232. * In order to get the correct address, the original address need to 
  233. * be multiplied by 2.
  234. */
  235. #define ReadRawRC(addr) (*(gpcRCBaseAddress + addr))
  236. //! Open Reader IC Connection
  237. /*!
  238. * -o  none
  239. * return: MI_OK
  240. *         other    error opening reader ic channel
  241. *
  242. * Open and initialize communication channel to the reader module
  243. */
  244. char OpenRC(void);
  245. //! Write one byte to the reader IC address space
  246. /*!
  247. * -o  address  (IN) reader ic register address
  248. * -o  value    (IN) 8 bit value
  249. * return: none
  250. *
  251. * This function determines the necessary page address of the 
  252. * reader module and writes the page number to the page 
  253. * register and the value to the specified address.
  254. */
  255. void WriteRC(unsigned char Address, unsigned char value);
  256. //! Write one byte to the reader IC address space
  257. /*
  258. * -o  address   (IN) reader IC register address
  259. * return: value    8 bit data, read from the reader ic address space
  260. *
  261. * This function determines the necessary page address of the 
  262. * reader module and writes the page number to the page 
  263. * register and reads the value from the specified address.
  264. */
  265. unsigned char ReadRC(unsigned char Address);
  266. //! Close reader IC communication channel
  267. /*!
  268. * -o  none
  269. * return: none
  270. *
  271. * Closing the communication channel to the reader module
  272. */
  273. void CloseRC(void);
  274. // In case of a parallel connection, the address space of the reader module
  275. // needs to be mapped to the address space of the microcontroller. Therefore
  276. // a base address is reserved.
  277. unsigned char * const gpcRCBaseAddress = (unsigned char * const)(MEMORY_BASE_ADDRESS);
  278. ///////////////////////////////////////////////////////////////////////////////
  279. //                 Open Reader Communication
  280. ///////////////////////////////////////////////////////////////////////////////
  281. char OpenRC(void)
  282. {
  283.    signed char status = MI_OK;
  284.    READER_INIT_RESET;
  285.    return status;
  286. }
  287. ///////////////////////////////////////////////////////////////////////////////
  288. //                 Close Reader Communication
  289. ///////////////////////////////////////////////////////////////////////////////
  290. void CloseRC(void)
  291. {
  292. }
  293. ///////////////////////////////////////////////////////////////////////////////
  294. //          G E N E R I C    W R I T E
  295. ///////////////////////////////////////////////////////////////////////////////
  296. void WriteRC(unsigned char Address, unsigned char value)
  297. {
  298.    WriteRawRC(0x00,GetRegPage(Address));   // select appropriate page
  299.    WriteRawRC(Address,value);              // write value at the specified 
  300.                                            // address
  301. }
  302. ///////////////////////////////////////////////////////////////////////////////
  303. //          G E N E R I C    R E A D
  304. ///////////////////////////////////////////////////////////////////////////////
  305. unsigned char ReadRC(unsigned char Address)
  306. {
  307.    WriteRawRC(0x00,GetRegPage(Address));   // select appropriate page
  308.    return ReadRawRC(Address);              // read value at the specified 
  309. }  
  310. ///////////////////////////////////////////////////////////////////////////////
  311. //             Prototypes for local functions 
  312. ///////////////////////////////////////////////////////////////////////////////
  313. ///  Internal Authentication State Switch
  314. /*!
  315. * -o  auth_mode (IN) 
  316. *                  enum: selects master key A or master key B 
  317. *                   - PICC_AUTHENT1A
  318. *                   - PICC_AUTHENT1B 
  319. *                  
  320. * -o  *snr      (IN) 
  321. *                  4 byte serial number of the card, which should be 
  322. *                  authenticated
  323. * -o  sector (IN) Range [0..15] 
  324. *               specifies the key RAM address 
  325. *               from which the keys should be taken
  326. * return: enum:
  327. *          - MI_OK
  328. *          - CCE
  329. *          - MI_BITCOUNTERR  wrong number of bits received
  330. *          - MI_AUTHERR      wrong keys for selected card
  331. *          - MI_KEYERR       error while loading keys
  332. *         
  333. * Internal authentication state function.
  334. */
  335. char Mf500PiccAuthState(unsigned char auth_mode,// PICC_AUTHENT1A, PICC_AUTHENT1B
  336.                        unsigned char *snr,    // 4 byte serial number
  337.                        unsigned char sector); // 0 <= sector <= 15  
  338.                                             // sector address for authentication
  339. /// Write Baudrate Divider
  340. /*!
  341. * -o     none
  342. * return:   MI_OK
  343. *
  344. * Write function for baudrate divider and PCD properties
  345. */
  346. char  Mf500PcdWriteAttrib(void);
  347. /* ISR Communication Structure
  348. * Data, which have to be passed between ISR and other functions are
  349. * colleted within one structure. 
  350. */ 
  351. //{
  352. // ISR for Single Response Commands 
  353. /*
  354. * -o  none
  355. * return: none
  356. *
  357. * This function is a central routine in the communication chain between
  358. * PCD and PICC. 
  359. */ 
  360. //interrupt (READER_INT) 
  361. void SingleResponseIsr(void);
  362. // Command issuer for Single Response Commands 
  363. /*
  364. * -o  cmd  (IN)
  365. *             Command type
  366. *             enum:
  367. *              - PCD_IDLE
  368. *              - PCD_WRITEE2
  369. *              - PCD_READE2
  370. *              - PCD_LOADCONFIG
  371. *              - PCD_LOADKEYE2
  372. *              - PCD_AUTHENT1
  373. *              - PCD_CALCCRC
  374. *              - PCD_AUTHENT2
  375. *              - PCD_RECEIVE
  376. *              - PCD_LOADKEY
  377. *              - PCD_TRANSMIT
  378. *              - PCD_TRANSCEIVE
  379. *             
  380. *       send  (IN)
  381. *             byte stream of variable length, which should be send to
  382. *             the PICC, the length of stream has to be specified
  383. *             in the info - structure
  384. *       rcv   (OUT) 
  385. *             byte stream of variable length, which was received 
  386. *             from the PICC. The length can be obtained from the
  387. *             info - structure
  388. *       info  (OUT)
  389. *             communication and status structure
  390. * return: enum:
  391. *          - MI_OK               operation without error
  392. *          - MI_NOTAGERR         no tag in rf field
  393. *          - MI_ACCESSTIMEOUT    RIC is not responding in time
  394. *          - MI_COLLERR          collision in during rf data transfer
  395. *          - MI_PARITYERR        parity error while receiving data
  396. *          - MI_FRAMINGERR       framing error - start bit not valid
  397. *          - MI_OVFLERR          FIFO overflow - to many data bytes
  398. *          - MI_CRCERR           CRC error of received data
  399. *          - MI_NY_IMPLEMENTED   internal error - source not identified
  400. *         
  401. *
  402. * This function provides the central interface to the reader module.
  403. * Depending on the "cmd"-value, all necessary interrupts are enabled
  404. * and the communication is started. While the processing is done by
  405. * the reader module, this function waits for its completion.
  406. *
  407. * It's notable, that the data in the send byte stream is written 
  408. * to the FIFO of the reader module by the ISR itself. Immediate after 
  409. * enabling the interrupts, the LoAlert interrupt is activated.
  410. *
  411. * The ISR writes the data to the FIFO. This function is not directly involved
  412. * in writing or fetching data from FIFO, all work is done by the 
  413. * corresponding ISR.After command completion, the error status is evaluated and 
  414. * returned to the calling function.
  415. */ 
  416. char PcdSingleResponseCmd(unsigned char cmd,
  417.                 volatile unsigned char* send, 
  418.                 volatile unsigned char* rcv,
  419.                 volatile MfCmdInfo *info);
  420. /// Basic Register definitions
  421. /*!
  422. * return: none
  423. */
  424. char PcdBasicRegisterConfiguration(void);
  425. /// Set Reader IC Register Bit
  426. /*!
  427. * -o  reg  (IN)
  428. *             register address
  429. * -o  mask (IN)
  430. *             Bit mask to set
  431. * return:     none
  432. *              
  433. * This function performs a read - modify - write sequence
  434. * on the specified register. All bits with a 1 in the mask
  435. * are set - all other bits keep their original value.
  436. */
  437. void SetBitMask(unsigned char reg,unsigned char mask);
  438. /// Clear Reader IC Register Bit
  439. /*!
  440. * -o  reg  (IN)
  441. *             register address
  442. * -o  mask (IN)
  443. *             Bit mask to clear
  444. * return: none
  445. *              
  446. * This function performs a read - modify - write sequence
  447. * on the specified register. All bits with a 1 in the mask
  448. * are cleared - all other bits keep their original value.
  449. */
  450. void ClearBitMask(unsigned char reg,unsigned char mask);
  451. /// Flush remaining data from the FIFO
  452. /*!
  453. * -o  none
  454. * return: none
  455. *              
  456. * This function erases  all remaining data in the MF RC 500's FIFO .
  457. * Before writing new data or starting a new command, all remaining data 
  458. * from former  commands should be deleted.
  459. */
  460. void FlushFIFO(void);
  461. /// Sleep several milliseconds
  462. /*
  463. The implementation of this function depends heavily
  464. on the microcontroller in use. The measurement need not to be
  465. very accurate. Only make sure, that the periode is not shorter, than
  466. the required one.
  467. */
  468. void SleepMs(unsigned short ms);
  469. /// Sleep several microseconds
  470. /*
  471. The implementation of this function depends heavily
  472. on the microcontroller in use. The measurement need not to be
  473. very accurate. Only make sure, that the periode is not shorter, than
  474. the required one.
  475. */
  476. void SleepUs(unsigned short us);
  477. ///////////////////////////////////////////////////////////////////////
  478. //      M I F A R E   M O D U L E   C O N F I G U R A T I O N
  479. ///////////////////////////////////////////////////////////////////////
  480. char Mf500PcdConfig(void)
  481. {
  482.    char status = MI_RESETERR;
  483.       
  484.    status = PcdReset();
  485.    if (status == MI_OK)
  486.    {
  487.      if ((status = PcdBasicRegisterConfiguration()) == MI_OK);
  488.      {
  489.         Mf500PcdWriteAttrib(); // write current modulation parameters
  490.         PcdRfReset(1); // Rf - reset and enable output driver    
  491.      }
  492.    }
  493.    return status;
  494. }
  495. ///////////////////////////////////////////////////////////////////////
  496. //          M I F A R E   R E M O T E   A N T E N N A
  497. //  Configuration of slave module
  498. ///////////////////////////////////////////////////////////////////////
  499. char Mf500ActiveAntennaSlaveConfig(void)
  500. {
  501.    char status = MI_OK;
  502.    FlushFIFO();    // empty FIFO
  503.    ResetInfo(MInfo);   
  504.    MSndBuffer[0] = 0x10; // addr low byte
  505.    MSndBuffer[1] = 0x00; // addr high byte
  506.    MSndBuffer[2] = 0x00; // Page
  507.    MSndBuffer[3] = 0x7B; // RegTxControl modsource 11,InvTx2,Tx2RFEn,TX1RFEn
  508.    MSndBuffer[4] = 0x3F; // RegCwConductance
  509.    MSndBuffer[5] = 0x3F; // RFU13
  510.    MSndBuffer[6] = 0x19; // RFU14
  511.    MSndBuffer[7] = 0x13; // RegModWidth     
  512.    MSndBuffer[8] = 0x00; // RFU16
  513.    MSndBuffer[9] = 0x00; // RFU17
  514.  
  515.    MSndBuffer[10] = 0x00; // Page
  516.    MSndBuffer[11] = 0x73; // RegRxControl1 
  517.    MSndBuffer[12] = 0x08; // RegDecoderControl
  518.    MSndBuffer[13] = 0x6c; // RegBitPhase     
  519.    MSndBuffer[14] = 0xFF; // RegRxThreshold  
  520.    MSndBuffer[15] = 0x00; // RegBPSKDemControl
  521.    MSndBuffer[16] = 0x00; // RegRxControl2   
  522.    MSndBuffer[17] = 0x00; // RegClockQControl
  523.    MSndBuffer[18] = 0x00; // Page
  524.    MSndBuffer[19] = 0x06; // RegRxWait
  525.    MSndBuffer[20] = 0x03; // RegChannelRedundancy
  526.    MSndBuffer[21] = 0x63; // RegCRCPresetLSB    
  527.    MSndBuffer[22] = 0x63; // RegCRCPresetMSB    
  528.    MSndBuffer[23] = 0x0;  // RFU25
  529.    MSndBuffer[24] = 0x04; // RegMfOutSelect enable mfout = manchester HT
  530.    MSndBuffer[25] = 0x00; // RFU27
  531.      
  532.    // PAGE 5      FIFO, Timer and IRQ-Pin Configuration
  533.    MSndBuffer[26] = 0x00; // Page
  534.    MSndBuffer[27] = 0x08; // RegFIFOLevel       
  535.    MSndBuffer[28] = 0x07; // RegTimerClock      
  536.    MSndBuffer[29] = 0x06; // RegTimerControl    
  537.    MSndBuffer[30] = 0x0A; // RegTimerReload     
  538.    MSndBuffer[31] = 0x02; // RegIRqPinConfig    
  539.    MSndBuffer[32] = 0x00; // RFU    
  540.    MSndBuffer[33] = 0x00; // RFU
  541.    MInfo.nBytesToSend   = 34;
  542.          
  543.    status = PcdSingleResponseCmd(PCD_WRITEE2,
  544.                    MSndBuffer,
  545.                    MRcvBuffer,
  546.                    &MInfo); // write e2
  547.    return status;
  548. }
  549. ///////////////////////////////////////////////////////////////////////
  550. //          M I F A R E   R E M O T E   A N T E N N A
  551. //  Configuration of master module
  552. ///////////////////////////////////////////////////////////////////////
  553. char Mf500ActiveAntennaMasterConfig(void)
  554. {
  555.    char status = MI_OK;
  556.    WriteRC(RegRxControl2,0x42);
  557.    WriteRC(RegTxControl,0x10);
  558.    WriteRC(RegBitPhase,0x11);
  559.    WriteRC(RegMfOutSelect,0x02);
  560.    return status;
  561. }     
  562.                   
  563. ///////////////////////////////////////////////////////////////////////
  564. //          M I F A R E    R E Q U E S T 
  565. ///////////////////////////////////////////////////////////////////////
  566. char Mf500PiccRequest(unsigned char req_code, // request code ALL = 0x52 
  567.                                            // or IDLE = 0x26 
  568.                    unsigned char *atq)     // answer to request
  569. {
  570.   return Mf500PiccCommonRequest(req_code,atq);
  571. }
  572. ///////////////////////////////////////////////////////////////////////
  573. //          M I F A R E   C O M M O N   R E Q U E S T 
  574. ///////////////////////////////////////////////////////////////////////
  575. char Mf500PiccCommonRequest(unsigned char req_code, 
  576.                             unsigned char *atq)
  577. {
  578.    char status = MI_OK;
  579.     //************* initialize ******************************
  580.    if ((status = Mf500PcdSetDefaultAttrib()) == MI_OK)
  581.    {
  582.    
  583.       PcdSetTmo(60);
  584.       
  585.       WriteRC(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enable
  586.       ClearBitMask(RegControl,0x08);      // disable crypto 1 unit   
  587.       WriteRC(RegBitFraming,0x07);        // set TxLastBits to 7 
  588.       
  589.       ResetInfo(MInfo);   
  590.       MSndBuffer[0] = req_code;
  591.       MInfo.nBytesToSend   = 1;   
  592.       MInfo.DisableDF = 1;
  593.       status = PcdSingleResponseCmd(PCD_TRANSCEIVE,
  594.                          MSndBuffer,
  595.                          MRcvBuffer,
  596.                          &MInfo);
  597.       if ((status == MI_OK) && (MInfo.nBitsReceived != 16)) // 2 bytes expected
  598.       {
  599.          status = MI_BITCOUNTERR;
  600.       } 
  601.       if ((status == MI_COLLERR) && (MInfo.nBitsReceived == 16)) //
  602.          status = MI_OK; // all received tag-types are combined to the 16 bit
  603.          
  604.       // in any case, copy received data to output - for debugging reasons
  605.       if (MInfo.nBytesReceived >= 2)
  606.       {
  607.          memcpy(atq,MRcvBuffer,2);      
  608.       }
  609.       else
  610.       {
  611.          if (MInfo.nBytesReceived == 1)
  612.             atq[0] = MRcvBuffer[0];
  613.          else
  614.             atq[0] = 0x00;
  615.          atq[1] = 0x00;
  616.       }
  617.    }
  618.    return status; 
  619. }
  620. ///////////////////////////////////////////////////////////////////////
  621. //          M I F A R E    A N T I C O L L I S I O N
  622. // for standard select
  623. ///////////////////////////////////////////////////////////////////////
  624. char Mf500PiccAnticoll (unsigned char bcnt,
  625.                      unsigned char *snr)
  626. {
  627.    return Mf500PiccCascAnticoll(0x93,bcnt,snr); // first cascade level
  628. }
  629. ///////////////////////////////////////////////////////////////////////
  630. //          M I F A R E    A N T I C O L L I S I O N
  631. // for extended serial numbers
  632. ///////////////////////////////////////////////////////////////////////
  633. char Mf500PiccCascAnticoll (unsigned char select_code,
  634.                          unsigned char bcnt,       
  635.                          unsigned char *snr)       
  636. {
  637.    char  status = MI_OK;
  638.    char  snr_in[4];         // copy of the input parameter snr
  639.    char  nbytes = 0;        // how many bytes received
  640.    char  nbits = 0;         // how many bits received
  641.    char  complete = 0;      // complete snr recived
  642.    short i        = 0;
  643.    char  byteOffset = 0;
  644.    unsigned char snr_crc;   // check byte calculation
  645.    unsigned char snr_check;
  646.    unsigned char dummyShift1;       // dummy byte for snr shift
  647.    unsigned char dummyShift2;       // dummy byte for snr shift   
  648.  
  649.    //************* Initialisierung ******************************
  650.    if ((status = Mf500PcdSetDefaultAttrib()) == MI_OK)
  651.    {
  652.       PcdSetTmo(106);
  653.       
  654.       memcpy(snr_in,snr,4);   
  655.       
  656.       WriteRC(RegDecoderControl,0x28); // ZeroAfterColl aktivieren   
  657.       ClearBitMask(RegControl,0x08);    // disable crypto 1 unit
  658.          
  659.       //************** Anticollision Loop ***************************
  660.       complete=0;
  661.       while (!complete && (status == MI_OK) )
  662.       {
  663.          // if there is a communication problem on the RF interface, bcnt 
  664.          // could be larger than 32 - folowing loops will be defective.
  665.          if (bcnt > 32)
  666.          {
  667.             status = MI_WRONG_PARAMETER_VALUE;
  668.             continue;
  669.          }
  670.          ResetInfo(MInfo);
  671.          MInfo.cmd = select_code;   // pass command flag to ISR        
  672.          MInfo.DisableDF = 1;
  673.          WriteRC(RegChannelRedundancy,0x03); // RxCRC and TxCRC disable, parity enable
  674.          nbits = bcnt % 8;   // remaining number of bits
  675.          if (nbits)
  676.          {
  677.             WriteRC(RegBitFraming,nbits << 4 | nbits); // TxLastBits/RxAlign auf nb_bi
  678.             nbytes = bcnt / 8 + 1;   
  679.             // number of bytes known
  680.    
  681.             // in order to solve an inconsistancy in the anticollision sequence
  682.             // (will be solved soon), the case of 7 bits has to be treated in a
  683.             // separate way
  684.             if (nbits == 7 )
  685.             {
  686.              MInfo.RxAlignWA = 1;
  687.                MInfo.nBitsReceived = 7; // set flag for 7 bit anticoll, which is evaluated
  688.                                         // in the ISRnBitsReceived        
  689.                WriteRC(RegBitFraming,nbits); // reset RxAlign to zero
  690.             }
  691.          } 
  692.          else
  693.          {
  694.             nbytes = bcnt / 8;
  695.          }
  696.   
  697.          MSndBuffer[0] = select_code;
  698.          MSndBuffer[1] = 0x20 + ((bcnt/8) << 4) + nbits; //number of bytes send
  699.                   
  700.          for (i = 0; i < nbytes; i++)  // Sende Buffer beschreiben
  701.          {
  702.             MSndBuffer[i + 2] = snr_in[i];
  703.          }
  704.          MInfo.nBytesToSend   = 2 + nbytes;    
  705.          status = PcdSingleResponseCmd(PCD_TRANSCEIVE,
  706.                             MSndBuffer,
  707.                             MRcvBuffer,
  708.                             &MInfo);
  709.           // in order to solve an inconsistancy in the anticollision sequence
  710.           // (will be solved soon), the case of 7 bits has to be treated in a
  711.           // separate way 
  712.          if (MInfo.RxAlignWA)
  713.          {
  714.             // reorder received bits
  715.             dummyShift1 = 0x00;
  716.             for (i = 0; i < MInfo.nBytesReceived; i++)
  717.             {
  718.                 dummyShift2 = MRcvBuffer[i];
  719.                 MRcvBuffer[i] = (dummyShift1 >> (i+1)) | (MRcvBuffer[i] << (7-i));
  720.                 dummyShift1 = dummyShift2;
  721.             }
  722.             MInfo.nBitsReceived -= MInfo.nBytesReceived; // subtract received parity bits
  723.             // recalculation of collision position
  724.             if ( MInfo.collPos ) MInfo.collPos += 7 - (MInfo.collPos + 6) / 9;
  725.          }
  726.          
  727.          if ( status == MI_OK || status == MI_COLLERR)    // no other occured
  728.          {
  729.             byteOffset = 0;
  730.             if ( nbits != 0 )           // last byte was not complete
  731.             {
  732.                snr_in[nbytes - 1] = snr_in[nbytes - 1] | MRcvBuffer[0];
  733.                byteOffset = 1;
  734.             }
  735.             for ( i =0; i < (4 - nbytes); i++)     
  736.             {
  737.                snr_in[nbytes + i] = MRcvBuffer[i + byteOffset];
  738.             }
  739.             // R e s p o n s e   P r o c e s s i n g   
  740.             if ( MInfo.nBitsReceived != (40 - bcnt) ) // not 5 bytes answered
  741.             {
  742.                status = MI_BITCOUNTERR;
  743.             } 
  744.             else 
  745.             {
  746.                if (status != MI_COLLERR ) // no error and no collision
  747.                {
  748.                   // SerCh check
  749.                   snr_crc = snr_in[0] ^ snr_in[1] ^ snr_in[2] ^ snr_in[3];
  750.                   snr_check = MRcvBuffer[MInfo.nBytesReceived - 1];
  751.                   if (snr_crc != snr_check)
  752.                   {
  753.                      status = MI_SERNRERR;
  754.                   } 
  755.                   else   
  756.                   {
  757.                      complete = 1;
  758.                   }
  759.                }
  760.                else                   // collision occured
  761.                {
  762.                   bcnt = bcnt + MInfo.collPos - nbits;
  763.                   status = MI_OK;
  764.                }
  765.             }
  766.         }
  767.       }
  768.    }
  769.    // transfer snr_in to snr - even in case of an error - for 
  770.    // debugging reasons
  771.    memcpy(snr,snr_in,4);
  772.    //----------------------Einstellungen aus Initialisierung ruecksetzen 
  773.    ClearBitMask(RegDecoderControl,0x20); // ZeroAfterColl disable
  774.    
  775.    return status;  
  776. }
  777. ///////////////////////////////////////////////////////////////////////
  778. //          M I F A R E    S E L E C T 
  779. // for std. select
  780. ///////////////////////////////////////////////////////////////////////
  781. char Mf500PiccSelect(unsigned char *snr, 
  782.                   unsigned char *sak)
  783. {
  784.    return Mf500PiccCascSelect(0x93,snr,sak); // first cascade level
  785. }
  786. ///////////////////////////////////////////////////////////////////////
  787. //          M I F A R E    C A S C A D E D   S E L E C T 
  788. //  for extended serial number
  789. ///////////////////////////////////////////////////////////////////////
  790. char Mf500PiccCascSelect(unsigned char select_code, 
  791.                         unsigned char *snr,
  792.                         unsigned char *sak)
  793. {
  794.    char   status = MI_OK; 
  795.    if ((status = Mf500PcdSetDefaultAttrib()) == MI_OK)
  796.    {
  797.       PcdSetTmo(106);
  798.     
  799.       WriteRC(RegChannelRedundancy,0x0F); // RxCRC,TxCRC, Parity enable
  800.       ClearBitMask(RegControl,0x08);    // disable crypto 1 unit
  801.    
  802.       //************* Cmd Sequence ********************************** 
  803.       ResetInfo(MInfo);   
  804.       MSndBuffer[0] = select_code;
  805.       MSndBuffer[1] = 0x70;         // number of bytes send
  806.       
  807.       memcpy(MSndBuffer + 2,snr,4);
  808.       MSndBuffer[6] = MSndBuffer[2] 
  809.                       ^ MSndBuffer[3] 
  810.                       ^ MSndBuffer[4] 
  811.                       ^ MSndBuffer[5];
  812.       MInfo.nBytesToSend   = 7;
  813.       MInfo.DisableDF = 1;
  814.       status = PcdSingleResponseCmd(PCD_TRANSCEIVE,
  815.                           MSndBuffer,
  816.                           MRcvBuffer,
  817.                           &MInfo);
  818.    
  819.       *sak = 0;   
  820.       if (status == MI_OK)    // no timeout occured
  821.       {
  822.          if (MInfo.nBitsReceived != 8)    // last byte is not complete
  823.          {
  824.             status = MI_BITCOUNTERR;
  825.          }
  826.          else
  827.          {
  828.             memcpy(MLastSelectedSnr,snr,4);            
  829.          }
  830.       }
  831.       // copy received data in any case - for debugging reasons
  832.       *sak = MRcvBuffer[0];
  833.    }
  834.    return status;
  835. }
  836. ///////////////////////////////////////////////////////////////////////
  837. //       M I F A R E   P I C C   A C T I V A T I O N    S E Q E N C E
  838. ///////////////////////////////////////////////////////////////////////
  839. char Mf500PiccActivateIdle(unsigned char br,
  840.                            unsigned char *atq, 
  841.                            unsigned char *sak, 
  842.                            unsigned char *uid, 
  843.                            unsigned char *uid_len)
  844. {
  845.   unsigned char cascade_level;
  846.   unsigned char sel_code;
  847.   unsigned char uid_index;
  848.   signed char status;
  849.   unsigned char cmdASEL;
  850.   *uid_len      = 0;
  851.   //call activation with def. divs
  852.   status = Mf500PcdSetDefaultAttrib();
  853.   if (status == MI_OK)
  854.   {
  855.      status = Mf500PiccCommonRequest(PICC_REQIDL,atq);
  856.   }
  857.   if (status == MI_OK)
  858.   {
  859.      if((atq[0] & 0x1F) == 0x00) // check lower 5 bits, for tag-type
  860.                                  // all tags within this 5 bits have to
  861.                                  // provide a bitwise anticollision
  862.      {
  863.         status = MI_NOBITWISEANTICOLL;
  864.      }
  865.   }
  866.   if (status == MI_OK)
  867.   {
  868.       //Get UID in 1 - 3 levels (standard, [double], [triple] )
  869.       //-------
  870.       switch(br)
  871.       {
  872.          case 0: cmdASEL = PICC_ANTICOLL1; break;
  873.          case 1: cmdASEL = PICC_ANTICOLL11; break;
  874.          case 2: cmdASEL = PICC_ANTICOLL12; break;
  875.          case 3: cmdASEL = PICC_ANTICOLL13; break;
  876.          default:
  877.               status = MI_BAUDRATE_NOT_SUPPORTED; break;
  878.       }
  879.   }
  880.   if (status == MI_OK)
  881.   {
  882.       cascade_level = 0;
  883.       uid_index     = 0;
  884.       do
  885.       {
  886.         //Select code depends on cascade level
  887.         sel_code   = cmdASEL + (2 * cascade_level);
  888.         cmdASEL = PICC_ANTICOLL1; // reset anticollistion level for calculation
  889.         //ANTICOLLISION
  890.         status = Mf500PiccCascAnticoll(sel_code, 0, &uid[uid_index]);
  891.         //SELECT
  892.         if (status == MI_OK)
  893.         {
  894.            status = Mf500PiccCascSelect(sel_code, &uid[uid_index], sak);
  895.            if (status == MI_OK)
  896.            {
  897.               cascade_level++;
  898.               //we differ cascaded and uncascaded UIDs
  899.               if (*sak & 0x04) // if cascaded, bit 2 is set in answer to select
  900.               {
  901.                  //this UID is cascaded, remove the cascaded tag that is
  902.                  //0x88 as first of the 4 byte received
  903.                  memmove(&uid[uid_index], &uid[uid_index + 1], 3);
  904.                  uid_index += 3;
  905.                  *uid_len += 3;
  906.               }
  907.               else
  908.               {
  909.                  //this UID is not cascaded -> the length is 4 bytes
  910.                  uid_index += 4;
  911.                  *uid_len += 4;
  912.               }
  913.            }
  914.         }
  915.       }
  916.       while((status == MI_OK)        // error status
  917.             && (*sak & 0x04)         // no further cascade level
  918.             && (cascade_level < 3)); // highest cascade level is reached
  919.    }
  920.    if (status == MI_OK)
  921.    {
  922.       //Exit function, if cascade level is triple and sak indicates another
  923.       //cascase level.
  924.       if ((cascade_level == 3) && (*sak & 0x04))
  925.       {
  926.          *uid_len = 0;
  927.          status = MI_CASCLEVEX;
  928.       }
  929.       Mf500PcdSetAttrib(br,br);
  930.    }
  931.    return (status);
  932. }
  933. ///////////////////////////////////////////////////////////////////////
  934. //       M I F A R E   P I C C   A C T I V A T I O N    S E Q E N C E
  935. ///////////////////////////////////////////////////////////////////////
  936. char Mf500PiccActivateWakeup(unsigned char br,
  937.                              unsigned char *atq, 
  938.                              unsigned char *sak,
  939.                              unsigned char *uid, 
  940.                              unsigned char uid_len)
  941. {
  942.    unsigned char cascade_level;
  943.    unsigned char uid_index;
  944.    unsigned char tmpuid[4];
  945.    unsigned char sel_code;
  946.    unsigned char cmdASEL;
  947.    signed char   status;
  948.    //call activation with def. divs
  949.    status = Mf500PcdSetDefaultAttrib();
  950.    if (status == MI_OK)
  951.    {
  952.       status = Mf500PiccCommonRequest(PICC_REQALL,atq);
  953.    }
  954.    if (status == MI_OK)
  955.    {
  956.       if ((atq[0] & 0x1F) == 0x00) // check lower 5 bits, for tag-type
  957.                                    // all tags within this 5 bits have to
  958.                                    // provide a bitwise anticollision
  959.       {
  960.          status = MI_NOBITWISEANTICOLL;
  961.       }
  962.    }
  963.    if (status == MI_OK)
  964.    {
  965.       //Get UID in 1 - 3 levels (standard, [double], [triple] )
  966.       //-------
  967.       switch(br)
  968.       {
  969.          case 0: cmdASEL = PICC_ANTICOLL1; break;
  970.          case 1: cmdASEL = PICC_ANTICOLL11; break;
  971.          case 2: cmdASEL = PICC_ANTICOLL12; break;
  972.          case 3: cmdASEL = PICC_ANTICOLL13; break;
  973.          default:
  974.               status = MI_BAUDRATE_NOT_SUPPORTED; break;
  975.       }
  976.    }
  977.    if (status == MI_OK)
  978.    {
  979.       //Select UID in up to 3 cascade levels (standard, [double], [triple] )
  980.       //------------------------------------
  981.       cascade_level = 0;
  982.       uid_index     = 0;
  983.       tmpuid[0] = 0x88;     //first byte of cascaded UIDs is 0x88 (cascaded tag)
  984.       do
  985.       {
  986.         sel_code   = cmdASEL + (2 * cascade_level);
  987.         cmdASEL = PICC_ANTICOLL1; // reset anticollistion level for calculation
  988.         //get the next UID part if we need to cascade
  989.         if((uid_len - uid_index) > 4)
  990.         {
  991.           //ok, we need to cascade the UID
  992.           memcpy(&tmpuid[1], &uid[uid_index], 3);
  993.           uid_index += 3;
  994.         }
  995.         else
  996.         {
  997.           //ah, how nice. no need to cascade
  998.           memcpy(tmpuid, &uid[uid_index], 4);
  999.           uid_index += 4;
  1000.         }
  1001.         status = Mf500PiccCascSelect(sel_code, tmpuid, sak);
  1002.         if(status == MI_OK)
  1003.         {
  1004.           cascade_level++;
  1005.         }
  1006.       }
  1007.       while((status == MI_OK )    // error occured
  1008.             && (*sak & 0x04)       // no further cascade level
  1009.             && ((uid_index + 1) < uid_len) // all bytes of snr sent
  1010.             && (cascade_level < 3)); // highest cascade level reached
  1011.    }
  1012.    if ( status == MI_OK) 
  1013.    {
  1014.       //Exit function, if UID length is not of expected length
  1015.       if ((uid_index) != uid_len)
  1016.       {
  1017.          status =  MI_SERNRERR ;
  1018.       }
  1019.    }
  1020.    if (status == MI_OK)
  1021.    {
  1022.       //Exit function, if cascade level is triple and sak indicates another
  1023.       //cascase level.
  1024.       if ((cascade_level == 3) && (*sak & 0x04))
  1025.       {
  1026.          status = MI_SERNRERR;
  1027.       }
  1028.    }
  1029.    return status;
  1030. }
  1031. ///////////////////////////////////////////////////////////////////////
  1032. //          M I F A R E      A U T H E N T I C A T I O N
  1033. //   calling compatible version    
  1034. ///////////////////////////////////////////////////////////////////////
  1035. char Mf500PiccAuth(unsigned char key_type,    // PICC_AUTHENT1A or PICC_AUTHENT1B
  1036.                    unsigned char key_addr,    // key address in reader storage
  1037.                    unsigned char block)       // block number which should be 
  1038.                                               // authenticated
  1039. {
  1040.    char            status = MI_OK;
  1041.    status = Mf500PiccAuthE2(  key_type,
  1042.                               MLastSelectedSnr,
  1043.                               key_addr,
  1044.                               block);
  1045.    return status;
  1046. }
  1047. ///////////////////////////////////////////////////////////////////////
  1048. //                  A U T H E N T I C A T I O N   
  1049. //             W I T H   K E Y S   F R O M   E 2 P R O M
  1050. ///////////////////////////////////////////////////////////////////////
  1051. char Mf500PiccAuthE2(   unsigned char auth_mode,   // PICC_AUTHENT1A or PICC_AUTHENT1B
  1052.                      unsigned char *snr,        // 4 bytes card serial number
  1053.                      unsigned char key_sector,  // 0 <= key_sector <= 15                     
  1054.                      unsigned char block)      //  0 <= block <= 256
  1055. {
  1056.    char status = MI_OK;
  1057.    // eeprom address calculation
  1058.    // 0x80 ... offset
  1059.    // key_sector ... sector
  1060.    // 0x18 ... 2 * 12 = 24 = 0x18
  1061.    unsigned short e2addr = 0x80 + key_sector * 0x18;
  1062.    unsigned char *e2addrbuf = (unsigned char*)&e2addr;
  1063.    
  1064.    PcdSetTmo(106);
  1065.    if (auth_mode == PICC_AUTHENT1B)
  1066.       e2addr += 12; // key B offset   
  1067.    FlushFIFO();    // empty FIFO
  1068.    ResetInfo(MInfo);
  1069.    memcpy(MSndBuffer,e2addrbuf,2); // write low and high byte of address
  1070.    MInfo.nBytesToSend   = 2;
  1071.     // write load command
  1072.    if ((status=PcdSingleResponseCmd(PCD_LOADKEYE2,MSndBuffer,MRcvBuffer,&MInfo)) == MI_OK)
  1073.    {      
  1074.       // execute authentication
  1075.       status = Mf500PiccAuthState(auth_mode,snr,block);  
  1076.    }
  1077.    return status;
  1078. }                        
  1079. ///////////////////////////////////////////////////////////////////////
  1080. //                      C O D E   K E Y S  
  1081. ///////////////////////////////////////////////////////////////////////
  1082. char Mf500HostCodeKey(  unsigned char *uncoded, // 6 bytes key value uncoded
  1083.                      unsigned char *coded)   // 12 bytes key value coded
  1084. {
  1085.    char status = MI_OK;
  1086.    unsigned char cnt = 0;
  1087.    unsigned char ln  = 0;     // low nibble
  1088.    unsigned char hn  = 0;     // high nibble
  1089.    
  1090.    for (cnt = 0; cnt < 6; cnt++)
  1091.    {
  1092.       ln = uncoded[cnt] & 0x0F;
  1093.       hn = uncoded[cnt] >> 4;
  1094.       coded[cnt * 2 + 1]     =  (~ln << 4) | ln;
  1095.       coded[cnt * 2 ] =  (~hn << 4) | hn;
  1096.    }
  1097.    return MI_OK;
  1098. }
  1099. ///////////////////////////////////////////////////////////////////////
  1100. //                  A U T H E N T I C A T I O N   
  1101. //             W I T H   P R O V I D E D   K E Y S
  1102. ///////////////////////////////////////////////////////////////////////
  1103. char Mf500PiccAuthKey(  unsigned char auth_mode,
  1104.                      unsigned char *snr,       
  1105.                      unsigned char *keys,      
  1106.                      unsigned char block)      
  1107. {
  1108.    char status     = MI_OK;
  1109.    unsigned char i = 0;
  1110.    
  1111.    PcdSetTmo(106);
  1112.    FlushFIFO();    // empty FIFO
  1113.    ResetInfo(MInfo);
  1114.    memcpy(MSndBuffer,keys,12);                  // write 12 bytes of the key
  1115.    MInfo.nBytesToSend = 12;
  1116.     // write load command
  1117.    if ((status=PcdSingleResponseCmd(PCD_LOADKEY,MSndBuffer,MRcvBuffer,&MInfo)) == MI_OK)
  1118.    {      
  1119.       // execute authentication
  1120.       status = Mf500PiccAuthState(auth_mode,snr,block); 
  1121.    }
  1122.    return status;
  1123. }
  1124. ///////////////////////////////////////////////////////////////////////
  1125. //        S T O R E   K E Y S   I N   E E P R O M
  1126. ///////////////////////////////////////////////////////////////////////
  1127. char Mf500PcdLoadKeyE2(unsigned char key_type,
  1128.                        unsigned char sector,
  1129.                        unsigned char *uncoded_keys)
  1130. {
  1131.    // eeprom address calculation
  1132.    // 0x80 ... offset
  1133.    // key_sector ... sector
  1134.    // 0x18 ... 2 * 12 = 24 = 0x18
  1135.    signed char status = MI_OK;
  1136.    unsigned short e2addr = 0x80 + sector * 0x18;
  1137.    unsigned char coded_keys[12];
  1138.    if (key_type == PICC_AUTHENT1B)
  1139.       e2addr += 12; // key B offset   
  1140.    if ((status = Mf500HostCodeKey(uncoded_keys,coded_keys)) == MI_OK)
  1141.       status = PcdWriteE2(  e2addr,12,coded_keys);
  1142.    return status;
  1143. }                       
  1144.                           
  1145. ///////////////////////////////////////////////////////////////////////
  1146. //        A U T H E N T I C A T I O N   S T A T E S
  1147. ///////////////////////////////////////////////////////////////////////
  1148. char Mf500PiccAuthState(   unsigned char auth_mode,
  1149.                         unsigned char *snr,
  1150.                         unsigned char block)
  1151. {
  1152.    char status = MI_OK;
  1153.    unsigned char i = 0;
  1154.    
  1155.    WriteRC(RegChannelRedundancy,0x07); // RxCRC disable,TxCRC, Parity enable
  1156.    PcdSetTmo(150);
  1157.    MSndBuffer[0] = auth_mode;        // write authentication command
  1158.    MSndBuffer[1] = block;    // write block number for authentication
  1159.    memcpy(MSndBuffer + 2,snr,4); // write 4 bytes card serial number 
  1160.    ResetInfo(MInfo);
  1161.    MInfo.nBytesToSend = 6;
  1162.    if ((status = PcdSingleResponseCmd(PCD_AUTHENT1,
  1163.                             MSndBuffer,
  1164.                             MRcvBuffer,
  1165.                             &MInfo)) == MI_OK)
  1166.    {
  1167.       if (ReadRC(RegSecondaryStatus) & 0x07) // RxLastBits mu