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