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