1 // **************************************************************************
    2 //   Custom DPA Handler code example - DPA Menu                             *
    3 // **************************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-DpaMenu.c,v $
    7 // Version: $Revision: 1.11 $
    8 // Date:    $Date: 2023/11/03 16:32:29 $
    9 //
   10 // Revision history:
   11 //   2023/03/07  Release for DPA 4.30
   12 //
   13 // *********************************************************************
   14 
   15 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   16 
   17 // Default IQRF include (modify the path according to your setup)
   18 #include "IQRF.h"
   19 // Default DPA header (modify the path according to your setup)
   20 #include "DPA.h"
   21 // Default Custom DPA Handler header (modify the path according to your setup)
   22 #include "DPAcustomHandler.h"
   23 
   24 #if defined( TR7xD )
   25 #error This example is intended for TR7xG
   26 #endif
   27 
   28 #define _HWPID_                   0x0F0F
   29 #define _HWPIDver_                0x1234
   30 
   31 // Executes DPA Menu User2 menu item
   32 void User2Execute();
   33 
   34 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   35 //############################################################################################
   36 bit CustomDpaHandler()
   37 //############################################################################################
   38 {
   39   static bit startBeamingAtIdle;
   40   static uns8 inStanbyCnt;
   41 
   42   // Handler presence mark
   43   clrwdt();
   44 
   45   // Detect DPA event to handle (unused event handlers can be commented out or even deleted)
   46   switch ( GetDpaEvent() )
   47   {
   48     // -------------------------------------------------
   49     case DpaEvent_Interrupt:
   50       // Do an extra quick background interrupt work
   51       // ! 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.
   52       // ! 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.
   53       // ! 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.
   54       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   55       // ! Make sure race condition does not occur when accessing those variables at other places.
   56       // ! 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.
   57       // ! Do not call any OS functions except setINDFx().
   58       // ! Do not use any OS variables especially for writing access.
   59       // ! 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.
   60       // https://doc.iqrf.org/DpaTechGuide/pages/EventInterrupt.html
   61 
   62       return Carry;
   63 
   64       // -------------------------------------------------
   65     case DpaEvent_Idle:
   66       // Do a quick background work when RF packet is not received
   67       // https://doc.iqrf.org/DpaTechGuide/pages/idle.html
   68 
   69       // Was beaming selected at the Online menu?
   70       if ( startBeamingAtIdle )
   71       {
   72         startBeamingAtIdle = FALSE;
   73         // Simulate beaming (see CustomDpaHandler-SensorBeaming-Temperature.c for the real beaming code)
   74         FirstDpaApiSleep = TRUE;
   75         for ( ;; )
   76         {
   77           DpaApiSleep( WDTCON_512ms );
   78 
   79           // Indicate beaming
   80           setLEDG();
   81           waitMS( 20 );
   82           stopLEDG();
   83 
   84           DpaApiSleep( WDTCON_512ms );
   85 
   86           uns8 menuAndItem = DpaApiMenu( DMENU_Beaming, DMENU_Item_Implemented_User1Confirmed | DMENU_Item_Implemented_User2 );
   87           switch ( menuAndItem )
   88           {
   89             case MakeDMenuAndItem( DMENU_Beaming, DMENU_Item_None ):
   90               // No menu item was selected
   91               break;
   92 
   93             case MakeDMenuAndItem( DMENU_Beaming, DMENU_Item_User1 ):
   94               // User1 always reports error
   95               DpaApiMenuIndicateResult( FALSE );
   96               break;
   97 
   98             case MakeDMenuAndItem( DMENU_Beaming, DMENU_Item_User2 ):
   99               // User2 always reports OK
  100               DpaApiMenuIndicateResult( TRUE );
  101               // And is executed
  102               User2Execute();
  103               break;
  104 
  105             case MakeDMenuAndItem( DMENU_Beaming, DMENU_Item_ConnectivityCheck ):
  106               // Stop beaming sleeps
  107               DpaApiAfterSleep();
  108               // Voluntary indication of the TestRange execution
  109               pulsingLEDR();
  110               // Repeaters to test
  111               clearBufferINFO();
  112               bufferINFO[0 / 8] = 0b1111.1110;   // 1...7
  113               // Do the test and result indication
  114               DpaApiMenuIndicateResult( DpaApiLocalFrc( FRC_Ping, TX_POWER_MAX ) );
  115               // Continue regular beaming sleeps
  116               FirstDpaApiSleep = TRUE;
  117               break;
  118 
  119             default:
  120               // Stop beaming sleeps
  121               DpaApiAfterSleep();
  122               // Execute other menu items
  123               DpaApiMenuExecute( menuAndItem );
  124               // Continue regular beaming sleeps
  125               FirstDpaApiSleep = TRUE;
  126               break;
  127           }
  128         }
  129       }
  130       break;
  131 
  132       // -------------------------------------------------
  133     case DpaEvent_Reset:
  134       // Called after module is reset
  135       // https://doc.iqrf.org/DpaTechGuide/pages/ResetEvent.html
  136 
  137     {
  138       static bit wasReset;
  139       if ( !wasReset )
  140       {
  141         wasReset = TRUE;
  142 
  143         // To minimize the power consumption, no MCU pin must be left as a digital input without defined input level value.
  144         // So, unused pins in given hardware should be set as outputs:
  145 #if defined( TR72G ) // Symbols are generated by IQRF IDE according to the TR selection in a project
  146         // TR pin C1 (MCU pin RA0): should be set as an output
  147         LATA.0 = 0;                     // Low level
  148         TRISA.0 = 0;                    // Output
  149 
  150         // TR pin C2 (MCU pin RC2): should be set as an output
  151         LATC.2 = 0;                     // Low level
  152         TRISC.2 = 0;                    // Output
  153 
  154         // TR pin C5 (MCU pins RA5, RB4 and RC6 connected in parallel):
  155         //   All MCU pins can be set as an input, but pin RB4 must be configured with internal pull-up (default activated).
  156         TRISA.5 = 1;                    // Input
  157         TRISB.4 = 1;                    // Input
  158         TRISC.6 = 1;                    // Input
  159 
  160         // TR pin C6 (MCU pin RC3): should be set as an output
  161         LATC.3 = 0;                     // Low level
  162         TRISC.3 = 0;                    // Output
  163 
  164         // TR pin C7 (MCU pin RC4): should be set as an output
  165         LATC.4 = 0;                     // Low level
  166         TRISC.4 = 0;                    // Output
  167 
  168         // TR pin C8 (MCU pins RC5 and RC7 connected in parallel):
  169         //   Only one MCU pin should be set as an output
  170         LATC.5 = 0;                     // Low level
  171         TRISC.5 = 0;                    // Output
  172         TRISC.7 = 1;                    // Input
  173 #elif defined( TR76G )
  174         // TR pin Q14 (MCU pin RA0): should be set as an output
  175         LATA.0 = 0;                     // Low level
  176         TRISA.0 = 0;                    // Output
  177 
  178         // TR pin Q15 (MCU pin RC2): should be set as an output
  179         LATC.2 = 0;                     // Low level
  180         TRISC.2 = 0;                    // Output
  181 
  182         // TR pin Q4 (MCU pin RC6): should be set as an output
  183         LATC.6 = 0;                     // Low level
  184         TRISC.6 = 0;                    // Output
  185 
  186         // TR pin Q5 (MCU pin RC7): should be set as an output
  187         LATC.7 = 0;                     // Low level
  188         TRISC.7 = 0;                    // Output
  189 
  190         // TR pin Q6 (MCU pin RC3): should be set as an output
  191         LATC.3 = 0;                     // Low level
  192         TRISC.3 = 0;                    // Output
  193 
  194         // TR pin Q7 (MCU pin RC4): should be set as an output
  195         LATC.4 = 0;                     // Low level
  196         TRISC.4 = 0;                    // Output
  197 
  198         // TR pin Q8 (MCU pin RC5): should be set as an output
  199         LATC.5 = 0;                     // Low level
  200         TRISC.5 = 0;                    // Output
  201 
  202         // TR pin Q9 (MCU pin RA5): should be set as an output
  203         LATA.5 = 0;                     // Low level
  204         TRISA.5 = 0;                    // Output
  205 
  206         // TR LED pins Q10 and Q11 (MCU pins RB7 and RA2) are set as outputs by OS.
  207         // TR pin Q12 (MCU pin RB4) is set as an input with internal pull-up activated as default.
  208 #else
  209         #warning Low power consumption by treating unused pins is not implemented for the selected TR module
  210 #endif
  211 
  212         // Indicate startup
  213         waitDelay( 20 );
  214         setLEDR();
  215         setLEDG();
  216         waitDelay( 50 );
  217         stopLEDR();
  218         stopLEDG();
  219         waitDelay( 50 );
  220       }
  221 
  222       break;
  223     }
  224 
  225     // -------------------------------------------------
  226     case DpaEvent_MenuActivated:
  227       // Called to customize DPA menu
  228       // https://doc.iqrf.org/DpaTechGuide/pages/menuactivated.html
  229 
  230       inStanbyCnt = 0;
  231 
  232       switch ( userReg1 )
  233       {
  234         case DMENU_Online:
  235           // Customize Online DPA Menu
  236           userReg1 = DMENU_Item_Implemented_Beaming | DMENU_Item_Implemented_User1Confirmed | DMENU_Item_Implemented_User2 | DMENU_Item_Unimplemented_UnbondFactorySettingsAndRestart;
  237           goto DpaHandleReturnTRUE;
  238 
  239         case DMENU_ReadyToBond:
  240           // Customize ReadyToBond DPA Menu
  241           userReg1 = DMENU_Item_Implemented_User1Confirmed | DMENU_Item_Implemented_User2 | DMENU_Item_Unimplemented_UnbondAndRestart;
  242 
  243           // Was the BondingSleepCountdown just initiated?
  244           if ( BondingSleepCountdown == 0 )
  245             // Set a few seconds timeout
  246             BondingSleepCountdown = 10000 / BONDING_SLEEP_COUNTDOWN_UNIT;
  247           goto DpaHandleReturnTRUE;
  248       }
  249       break;
  250 
  251       // -------------------------------------------------
  252     case DpaEvent_MenuItemSelected:
  253       // Called to indicate "OK" or "Error" for selected menu item
  254       // https://doc.iqrf.org/DpaTechGuide/pages/menuitemselected.html
  255 
  256       switch ( userReg1 )
  257       {
  258         case MakeDMenuAndItem( DMENU_Online, DMENU_Item_Beaming ):
  259           // Beaming is OK when the node is bonded, but not prebonded
  260           if ( amIBonded() )
  261           {
  262             startBeamingAtIdle = TRUE;
  263             goto DpaHandleReturnTRUE;
  264           }
  265 
  266           break;
  267 
  268         case MakeDMenuAndItem( DMENU_Online, DMENU_Item_User2 ):
  269         case MakeDMenuAndItem( DMENU_ReadyToBond, DMENU_Item_User2 ):
  270           // User2 always reports OK
  271           goto DpaHandleReturnTRUE;
  272       }
  273 
  274       break;
  275 
  276       // -------------------------------------------------
  277     case DpaEvent_MenuItemFinalize:
  278       // Called to finalize menu item execution
  279       // https://doc.iqrf.org/DpaTechGuide/pages/menuitemfinalize.html
  280 
  281       switch ( GetDMenuItem( userReg1 ) )
  282       {
  283         // Execute User2 menu item
  284         case DMENU_Item_User2:
  285           User2Execute();
  286           break;
  287       }
  288       break;
  289 
  290       // -------------------------------------------------
  291     case DpaEvent_InStandby:
  292       // Called to set WDT during Standby
  293       // https://doc.iqrf.org/DpaTechGuide/pages/instandby.html
  294 
  295       // Pulse LEDR or LEDG for 8 ms every 4 s in Standby
  296       if ( inStanbyCnt.1 )
  297         _LEDR = 1;
  298       else
  299         _LEDG = 1;
  300 
  301       if ( inStanbyCnt.0 )
  302       {
  303         _LEDR = 0;
  304         _LEDG = 0;
  305         userReg1 = WDTCON_4s;
  306       }
  307       else
  308         userReg1 = WDTCON_8ms;
  309 
  310       inStanbyCnt++;
  311       goto DpaHandleReturnTRUE;
  312 
  313       // -------------------------------------------------
  314     case DpaEvent_DpaRequest:
  315       // Called to interpret DPA request for peripherals
  316       // https://doc.iqrf.org/DpaTechGuide/pages/EventDpaRequest.html
  317 
  318       if ( IsDpaEnumPeripheralsRequest() )
  319       {
  320         // -------------------------------------------------
  321         // Peripheral enumeration
  322         // https://doc.iqrf.org/DpaTechGuide/pages/enumerate-peripherals.html
  323 
  324         // We implement no user peripheral
  325         _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_;
  326         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= _HWPIDver_;
  327 
  328 DpaHandleReturnTRUE:
  329         return TRUE;
  330       }
  331   }
  332 
  333   return FALSE;
  334 }
  335 
  336 //############################################################################################
  337 void User2Execute()
  338 //############################################################################################
  339 {
  340   uns8 loop = 3;
  341   do
  342   {
  343     waitMS( 200 );
  344     setLEDR();
  345     setLEDG();
  346     waitMS( 50 );
  347     stopLEDR();
  348     stopLEDG();
  349     clrwdt();
  350   } while ( --loop != 0 );
  351 }
  352 
  353 //############################################################################################
  354 #pragma library 1   // Compile only used functions
  355 // 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)
  356 #include "DPAcustomHandler.h"
  357 //############################################################################################