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