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