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.23 $
    8 // Date:    $Date: 2024/12/02 17:46:59 $
    9 //
   10 // Revision history:
   11 //   2024/11/29  Release for DPA 4.3x
   12 //   2022/02/24  Release for DPA 4.17
   13 //   2021/08/20  Release for DPA 4.16
   14 //   2020/01/02  Release for DPA 4.11
   15 //
   16 // *********************************************************************
   17 
   18 #ifndef __I2C_NFC_LIB__
   19 #define __I2C_NFC_LIB__
   20 
   21 //############################################################################################
   22 
   23 // Define to avoid deadlock when the NFC chip is not connect to the I2C bus. Pull-up resistors are required anyway!
   24 // #define NFC_UPDATE_IGNORE_IF_MISSING
   25 
   26 // I2C chips addresses
   27 #define I2C_ADDRESS_NFC             0b1010.0110
   28 #define I2C_ADDRESS_NFC_SYS         0b1010.1110
   29 
   30 // NFC chip ID
   31 #ifndef NFC_IC_REF
   32 #define NFC_IC_REF  0x24  // = ST25DV04K
   33 #endif
   34 
   35 // NFC routines
   36 bit NfcIsPresent();
   37 bit NfcUpdateIQRFcode();
   38 bit NfcConfigure();
   39 void NfcWaitIsReady();
   40 
   41 // NFC low level routines
   42 uns8 NfcReadByte( uns16 addr, uns8 device );
   43 void NfcSysWriteByte( uns8 addrLow, uns8 data );
   44 // Reads bytes to bufferRF
   45 void NfcReadBytes( uns16 addr, uns8 length, uns8 device );
   46 // Writes bytes from bufferRF
   47 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device );
   48 
   49 #ifndef USE_FSRx
   50 void setINDF1inc( uns8 data );
   51 #else
   52 #define setINDF1inc( data ) do { *FSR1++ = data; } while(0)
   53 #endif
   54 
   55 #if DPA_VERSION_MASTER >= 0x0416
   56 #define _i2c_start        _DpaApiI2Cstart
   57 #define _i2c_stop         _DpaApiI2Cstop
   58 #define _i2c_read         _DpaApiI2Cread
   59 #define _i2c_write        _DpaApiI2Cwrite
   60 #define _i2c_waitForIdle  _DpaApiI2CwaitForIdle
   61 #define _i2c_shutdown     _DpaApiI2Cshutdown
   62 #else
   63 #define _i2c_start        i2c_start      
   64 #define _i2c_stop         i2c_stop       
   65 #define _i2c_read         i2c_read       
   66 #define _i2c_write        i2c_write      
   67 #define _i2c_waitForIdle  i2c_waitForIdle
   68 #define _i2c_shutdown     i2c_shutdown
   69 
   70 #ifndef __I2C_MASTER__
   71 #define __INCLUDE__I2C_MASTER__
   72 #include "lib/I2Cmaster.c"
   73 #endif
   74 
   75 #endif
   76 
   77 //############################################################################################
   78 #else
   79 
   80 #pragma library 1               // Compile only used methods
   81 
   82 #ifdef __INCLUDE__I2C_MASTER__
   83 #include "lib/I2Cmaster.c"
   84 #endif
   85 
   86 #ifndef USE_FSRx
   87 // ############################################################################################
   88 void setINDF1inc( uns8 data @ W )
   89 // ############################################################################################
   90 {
   91 #pragma updateBank exit = UserBank_01
   92   setINDF1( data );
   93   FSR1++;
   94 }
   95 #endif
   96 
   97 // ############################################################################################
   98 uns8 NfcCfgByte( uns8 addr @ W )
   99 // ############################################################################################
  100 {
  101   skip( addr );
  102 #pragma computedGoto 1
  103   return 0xC6; // GPO-generuje impuls pokud dojde k RF zapisu do EEPROM a RF command EOF to response EOF.
  104   return 0x00; // IT_TIME-delka pulsu GPO 301us - (0x00 * 37.5us)
  105   return 0x01; // EH_MODE-energy harvesting 0x01 na vyzadani
  106   return 0x00; // RF_MNGT-RF komunikace povolena
  107   return 0x0C; // RFA1SS-Area1 bez hesla a povoleno pouze RF cteni, RF zapis je zakazany (tam prave ulozim IQRF code)
  108   return 0x03; // ENDA1-Area1 adresa 0 až 127B
  109   return 0x06; // RFA2SS-Area2 RF cteni bez hesla a RF zapis s heslem RF_PWD1 (zde je mozne zapsat pouze pomoci RF hesla)
  110   return 0x07; // ENDA2-Area2 adresa 128 až 255B
  111   return 0x00; // RFA3SS-Area3 RF cteni/RF zapis bez hesla
  112   return 0x0B; // ENDA3-Area3 adresa 256 až 383B, zbytek je Area4 384 až 512B
  113   return 0x00; // RFA4SS-Area4 RF cteni/RF zapis bez hesla
  114   return 0x00; // I2CSS-I2C pristup do pameti bez hesla
  115 #pragma computedGoto 0
  116 }
  117 
  118 //############################################################################################
  119 void nfcConfigureInternal()
  120 //############################################################################################
  121 {
  122   // Enter I2C password (8x zero)
  123   clearBufferRF();
  124   // I2C password validation code between 2 repeated passwords
  125   bufferRF[8] = 0x09;
  126   // Write password (password+0x90+password)
  127   NfcWriteBytes( 0x0900, 8 + 1 + 8, I2C_ADDRESS_NFC_SYS );
  128 
  129   // Check the password was correct (I2C_SSO_Dyn register)
  130   if ( NfcReadByte( 0x2004, I2C_ADDRESS_NFC ) != 1 )
  131   {
  132 _NfcError:
  133     // No, pulse both LEDs
  134     userReg0 = 0;
  135     do
  136     {
  137       clrwdt();
  138       pulseLEDR();
  139       pulseLEDG();
  140       waitDelay( 20 );
  141     } while ( --userReg0 != 0 );
  142     return;
  143   }
  144 
  145   // Now configure NFC
  146   uns8 addr = 0; // System configuration memory address
  147   do {
  148     uns8 cfgByte = NfcCfgByte( addr );
  149     NfcSysWriteByte( addr, cfgByte );
  150     // Check the configuration was written
  151     if ( NfcReadByte( addr, I2C_ADDRESS_NFC_SYS ) != cfgByte )
  152       goto _NfcError;
  153   } while ( ++addr != ( 0x0B /* I2CSS-I2C register */ + 1 ) );
  154 }
  155 
  156 //############################################################################################
  157 bit NfcIsPresent()
  158 //############################################################################################
  159 {
  160   return NfcReadByte( 0x0017 /* IC_REF */, I2C_ADDRESS_NFC_SYS ) == NFC_IC_REF;
  161 }
  162 
  163 //############################################################################################
  164 bit NfcConfigure()
  165 //############################################################################################
  166 {
  167 #pragma updateBank exit = UserBank_01
  168 
  169 #ifdef NFC_UPDATE_IGNORE_IF_MISSING
  170   if ( !NfcIsPresent() )
  171     return Carry;
  172 #endif
  173 
  174   nfcConfigureInternal();
  175   return TRUE;
  176 }
  177 
  178 //############################################################################################
  179 void moduleInfoAndSetFSRs ()
  180 //############################################################################################
  181 {
  182   moduleInfo();
  183   setFSR01( _FSR_INFO, _FSR_RF );
  184 }
  185 
  186 //############################################################################################
  187 bit NfcUpdateIQRFcode()
  188 //############################################################################################
  189 {
  190 #if _HWPID_ > 0xFfFf
  191 #error _HWPID_ > 0xFfFf
  192 #endif
  193 
  194 #if _HWPIDver_ > 0xFfFf
  195 #error _HWPIDver_ > 0xFfFf
  196 #endif
  197 
  198 #ifdef NFC_UPDATE_IGNORE_IF_MISSING
  199   if ( !NfcIsPresent() )
  200     return Carry;
  201 #endif
  202 
  203 // ----------------------------------------------------
  204 #if !defined( TR7xG ) && !defined( NFC_FULL_IQRF_Code )
  205   // Old "D" style, when only MID is checked
  206 #define IQRFcodeLength  ( 1/*Nop+tag*/ + sizeof( ModuleInfo.MID ) + 1/*Nop+tag*/ + 16/*IBK*/ + 1/*Nop+tag*/ + sizeof( uns16 )/*HWPID*/ + 1/*End*/ )
  207 
  208   // 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
  209   uns8 addr = 1 + sizeof( ModuleInfo.MID );
  210   // My MID address to the FSR1
  211 #if &ModuleInfo.MID[0] == &bufferINFO[0]
  212   moduleInfoAndSetFSRs();
  213 #else
  214 #error  Cannot optimize FSR to MID address
  215 #endif
  216   do
  217   {
  218     // MID matches?
  219     if ( NfcReadByte( --addr, I2C_ADDRESS_NFC ) != *FSR0 )
  220     {
  221       // No, configure NFC and write IQRF Code
  222       nfcConfigureInternal();
  223 
  224       // Writes IQRF Code to the EEPROM to the address 0, prepare it at bufferRF
  225 
  226       // Prepare MID reversed, i.e. MSB first
  227       moduleInfoAndSetFSRs();
  228       FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID );
  229       // Example: 0x15 ,0x81,0x11,0x2f,0x0e
  230       setINDF1inc( 0x15 ); // Nop tag + MID tag
  231       uns8 loop = sizeof( ModuleInfo.MID );
  232       do {
  233         setINDF1inc( *--FSR0 );
  234       } while ( --loop != 0 );
  235 
  236       // Prepare IBK
  237       memoryOffsetFrom |= 16;
  238       moduleInfoAndSetFSRs();
  239       FSR1 += 1 + sizeof( ModuleInfo.MID );
  240       // Example: 0x25 ,0xb6,0x03,0x3e,0x8f,0xb0,0x8c,0x9b,0xd1,0x74,0xa1,0x9f,0xc0,0x91,0xb8,0xb9,0xbf
  241       setINDF1inc( 0x25 ); // Nop tag + IBK tag
  242       loop |= 16; // IBK size
  243       do {
  244         setINDF1inc( *FSR0++ );
  245       } while ( --loop != 0 );
  246 
  247       // Prepare HWPID
  248       // Example: 0x35 ,0x50,0x02
  249       setINDF1inc( 0x35 ); // Nop tag + HWPID tag
  250       setINDF1inc( _HWPID_ >> 8 );
  251       setINDF1inc( _HWPID_ & 0xFF );
  252 
  253       // End tag
  254       setINDF1inc( 0 );
  255 
  256       // Write prepared IQRF Code to NFC EEPROM at address 0
  257       NfcWriteBytes( 0, IQRFcodeLength, I2C_ADDRESS_NFC );
  258 
  259       break;
  260     }
  261 
  262     // Note: *FSR0++ cannot be used in the "if" condition above, because CC5X cannot generate code
  263     FSR0++;
  264   } while ( addr != 1 );
  265 
  266 #else
  267 // ----------------------------------------------------
  268   // non-D line, full IQRF Code is compared, construct IQRF Code at bufferRF
  269 #define IQRFcodeLength ( 1/*tags HWPID+MID*/ + sizeof( uns16 )/*HWPID*/ + sizeof( ModuleInfo.MID ) + 1/*tags HWPIDver+IBK*/ + sizeof( uns16 )/*HWPIDver*/ + 16/*IBK*/ + 1/*tags Nop+LogicalAddress*/ + sizeof( ntwADDR )/*LogicalAddress*/ + 1/*End*/ )
  270 
  271   moduleInfoAndSetFSRs();
  272 
  273   //// Prepare HWPID
  274   // Example: HwpId:ABCD => 0xB3, 0xDA, 0x1C
  275   setINDF1inc( ( ( _HWPID_ >> 4 ) & 0xF0 ) | 0x03 ); // HWPID.8-11 + HWPID tag
  276   setINDF1inc( ( ( (uns8)_HWPID_ << 4 ) & 0xF0 ) | ( _HWPID_ >> 12 ) );  // HWPID.0-3 + HWPID.12-15
  277   setINDF1inc( 0x10 | ( ( _HWPID_ >> 4 ) & 0x0F ) );  // MID tag + HWPID.4-7
  278 
  279   //// Prepare MID reversed, i.e. MSB first
  280   FSR0 += offsetof( TModuleInfo, MID ) + sizeof( ModuleInfo.MID );
  281   uns8 loop = sizeof( ModuleInfo.MID );
  282   do {
  283     setINDF1inc( *--FSR0 );
  284   } while ( --loop != 0 );
  285 
  286   //// Prepare HWPIDver
  287   // Example: HwpIdver:ABCDE => 0xB8, 0xDA, 0x2C
  288   setINDF1inc( ( ( _HWPIDver_ >> 4 ) & 0xF0 ) | 0x08 ); // HWPIDver.8-11 + HWPIDver tag
  289   setINDF1inc( ( ( (uns8)_HWPIDver_ << 4 ) & 0xF0 ) | ( _HWPIDver_ >> 12 ) );  // HWPIDver.0-3 + HWPIDver.12-15
  290   setINDF1inc( 0x20 | ( ( _HWPIDver_ >> 4 ) & 0x0F ) );  // IBK tag + HWPIDver.4-7
  291 
  292   //// Prepare IBK
  293   memoryOffsetFrom |= 16;
  294   moduleInfoAndSetFSRs();
  295   FSR1 += 1/*tags HWPID+MID*/ + sizeof( uns16 )/*HWPID*/ + sizeof( ModuleInfo.MID ) + 1/*tags HWPIDver+IBK*/ + sizeof( uns16 )/*HWPIDver*/;
  296   loop |= 16; // IBK size (loop was 0)
  297   do {
  298     setINDF1inc( *FSR0++ );
  299   } while ( --loop != 0 );
  300 
  301   //// Prepare logical address
  302   setINDF1inc( 0x45 ); // Nop tag + Logical address tag
  303   W = 0;  // Coordinator address
  304   // Not Coordinator( _networkingMode == 1 && _networkTwo == 0 ) ?
  305   if ( _networkingMode != 1 || _networkTwo != 0 ) // Note: must not modify W
  306   {
  307     Carry = amIBonded();
  308     W = ntwADDR;  // Bonded value, Note: must not modify Carry
  309     if ( !Carry ) // Note: must not modify W
  310       W = 0xFF; // Not bonded value
  311   }
  312   setINDF1inc( W );
  313 
  314   //// End tag
  315   setINDF1inc( 0 );
  316   // FSR1 is behind the end of generated IQRF Code
  317 
  318   // loop used both as counter and NFC address
  319   loop = IQRFcodeLength;
  320   do
  321   {
  322     FSR1--;
  323     // IQRF Code matches byte by byte?
  324     if ( NfcReadByte( --loop, I2C_ADDRESS_NFC ) != *FSR1 )
  325     {
  326       // No, set IQRF Code aside
  327       copyBufferRF2INFO();
  328       // Configure NFC chip 
  329       nfcConfigureInternal();
  330       // Get IQRF Code back
  331       copyBufferINFO2RF();
  332       // Write prepared IQRF Code to NFC EEPROM at address 0
  333       NfcWriteBytes( 0, IQRFcodeLength, I2C_ADDRESS_NFC );
  334       break;
  335     }
  336   } while ( loop != 0 );
  337 #endif
  338   // ----------------------------------------------------
  339 
  340 #undef IQRFcodeLength
  341   return TRUE;
  342 }
  343 
  344 //############################################################################################
  345 void NfcWaitIsReady()
  346 //############################################################################################
  347 {
  348   _i2c_stop();
  349   do
  350   {
  351     _i2c_start( I2C_ADDRESS_NFC );
  352     _i2c_waitForIdle();
  353 #if defined( TR7xG ) || defined( TR8xG )
  354   } while ( SSP1CON2.6 /*ACKSTAT*/ );
  355 #else
  356 } while ( ACKSTAT );
  357 #endif
  358   _i2c_stop();
  359 }
  360 
  361 //############################################################################################
  362 void NfcSysWriteByte( uns8 addrLow, uns8 data )
  363 //############################################################################################
  364 {
  365   _i2c_start( I2C_ADDRESS_NFC_SYS );
  366   _i2c_write( 0 );
  367   _i2c_write( addrLow );
  368   _i2c_write( data );
  369   NfcWaitIsReady();
  370 }
  371 
  372 //############################################################################################
  373 uns8 NfcReadByte( uns16 addr, uns8 device )
  374 //############################################################################################
  375 {
  376 #pragma updateBank exit = UserBank_01
  377   _i2c_start( device );
  378   _i2c_write( addr.high8 );
  379   _i2c_write( addr.low8 );
  380   _i2c_start( device | 1 );
  381   uns8 data = _i2c_read( FALSE );
  382   _i2c_stop();
  383   return data;
  384 }
  385 
  386 //############################################################################################
  387 void NfcWriteBytes( uns16 addr, uns8 length, uns8 device @ W )
  388 //############################################################################################
  389 {
  390   _i2c_start( device );
  391   _i2c_write( addr.high8 );
  392   _i2c_write( addr.low8 );
  393   setFSR1( _FSR_RF );
  394   do {
  395     _i2c_write( *FSR1++ );
  396   } while ( --length != 0 );
  397   NfcWaitIsReady();
  398 }
  399 
  400 //############################################################################################
  401 void NfcReadBytes( uns16 addr, uns8 length, uns8 device )
  402 //############################################################################################
  403 {
  404   _i2c_start( device );
  405   _i2c_write( addr.high8 );
  406   _i2c_write( addr.low8 );
  407   _i2c_start( device | 1 );
  408   setFSR1( _FSR_RF );
  409   do {
  410     setINDF1inc( _i2c_read( length != 1 ) );
  411   } while ( --length != 0 );
  412   _i2c_stop();
  413 }
  414 //############################################################################################
  415 
  416 #pragma library 0
  417 
  418 #endif
  419 //############################################################################################