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.18 $
    8 // Date:    $Date: 2022/05/13 15:14:48 $
    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 
  175   return TRUE;
  176 }
  177 
  178 //############################################################################################
  179 bit NfcUpdateIQRFcode()
  180 //############################################################################################
  181 {
  182 #ifdef NFC_UPDATE_IGNORE_IF_MISSING
  183   if ( !NfcIsPresent() )
  184     return Carry;
  185 #endif
  186 
  187   // 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
  188   uns8 addr = 1 + sizeof( ModuleInfo.MID );
  189   // My MID address to the FSR1
  190 #if &ModuleInfo.MID[0] == &bufferINFO[0]
  191   moduleInfo();
  192   setFSR1( _FSR_INFO );
  193 #else
  194 #error  Cannot optimize FSR to MID address
  195 #endif
  196   do
  197   {
  198     // MID matches?
  199     if ( NfcReadByte( --addr, I2C_ADDRESS_NFC ) != *FSR1 )
  200     {
  201       // No, configure NFC and write IQRF Code
  202       nfcConfigureInternal();
  203 
  204       // Writes IQRF Code to the EEPROM to the address 0, prepare it at bufferRF
  205 
  206       // Prepare MID reversed, i.e. MSB first
  207       setFSR01( _FSR_INFO, _FSR_RF );
  208       FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID );
  209       // Example: 0x15 ,0x81,0x11,0x2f,0x0e
  210       setINDF1inc( 0x15 ); // Nop tag + MID tag
  211       uns8 loop = sizeof( ModuleInfo.MID );
  212       do {
  213         setINDF1inc( *--FSR0 );
  214       } while ( --loop != 0 );
  215 
  216       // Prepare IBK
  217       memoryOffsetFrom |= 16;
  218       moduleInfo(); // FSR0 = BUFFER_INFO = IBK
  219       setFSR01( _FSR_INFO, _FSR_RF );
  220       FSR1 += 1 + sizeof( ModuleInfo.MID );
  221       // Example: 0x25 ,0xb6,0x03,0x3e,0x8f,0xb0,0x8c,0x9b,0xd1,0x74,0xa1,0x9f,0xc0,0x91,0xb8,0xb9,0xbf
  222       setINDF1inc( 0x25 ); // Nop tag + IBK tag
  223       loop = 16; // IBK size
  224       do {
  225         setINDF1inc( *FSR0++ );
  226       } while ( --loop != 0 );
  227 
  228       // Prepare HWPID
  229       // Example: 0x35 ,0x50,0x02
  230       setINDF1inc( 0x35 ); // Nop tag + HWPID tag
  231       setINDF1inc( _HWPID_ >> 8 );
  232       setINDF1inc( _HWPID_ & 0xFF );
  233 
  234       // End tag
  235       setINDF1inc( 0 );
  236 
  237       // Write prepared IQRF Code to NFC EEPROM at address 0
  238       NfcWriteBytes( 0, 1 + sizeof( ModuleInfo.MID ) + 1 + 16 + 1 + sizeof( _HWPID ) + 1, I2C_ADDRESS_NFC );
  239 
  240       break;
  241     }
  242 
  243     // Note: *FSR1++ cannot be used in the "if" condition above, because CC5X cannot generate code
  244     FSR1++;
  245   } while ( addr != 1 );
  246 
  247   return TRUE;
  248 }
  249 
  250 //############################################################################################
  251 void NfcWaitIsReady()
  252 //############################################################################################
  253 {
  254   _i2c_stop();
  255   do
  256   {
  257     _i2c_start( I2C_ADDRESS_NFC );
  258     _i2c_waitForIdle();
  259 #ifdef TR7xG
  260   } while ( SSP1CON2.6 /*ACKSTAT*/ );
  261 #else
  262 } while ( ACKSTAT );
  263 #endif
  264 _i2c_stop();
  265 }
  266 
  267 //############################################################################################
  268 void NfcSysWriteByte( uns8 addrLow, uns8 data )
  269 //############################################################################################
  270 {
  271   _i2c_start( I2C_ADDRESS_NFC_SYS );
  272   _i2c_write( 0 );
  273   _i2c_write( addrLow );
  274   _i2c_write( data );
  275   NfcWaitIsReady();
  276 }
  277 
  278 //############################################################################################
  279 uns8 NfcReadByte( uns16 addr, uns8 device )
  280 //############################################################################################
  281 {
  282 #pragma updateBank exit = UserBank_01
  283   _i2c_start( device );
  284   _i2c_write( addr.high8 );
  285   _i2c_write( addr.low8 );
  286   _i2c_start( device | 1 );
  287   uns8 data = _i2c_read( FALSE );
  288   _i2c_stop();
  289   return data;
  290 }
  291 
  292 //############################################################################################
  293 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device @ W )
  294 //############################################################################################
  295 {
  296   _i2c_start( device );
  297   _i2c_write( addr.high8 );
  298   _i2c_write( addr.low8 );
  299   setFSR1( _FSR_RF );
  300   do {
  301     _i2c_write( *FSR1++ );
  302   } while ( --length != 0 );
  303   NfcWaitIsReady();
  304 }
  305 
  306 //############################################################################################
  307 void NfcReadBytes( uns16 addr, uns8 length, uns8 device )
  308 //############################################################################################
  309 {
  310   _i2c_start( device );
  311   _i2c_write( addr.high8 );
  312   _i2c_write( addr.low8 );
  313   _i2c_start( device | 1 );
  314   setFSR1( _FSR_RF );
  315   do {
  316     setINDF1inc( _i2c_read( length != 1 ) );
  317   } while ( --length != 0 );
  318   _i2c_stop();
  319 }
  320 //############################################################################################
  321 
  322 #pragma library 0
  323 
  324 #endif
  325 //############################################################################################