1 // *******************************************************************
    2 //   NFC Library for Custom DPA Handlers, chip is ST25DV04K          *
    3 // *******************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: NFC.c,v $
    7 // Version: $Revision: 1.3 $
    8 // Date:    $Date: 2020/03/20 12:07:39 $
    9 //
   10 // Revision history:
   11 //   2020/01/02  Release for DPA 4.11
   12 //
   13 // *********************************************************************
   14 
   15 #ifndef __I2C_NFC_LIB__
   16 #define __I2C_NFC_LIB__
   17 
   18 //############################################################################################
   19 
   20 // Define to avoid deadlock when the NFC chip is not connect to the I2C bus. Pull-up resistors are required anyway!
   21 // #define NFC_UPDATE_IGNORE_IF_MISSING
   22 
   23 // I2C chips addresses
   24 #define I2C_ADDRESS_NFC             0b10100110
   25 #define I2C_ADDRESS_NFC_SYS         0b10101110
   26 
   27 // NFC chip ID
   28 #ifndef NFC_IC_REF
   29 #define NFC_IC_REF  0x24  // = ST25DV04K
   30 #endif
   31 
   32 // NFC routines
   33 void NfcUpdateIQRFcode();
   34 
   35 // NFC low level routines
   36 uns8 NfcReadByte( uns16 addr, uns8 device );
   37 void NfcSysWriteByte( uns8 addrLow, uns8 data );
   38 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device );
   39 uns8 NfcCfgByte( uns8 addr );
   40 void setINDF1inc( uns8 data );
   41 
   42 //############################################################################################
   43 #else
   44 
   45 #pragma library 1               // Compile only used methods
   46 
   47 //############################################################################################
   48 void NfcUpdateIQRFcode()
   49 //############################################################################################
   50 {
   51 #ifdef NFC_UPDATE_IGNORE_IF_MISSING
   52   if ( NfcReadByte( 0x0017 /* IC_REF */, I2C_ADDRESS_NFC_SYS ) != NFC_IC_REF )
   53     return;
   54 #endif
   55 
   56   // 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
   57   uns8 addr = 1 + sizeof( ModuleInfo.MID );
   58   // My MID address to the FSR1
   59 #if &ModuleInfo.MID[0] == &bufferINFO[0]
   60   moduleInfo();
   61   setFSR1( _FSR_INFO );
   62 #else
   63 #error  Cannot optimize FSR to MID address
   64 #endif
   65   do
   66   {
   67     // MID matches?
   68     if ( NfcReadByte( --addr, I2C_ADDRESS_NFC ) != *FSR1 )
   69     {
   70       // No, configure NFC and write IQRF Code
   71 
   72       // Enter I2C password (8x zero)
   73       clearBufferRF();
   74       // I2C password validation code between 2 repeated passwords
   75       bufferRF[8] = 0x09;
   76       // Write password (password+0x90+password)
   77       NfcWriteBytes( 0x0900, 8 + 1 + 8, I2C_ADDRESS_NFC_SYS );
   78 
   79       // Check the password was correct (I2C_SSO_Dyn register)
   80       if ( NfcReadByte( 0x2004, I2C_ADDRESS_NFC ) != 1 )
   81       {
   82 _NfcError:
   83         // No, pulse both LEDs
   84         pulsingLEDR();
   85         pulsingLEDG();
   86         for ( ;; );
   87       }
   88 
   89       // Now configure NFC
   90       addr = 0 /* GPO register */;
   91       do {
   92         uns8 cfgByte = NfcCfgByte( addr );
   93         NfcSysWriteByte( addr, cfgByte );
   94         // Check the configuration was written
   95         if ( NfcReadByte( addr, I2C_ADDRESS_NFC_SYS ) != cfgByte )
   96           goto _NfcError;
   97       } while ( ++addr != ( 0x0B /* I2CSS-I2C register */ + 1 ) );
   98 
   99       // Writes IQRF Code to the EEPROM to the address 0, prepare it at bufferRF
  100 
  101       // Prepare MID reversed, i.e. MSB first
  102       setFSR01( _FSR_INFO, _FSR_RF );
  103       FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID );
  104       // Example: 0x15 ,0x81,0x11,0x2f,0x0e
  105       setINDF1inc( 0x15 ); // Nop tag + MID tag
  106       uns8 loop = sizeof( ModuleInfo.MID );
  107       do {
  108         setINDF1inc( *--FSR0 );
  109       } while ( --loop != 0 );
  110 
  111       // Prepare IBK
  112       memoryOffsetFrom |= 16;
  113       moduleInfo(); // FSR0 = BUFFER_INFO = IBK
  114       setFSR01( _FSR_INFO, _FSR_RF );
  115       FSR1 += 1 + sizeof( ModuleInfo.MID );
  116       // Example: 0x25 ,0xb6,0x03,0x3e,0x8f,0xb0,0x8c,0x9b,0xd1,0x74,0xa1,0x9f,0xc0,0x91,0xb8,0xb9,0xbf
  117       setINDF1inc( 0x25 ); // Nop tag + IBK tag
  118       loop = 16; // IBK size
  119       do {
  120         setINDF1inc( *FSR0++ );
  121       } while ( --loop != 0 );
  122 
  123       // Prepare HWPID
  124       // Example: 0x35 ,0x50,0x02
  125       setINDF1inc( 0x35 ); // Nop tag + HWPID tag
  126       setINDF1inc( _HWPID_ >> 8 );
  127       setINDF1inc( _HWPID_ & 0xFF );
  128 
  129       // End tag
  130       setINDF1inc( 0 );
  131 
  132       // Write prepared IQRF Code to NFC EEPROM at address 0
  133       NfcWriteBytes( 0, 1 + sizeof( ModuleInfo.MID ) + 1 + 16 + 1 + sizeof( _HWPID ) + 1, I2C_ADDRESS_NFC );
  134 
  135       return;
  136     }
  137 
  138     // Note: *FSR1++ cannot be used in the "if" condition above, because CC5X cannot generate code
  139     FSR1++;
  140   } while ( addr != 1 );
  141 }
  142 
  143 //############################################################################################
  144 void NfcWaitIsReady()
  145 //############################################################################################
  146 {
  147   i2c_stop();
  148   do
  149   {
  150     i2c_start( I2C_ADDRESS_NFC );
  151     i2c_waitForIdle();
  152   } while ( ACKSTAT );
  153   i2c_stop();
  154 }
  155 
  156 //############################################################################################
  157 void NfcSysWriteByte( uns8 addrLow, uns8 data )
  158 //############################################################################################
  159 {
  160   i2c_start( I2C_ADDRESS_NFC_SYS );
  161   i2c_write( 0 );
  162   i2c_write( addrLow );
  163   i2c_write( data );
  164   NfcWaitIsReady();
  165 }
  166 
  167 //############################################################################################
  168 uns8 NfcReadByte( uns16 addr, uns8 device )
  169 //############################################################################################
  170 {
  171   i2c_start( device );
  172   i2c_write( addr.high8 );
  173   i2c_write( addr.low8 );
  174   i2c_start( device | 1 );
  175   uns8 data = i2c_read( FALSE );
  176   i2c_stop();
  177   return data;
  178 }
  179 
  180 //############################################################################################
  181 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device @ W )
  182 //############################################################################################
  183 {
  184   i2c_start( device );
  185   i2c_write( addr.high8 );
  186   i2c_write( addr.low8 );
  187   setFSR1( _FSR_RF );
  188   do {
  189     i2c_write( *FSR1++ );
  190   } while ( --length != 0 );
  191   NfcWaitIsReady();
  192 }
  193 
  194 // ############################################################################################
  195 uns8 NfcCfgByte( uns8 addr @ W )
  196 // ############################################################################################
  197 {
  198   skip( addr );
  199 #pragma computedGoto 1
  200   return 0xC4; // GPO-generuje impuls pokud dojde k RF zapisu do EEPROM 
  201   return 0x00; // IT_TIME-delka pulsu GPO 301us - (0x00 * 37.5us)
  202   return 0x01; // EH_MODE-energy harvesting 0x01 na vyzadani
  203   return 0x00; // RF_MNGT-RF komunikace povolena
  204   return 0x0C; // RFA1SS-Area1 bez hesla a povoleno pouze RF cteni, RF zapis je zakazany (tam prave ulozim IQRF code)
  205   return 0x03; // ENDA1-Area1 adresa 0 až 127B
  206   return 0x06; // RFA2SS-Area2 RF cteni bez hesla a RF zapis s heslem RF_PWD1 (zde je mozne zapsat pouze pomoci RF hesla)
  207   return 0x07; // ENDA2-Area2 adresa 128 až 255B
  208   return 0x00; // RFA3SS-Area3 RF cteni/RF zapis bez hesla
  209   return 0x0B; // ENDA3-Area3 adresa 256 až 383B, zbytek je Area4 384 až 512B
  210   return 0x00; // RFA4SS-Area4 RF cteni/RF zapis bez hesla
  211   return 0x00; // I2CSS-I2C pristup do pameti bez hesla
  212 #pragma computedGoto 0
  213 }
  214 
  215 #ifndef USE_FSRx
  216 // ############################################################################################
  217 void setINDF1inc( uns8 data @ W )
  218 // ############################################################################################
  219 {
  220   setINDF1( data );
  221   FSR1++;
  222 }
  223 #else
  224 #define setINDF1inc( data ) do { *FSR1++ = data; } while(0)
  225 #endif
  226 
  227 #pragma library 0
  228 
  229 #endif
  230 //############################################################################################