1 // *******************************************************************
    2 //   NFC Library for Custom DPA Handlers, chip is ST25DV04K          *
    3 // *******************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: NFC.c,v $
    7 // Version: $Revision: 1.11 $
    8 // Date:    $Date: 2021/08/18 20:43:06 $
    9 //
   10 // Revision history:
   11 //   2021/08/18  Release for DPA 4.16
   12 //   2020/01/02  Release for DPA 4.11
   13 //
   14 // *********************************************************************
   15 
   16 #ifndef __I2C_NFC_LIB__
   17 #define __I2C_NFC_LIB__
   18 
   19 //############################################################################################
   20 
   21 // Define to avoid deadlock when the NFC chip is not connect to the I2C bus. Pull-up resistors are required anyway!
   22 // #define NFC_UPDATE_IGNORE_IF_MISSING
   23 
   24 // I2C chips addresses
   25 #define I2C_ADDRESS_NFC             0b1010.0110
   26 #define I2C_ADDRESS_NFC_SYS         0b1010.1110
   27 
   28 // NFC chip ID
   29 #ifndef NFC_IC_REF
   30 #define NFC_IC_REF  0x24  // = ST25DV04K
   31 #endif
   32 
   33 // NFC routines
   34 void NfcUpdateIQRFcode();
   35 void NfcConfigure();
   36 
   37 // NFC low level routines
   38 uns8 NfcReadByte( uns16 addr, uns8 device );
   39 void NfcSysWriteByte( uns8 addrLow, uns8 data );
   40 // Reads bytes to bufferRF
   41 void NfcReadBytes( uns16 addr, uns8 length, uns8 device );
   42 // Writes bytes from bufferRF
   43 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device );
   44 
   45 #ifndef USE_FSRx
   46 void setINDF1inc( uns8 data );
   47 #else
   48 #define setINDF1inc( data ) do { *FSR1++ = data; } while(0)
   49 #endif
   50 
   51 #if DPA_VERSION_MASTER >= 0x0416
   52 #define _i2c_start        _DpaApiI2Cstart
   53 #define _i2c_stop         _DpaApiI2Cstop
   54 #define _i2c_read         _DpaApiI2Cread
   55 #define _i2c_write        _DpaApiI2Cwrite
   56 #define _i2c_waitForIdle  _DpaApiI2CwaitForIdle
   57 #else
   58 #define _i2c_start        i2c_start      
   59 #define _i2c_stop         i2c_stop       
   60 #define _i2c_read         i2c_read       
   61 #define _i2c_write        i2c_write      
   62 #define _i2c_waitForIdle  i2c_waitForIdle
   63 
   64 #ifndef __I2C_MASTER__
   65 #define __INCLUDE__I2C_MASTER__
   66 #include "lib/I2Cmaster.c"
   67 #endif
   68 
   69 #endif
   70 
   71 //############################################################################################
   72 #else
   73 
   74 #pragma library 1               // Compile only used methods
   75 
   76 #ifdef __INCLUDE__I2C_MASTER__
   77 #include "lib/I2Cmaster.c"
   78 #endif
   79 
   80 #ifndef USE_FSRx
   81 // ############################################################################################
   82 void setINDF1inc( uns8 data @ W )
   83 // ############################################################################################
   84 {
   85   setINDF1( data );
   86   FSR1++;
   87 }
   88 #endif
   89 
   90 // ############################################################################################
   91 uns8 NfcCfgByte( uns8 addr @ W )
   92 // ############################################################################################
   93 {
   94   skip( addr );
   95 #pragma computedGoto 1
   96   return 0xC6; // GPO-generuje impuls pokud dojde k RF zapisu do EEPROM a RF command EOF to response EOF.
   97   return 0x00; // IT_TIME-delka pulsu GPO 301us - (0x00 * 37.5us)
   98   return 0x01; // EH_MODE-energy harvesting 0x01 na vyzadani
   99   return 0x00; // RF_MNGT-RF komunikace povolena
  100   return 0x0C; // RFA1SS-Area1 bez hesla a povoleno pouze RF cteni, RF zapis je zakazany (tam prave ulozim IQRF code)
  101   return 0x03; // ENDA1-Area1 adresa 0 až 127B
  102   return 0x06; // RFA2SS-Area2 RF cteni bez hesla a RF zapis s heslem RF_PWD1 (zde je mozne zapsat pouze pomoci RF hesla)
  103   return 0x07; // ENDA2-Area2 adresa 128 až 255B
  104   return 0x00; // RFA3SS-Area3 RF cteni/RF zapis bez hesla
  105   return 0x0B; // ENDA3-Area3 adresa 256 až 383B, zbytek je Area4 384 až 512B
  106   return 0x00; // RFA4SS-Area4 RF cteni/RF zapis bez hesla
  107   return 0x00; // I2CSS-I2C pristup do pameti bez hesla
  108 #pragma computedGoto 0
  109 }
  110 
  111 //############################################################################################
  112 void NfcConfigure()
  113 //############################################################################################
  114 {
  115 #ifdef NFC_UPDATE_IGNORE_IF_MISSING
  116   if ( NfcReadByte( 0x0017 /* IC_REF */, I2C_ADDRESS_NFC_SYS ) != NFC_IC_REF )
  117     return;
  118 #endif
  119 
  120   // Enter I2C password (8x zero)
  121   clearBufferRF();
  122   // I2C password validation code between 2 repeated passwords
  123   bufferRF[8] = 0x09;
  124   // Write password (password+0x90+password)
  125   NfcWriteBytes( 0x0900, 8 + 1 + 8, I2C_ADDRESS_NFC_SYS );
  126 
  127   // Check the password was correct (I2C_SSO_Dyn register)
  128   if ( NfcReadByte( 0x2004, I2C_ADDRESS_NFC ) != 1 )
  129   {
  130 _NfcError:
  131     // No, pulse both LEDs
  132     pulsingLEDR();
  133     pulsingLEDG();
  134     for ( ;; );
  135   }
  136 
  137   // Now configure NFC
  138   uns8 addr = 0; // System configuration memory address
  139   do {
  140     uns8 cfgByte = NfcCfgByte( addr );
  141     NfcSysWriteByte( addr, cfgByte );
  142     // Check the configuration was written
  143     if ( NfcReadByte( addr, I2C_ADDRESS_NFC_SYS ) != cfgByte )
  144       goto _NfcError;
  145   } while ( ++addr != ( 0x0B /* I2CSS-I2C register */ + 1 ) );
  146 }
  147 
  148 //############################################################################################
  149 void NfcUpdateIQRFcode()
  150 //############################################################################################
  151 {
  152 #ifdef NFC_UPDATE_IGNORE_IF_MISSING
  153   if ( NfcReadByte( 0x0017 /* IC_REF */, I2C_ADDRESS_NFC_SYS ) != NFC_IC_REF )
  154     return;
  155 #endif
  156 
  157   // Check MID for the valid IQRF Code at the NFC EEPROM, read user area from address 1 where the reversed (Big Endian) MID is supposed to be
  158   uns8 addr = 1 + sizeof( ModuleInfo.MID );
  159   // My MID address to the FSR1
  160 #if &ModuleInfo.MID[0] == &bufferINFO[0]
  161   moduleInfo();
  162   setFSR1( _FSR_INFO );
  163 #else
  164 #error  Cannot optimize FSR to MID address
  165 #endif
  166   do
  167   {
  168     // MID matches?
  169     if ( NfcReadByte( --addr, I2C_ADDRESS_NFC ) != *FSR1 )
  170     {
  171       // No, configure NFC and write IQRF Code
  172 
  173       // Enter I2C password (8x zero)
  174       clearBufferRF();
  175       // I2C password validation code between 2 repeated passwords
  176       bufferRF[8] = 0x09;
  177       // Write password (password+0x90+password)
  178       NfcWriteBytes( 0x0900, 8 + 1 + 8, I2C_ADDRESS_NFC_SYS );
  179 
  180       // Check the password was correct (I2C_SSO_Dyn register)
  181       if ( NfcReadByte( 0x2004, I2C_ADDRESS_NFC ) != 1 )
  182       {
  183 _NfcError:
  184         // No, pulse both LEDs
  185         pulsingLEDR();
  186         pulsingLEDG();
  187         for ( ;; );
  188       }
  189 
  190       // Now configure NFC
  191       addr = 0; // System configuration memory address
  192       do {
  193         uns8 cfgByte = NfcCfgByte( addr );
  194         NfcSysWriteByte( addr, cfgByte );
  195         // Check the configuration was written
  196         if ( NfcReadByte( addr, I2C_ADDRESS_NFC_SYS ) != cfgByte )
  197           goto _NfcError;
  198       } while ( ++addr != ( 0x0B /* I2CSS-I2C register */ + 1 ) );
  199 
  200       // Writes IQRF Code to the EEPROM to the address 0, prepare it at bufferRF
  201 
  202       // Prepare MID reversed, i.e. MSB first
  203       setFSR01( _FSR_INFO, _FSR_RF );
  204       FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID );
  205       // Example: 0x15 ,0x81,0x11,0x2f,0x0e
  206       setINDF1inc( 0x15 ); // Nop tag + MID tag
  207       uns8 loop = sizeof( ModuleInfo.MID );
  208       do {
  209         setINDF1inc( *--FSR0 );
  210       } while ( --loop != 0 );
  211 
  212       // Prepare IBK
  213       memoryOffsetFrom |= 16;
  214       moduleInfo(); // FSR0 = BUFFER_INFO = IBK
  215       setFSR01( _FSR_INFO, _FSR_RF );
  216       FSR1 += 1 + sizeof( ModuleInfo.MID );
  217       // Example: 0x25 ,0xb6,0x03,0x3e,0x8f,0xb0,0x8c,0x9b,0xd1,0x74,0xa1,0x9f,0xc0,0x91,0xb8,0xb9,0xbf
  218       setINDF1inc( 0x25 ); // Nop tag + IBK tag
  219       loop = 16; // IBK size
  220       do {
  221         setINDF1inc( *FSR0++ );
  222       } while ( --loop != 0 );
  223 
  224       // Prepare HWPID
  225       // Example: 0x35 ,0x50,0x02
  226       setINDF1inc( 0x35 ); // Nop tag + HWPID tag
  227       setINDF1inc( _HWPID_ >> 8 );
  228       setINDF1inc( _HWPID_ & 0xFF );
  229 
  230       // End tag
  231       setINDF1inc( 0 );
  232 
  233       // Write prepared IQRF Code to NFC EEPROM at address 0
  234       NfcWriteBytes( 0, 1 + sizeof( ModuleInfo.MID ) + 1 + 16 + 1 + sizeof( _HWPID ) + 1, I2C_ADDRESS_NFC );
  235 
  236       return;
  237     }
  238 
  239     // Note: *FSR1++ cannot be used in the "if" condition above, because CC5X cannot generate code
  240     FSR1++;
  241   } while ( addr != 1 );
  242 }
  243 
  244 //############################################################################################
  245 void NfcWaitIsReady()
  246 //############################################################################################
  247 {
  248   _i2c_stop();
  249   do
  250   {
  251     _i2c_start( I2C_ADDRESS_NFC );
  252     _i2c_waitForIdle();
  253   } while ( ACKSTAT );
  254   _i2c_stop();
  255 }
  256 
  257 //############################################################################################
  258 void NfcSysWriteByte( uns8 addrLow, uns8 data )
  259 //############################################################################################
  260 {
  261   _i2c_start( I2C_ADDRESS_NFC_SYS );
  262   _i2c_write( 0 );
  263   _i2c_write( addrLow );
  264   _i2c_write( data );
  265   NfcWaitIsReady();
  266 }
  267 
  268 //############################################################################################
  269 uns8 NfcReadByte( uns16 addr, uns8 device )
  270 //############################################################################################
  271 {
  272   _i2c_start( device );
  273   _i2c_write( addr.high8 );
  274   _i2c_write( addr.low8 );
  275   _i2c_start( device | 1 );
  276   uns8 data = _i2c_read( FALSE );
  277   _i2c_stop();
  278   return data;
  279 }
  280 
  281 //############################################################################################
  282 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device @ W )
  283 //############################################################################################
  284 {
  285   _i2c_start( device );
  286   _i2c_write( addr.high8 );
  287   _i2c_write( addr.low8 );
  288   setFSR1( _FSR_RF );
  289   do {
  290     _i2c_write( *FSR1++ );
  291   } while ( --length != 0 );
  292   NfcWaitIsReady();
  293 }
  294 
  295 //############################################################################################
  296 void NfcReadBytes( uns16 addr, uns8 length, uns8 device )
  297 //############################################################################################
  298 {
  299   _i2c_start( device );
  300   _i2c_write( addr.high8 );
  301   _i2c_write( addr.low8 );
  302   _i2c_start( device | 1 );
  303   setFSR1( _FSR_RF );
  304   do {
  305     setINDF1inc( _i2c_read( length != 1 ) );
  306   } while ( --length != 0 );
  307   _i2c_stop();
  308 }
  309 
  310 #pragma library 0
  311 
  312 #endif
  313 //############################################################################################