1 // ************************************************************************************************
    2 //   Custom DPA Handler code example - Shows custom (un)bonding and factory settings using button *
    3 // ************************************************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-Bonding.c,v $
    7 // Version: $Revision: 1.39 $
    8 // Date:    $Date: 2020/01/03 13:56:50 $
    9 //
   10 // Revision history:
   11 //   2019/12/11  Release for DPA 4.11
   12 //   2019/10/09  Release for DPA 4.10
   13 //   2019/06/03  Release for DPA 4.02
   14 //   2019/01/10  Release for DPA 4.00
   15 //   2018/10/25  Release for DPA 3.03
   16 //   2017/08/14  Release for DPA 3.01
   17 //   2017/03/13  Release for DPA 3.00
   18 //   2015/08/05  Release for DPA 2.20
   19 //
   20 // *********************************************************************
   21 
   22 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   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 
   32 // This code illustrates bonding using a button connected to the custom pin.
   33 // Except going to sleep the code behaves the same way as the standard bonding procedure.
   34 // Please see https://www.iqrf.org/DpaTechGuide/index.html?page=device-startup.html and the following chapters.
   35 
   36 // Define to just reassign a bonding button with the button behavior implemented inside DPA
   37 // #define  USE_DpaEvent_BondingButton
   38 
   39 // Custom bonding button. Change to the pin and an active level of your choice.
   40 //#define   IsButton  ( !PORTA.5 )
   41 #define IsButton  buttonPressed
   42 
   43 // Returns TRUE when button is released shortly after LEDG goes out
   44 bit ButtonAfterGreen();
   45 // Same as above but with leading gap
   46 bit ButtonAfterGreenWithGap();
   47 // RedLED on for 1s 
   48 void LEDR1s();
   49 
   50 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   51 //############################################################################################
   52 bit CustomDpaHandler()
   53 //############################################################################################
   54 {
   55   // Handler presence mark
   56   clrwdt();
   57 
   58   // Detect DPA event to handle
   59   switch ( GetDpaEvent() )
   60   {
   61     // -------------------------------------------------
   62     case DpaEvent_Interrupt:
   63       // Do an extra quick background interrupt work
   64       // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible.
   65       // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one.
   66       // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time.
   67       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   68       // ! Make sure race condition does not occur when accessing those variables at other places.
   69       // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt.
   70       // ! Do not call any OS functions except setINDFx().
   71       // ! Do not use any OS variables especially for writing access.
   72       // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage.
   73       return Carry;
   74 
   75 #ifdef USE_DpaEvent_BondingButton
   76       // -------------------------------------------------
   77     case DpaEvent_BondingButton:
   78       // Called to allow a bonding button customization 
   79 
   80       userReg1.0 = 0;
   81       if ( IsButton )
   82         userReg1.0 = 1;
   83 
   84       return TRUE;
   85 #else
   86       // -------------------------------------------------
   87     case DpaEvent_Reset:
   88       // Called after module is reset
   89 
   90       // Handle (un)bonding
   91       if ( !amIBonded() )
   92       {
   93         // -------------------------------------------------
   94         // Not bonded
   95 
   96         // Very 1st bonding attempt and well released button after 2.5 s gap and LEDG?
   97         if ( ButtonAfterGreenWithGap() )
   98           // Factory settings!
   99           goto _factoryAndRemoveBond;
  100 
  101         // If and while node is not bonded
  102         for ( ;; )
  103         {
  104           // If button is not pressed, be ready to be SmartConnected
  105           while ( !IsButton )
  106           {
  107             // Do and wait for an indication
  108             pulseLEDR();
  109             waitMS( 6 );
  110             // Make sure to use LP mode
  111             setRFmode( _WPE | _RX_LP | _TX_LP );
  112 
  113             // Set sometimes a new service channel for SmartConnect, otherwise the last one
  114             static uns8 lastServiceChannel;
  115             static uns8 channelCnt;
  116             // Time to set a new service channel?
  117             if ( ( channelCnt & 0x03 ) == 0 )
  118               // Set a new service channel
  119               lastServiceChannel = 0;
  120             // Next "timer"
  121             channelCnt++;
  122 
  123             // Set the SmartConnect service channel
  124             setServiceChannel( lastServiceChannel );
  125             // Save last service channel used
  126             lastServiceChannel = param2 + 1;
  127 
  128             // Try SmartConnect
  129             _checkRFcfg_PQT = TRUE;
  130             toutRF = 6;
  131             RFRXpacket();
  132             answerSystemPacket();
  133             // Restore RF settings (and make sure Spirit1 is not locked)
  134             wasRFICrestarted();
  135             DpaApiSetRfDefaults();
  136             // SmartConnect success?
  137             if ( amIBonded() )
  138               goto _NodeWasBonded;
  139           }
  140 
  141           // Bonding by button indication
  142           pulseLEDR();
  143           // Traditional bonding using 3 service channels
  144           _3CHTX = TRUE;
  145           // Bonded?
  146           if ( bondRequestAdvanced() )
  147           {
  148 _NodeWasBonded:
  149             // Indicate bonding for 0.5 s
  150             setLEDG();
  151             waitDelay( 50 );
  152             stopLEDG();
  153             // Exit the loop
  154             break;
  155           }
  156         }
  157       }
  158       else
  159       {
  160         // -------------------------------------------------
  161         // Bonded
  162 
  163         // If the button is pressed for 2s (Green LED is on during this time) and then released within 0.5s, then un-bond the node (indicated by 1s Red LED)
  164         if ( ButtonAfterGreen() )
  165         {
  166           // Red LED for 1s
  167           LEDR1s();
  168           // Remove bond + implicit restart
  169           _DpaDataLength = 0;
  170           _PNUM = PNUM_NODE;
  171           _PCMD = CMD_NODE_REMOVE_BOND;
  172           // Perform local DPA Request
  173           DpaApiLocalRequest();
  174           // Unreachable code because of restart
  175         }
  176 
  177         // Now wait if the button is still pressed for about 2.5 s and if again released after green LED do factory settings and remove bond
  178         if ( ButtonAfterGreenWithGap() )
  179         {
  180 _factoryAndRemoveBond:
  181           // Red LED for 1s
  182           LEDR1s();
  183           // Factory settings + remove bond + implicit restart
  184           _DpaDataLength = 0;
  185           _PNUM = PNUM_OS;
  186           _PCMD = CMD_OS_FACTORY_SETTINGS;
  187           // Perform local DPA Request
  188           DpaApiLocalRequest();
  189           // Unreachable code because of restart
  190         }
  191       }
  192 
  193       return TRUE;
  194 #endif
  195   }
  196 
  197   return FALSE;
  198 }
  199 
  200 //############################################################################################
  201 void LEDR1s()
  202 //############################################################################################
  203 {
  204   setLEDR();
  205   waitDelay( 100 );
  206   stopLEDR();
  207 }
  208 
  209 //############################################################################################
  210 bit ButtonAfterGreen()
  211 //############################################################################################
  212 {
  213   // Returns TRUE when button is released shortly after LEDG goes out
  214 
  215   // Time for Green LED on
  216   startDelay( 200 );
  217   // Green LED on
  218   setLEDG();
  219   do
  220   {
  221     // If button not pressed
  222     if ( !IsButton )
  223     {
  224       // Switch off Green LED
  225       stopLEDG();
  226       // And return FALSE
  227       return FALSE;
  228     }
  229     // Is button still pressed while Green LED is on?
  230   } while ( isDelay() );
  231 
  232   // Switch off Green LED
  233   stopLEDG();
  234   // Set testing delay
  235   startDelay( 50 );
  236   do
  237   {
  238     // If the button is released within the delay
  239     if ( !IsButton )
  240       // Return TRUE
  241       return TRUE;
  242   } while ( isDelay() );
  243   // Otherwise return FALSE
  244   return FALSE;
  245 }
  246 
  247 //############################################################################################
  248 bit ButtonAfterGreenWithGap()
  249 //############################################################################################
  250 {
  251   // Is button pressed for 2.55s ?
  252   startDelay( 255 );
  253   while ( IsButton && isDelay() );
  254   // If not the next call will return FALSE, otherwise will test for button release after Green LED goes off
  255   return ButtonAfterGreen();
  256 }
  257 
  258 //############################################################################################
  259 // 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) 
  260 #include "DPAcustomHandler.h"
  261 //############################################################################################