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