1 // ***********************************************************************************************************
    2 //   Custom DPA Handler code example - OTK - Node                                                            *
    3 // ***********************************************************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-OTK-Node.c,v $
    7 // Version: $Revision: 1.21 $
    8 // Date:    $Date: 2022/04/05 15:18:29 $
    9 //
   10 // Revision history:
   11 //   2022/02/24  Release for DPA 4.17
   12 //   2021/08/20  Release for DPA 4.16
   13 //
   14 // *********************************************************************
   15 
   16 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   17 
   18 /*
   19   This handler allows Node prebonding by NFC Reader "IQD-NFC-01" using OTK (One Time Key) stored at NFC EEPROM of the Node.
   20   New OTK is generated upon [1] the restart/reset or when [2] there is an RF NFC activity detected.
   21   The Current OTK is stored to the designated IQRF OS buffer to allow SmartConnect prebonding from the NFC Reader device.
   22   Default DPA LED indication is unchanged.
   23 */
   24 
   25 // NFC power pin definition
   26 #define NFC_POWER_TRIS  TRISC.2
   27 #define NFC_POWER_LAT   LATC.2
   28 
   29 // Default IQRF include (modify the path according to your setup)
   30 #include "IQRF.h"
   31 
   32 // Default DPA header (modify the path according to your setup)
   33 #include "DPA.h"
   34 // Default Custom DPA Handler header (modify the path according to your setup)
   35 #include "DPAcustomHandler.h"
   36 // Libraries
   37 #include "lib/NFC.c"
   38 
   39 //############################################################################################
   40 
   41 // This HWPID
   42 #define _HWPID_                   0x888F
   43 #define _HWPIDver_                0x0001
   44 
   45 // I2C SCL frequency [Hz]
   46 #define I2Cfrequency              100000
   47 // Bonding button timeout [ms] before [N] goes to sleep
   48 #define BONDING_BUTTON_TIMEOUT    ( 5 * 1000 )
   49 
   50 // OTK address at NFC EEPROM
   51 #define OTK_NFC_EE_ADDRESS  44
   52 // OTK Length
   53 #define OTK_Length          16
   54 
   55 // Generates new OTK at NFC EEPROM and loads the old one to the IQRF OS place
   56 void  NewOtk();
   57 // Switches NFC on
   58 void  NFCon();
   59 // Switches NFC off
   60 void  NFCoff();
   61 
   62 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   63 //############################################################################################
   64 bit CustomDpaHandler()
   65 //############################################################################################
   66 {
   67 #pragma updateBank default=UserBank_01
   68 
   69   // Handler presence mark
   70   clrwdt();
   71 
   72   // Detect DPA event to handle
   73   switch ( GetDpaEvent() )
   74   {
   75     // -------------------------------------------------
   76     case DpaEvent_Interrupt:
   77       // Do an extra quick background interrupt work
   78       return Carry;
   79 
   80       // -------------------------------------------------
   81     case DpaEvent_Reset:
   82       // Do a one time initialization before main loop starts
   83     {
   84       static bit wasReset;
   85       // It this a very first reset event?
   86       if ( !wasReset )
   87       {
   88         // Reset the flag
   89         wasReset = TRUE;
   90         // Start I2C
   91         _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
   92         // Switch NFC on
   93         NFCon();
   94         // Update IQRF Code and configure NFC EEPROM if needed
   95         if ( !amIBonded() )
   96         {
   97           // Note: To save the code the next call can be omitted supposed it was called at least once, for example during product manufacturing/testing
   98           NfcUpdateIQRFcode();
   99           // Or just the plain NFC configuration in case IQRF Code is not required for SmartConnect bonding
  100           //NfcConfigure();
  101 
  102           // Generate fresh new OTK at NFC EEPROM and make sure the OS buffer does not contain even the last one
  103           NewOtk();
  104           NewOtk();
  105         }
  106       }
  107 
  108       break;
  109     }
  110 
  111     // -------------------------------------------------
  112     case DpaEvent_DpaRequest:
  113       // Called to interpret DPA request for peripherals
  114 
  115       if ( IsDpaEnumPeripheralsRequest() )
  116       {
  117         // -------------------------------------------------
  118         // Peripheral enumeration
  119         _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_;
  120         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= _HWPIDver_;
  121         return TRUE;
  122       }
  123       break;
  124 
  125       // -------------------------------------------------
  126     case DpaEvent_Init:
  127       // Do a one time initialization before main loop starts
  128 
  129       // Optional Bonding/Unbonding is over so switch off NFC just in case it was on because of previous bonding
  130 _NfcAndI2Coff:
  131       NFCoff();
  132       // We do not need I2C any more (in this example)
  133       _DpaApiI2Cshutdown();
  134       break;
  135 
  136       // -------------------------------------------------
  137     case DpaEvent_BondingButton:
  138       // Called to allow a bonding button customization. This event is called regularly during bonding.
  139 
  140       // Keep the NFC and I2C on during the bonding in order to keep value of IT_STS_Dyn _volatile_ register in the NFC chip
  141       _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  142       NFCon();
  143 
  144       // Check, if there was an RF NFC activity detected by checking IT_STS_Dyn.RF_ACTIVITY
  145       if ( NfcReadByte( 0x2005 /* IT_STS_Dyn */, I2C_ADDRESS_NFC ) & 0x02 /* b1=RF_ACTIVITY */ )
  146       {
  147         // Yes there was an RF activity, hopefully OTK was read from the NFC EEPROM
  148         // Generate new OTK in the NFC EEPROM
  149         NewOtk();
  150         // Restart the full bonding timeout to keep the device up and ready for the prebonding from the NFC reader
  151         goto _RestartBondingTimeout;
  152       }
  153 
  154       // We can inspect BondingSleepCountdown value to detect important moments
  155       switch ( BondingSleepCountdown )
  156       {
  157         // Was the BondingSleepCountdown just initiated?
  158         case 0:
  159 _RestartBondingTimeout:
  160           // Yes, reset the timeout variable to BONDING_BUTTON_TIMEOUT
  161           BondingSleepCountdown = BONDING_BUTTON_TIMEOUT / BONDING_SLEEP_COUNTDOWN_UNIT;
  162           break;
  163 
  164           // Are we very probably just about one decrement away to go to sleep because of bonding timeout value is close to 0?
  165         case 0 + 1:
  166           // Yes, switch off NFC and I2C in order to minimize power consumption during the sleep
  167           goto _NfcAndI2Coff;
  168       }
  169 
  170       break;
  171   }
  172 
  173   return FALSE;
  174 }
  175 #pragma updateBank 1
  176 
  177 //############################################################################################
  178 void NewOtk()
  179 //############################################################################################
  180 {
  181   // Read current OTK from NFC EEPROM to bufferRF
  182   NfcReadBytes( OTK_NFC_EE_ADDRESS, OTK_Length, I2C_ADDRESS_NFC );
  183   // Set OTK to IQRF OS to allow prebonding via SmartConnect from NFC Reader device
  184   DpaApiSetOTK();
  185   // Modify OTK bytes randomly
  186   bufferRF[0] += Random.high8;
  187   bufferRF[1] += Random.low8;
  188   bufferRF[2] += TMR1L;
  189   // "Encrypt" i.e. generate new OTK@RF using UserKey
  190   // !!! Set your own UserKey from a default one in advance
  191   decryptBufferRF( OTK_Length / 16 );
  192   // Store new OTK to NFC EE
  193   NfcWriteBytes( OTK_NFC_EE_ADDRESS, OTK_Length, I2C_ADDRESS_NFC );
  194 }
  195 
  196 //############################################################################################
  197 void NFCon()
  198 //############################################################################################
  199 {
  200   // Set the output pin to power NFC
  201   NFC_POWER_TRIS = 0;
  202   // NFC is on?
  203   if ( NFC_POWER_LAT )
  204     return;
  205 
  206   // No, switch it on
  207   NFC_POWER_LAT = 1;
  208   // Do a short power-up delay
  209   waitMS( 1 );
  210 }
  211 
  212 //############################################################################################
  213 void NFCoff()
  214 //############################################################################################
  215 {
  216   NFC_POWER_LAT = 0;
  217 }
  218 
  219 //############################################################################################
  220 // Libraries
  221 #include "lib/NFC.c"
  222 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup)
  223 #include "DPAcustomHandler.h"
  224 //############################################################################################