1 // *********************************************************************
    2 //   Custom DPA Handler - Beaming template                             *
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-SensorBeaming-Temperature.c,v $
    7 // Version: $Revision: 1.30 $
    8 // Date:    $Date: 2023/11/24 10:36:39 $
    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 // Default IQRF include (modify the path according to your setup)
   21 #include "IQRF.h"
   22 
   23 // Default DPA header (modify the path according to your setup)
   24 #include "DPA.h"
   25 // Default Custom DPA Handler header (modify the path according to your setup)
   26 #include "DPAcustomHandler.h"
   27 
   28 // IQRF standards header (modify the path according to your setup)
   29 #include "standard/IQRFstandard.h"
   30 #include "standard/IQRF_HWPID.h"
   31 
   32 // Uncomment the following includes if the respective library is needed
   33 //#include "NFC.c"
   34 
   35 //############################################################################################
   36 
   37 // Unused pins are set (during the Reset event) as outputs to minimize power consumption. Modify the code according to your needs.
   38 
   39 // Define to pulse LEDG on every Idle event and after beaming has been transmitted. Also regular beaming is every 5 s instead of "default" 60 s and shorter go2beaming timeout
   40 #define DEBUGBeaming
   41 
   42 #define _HWPID_           0x5E7F
   43 #define _HWPIDver_        0x0300 // 3.00
   44 
   45 // Timeout in seconds to start beaming in case of network inactivity (655 seconds is maximum)
   46 #ifndef DEBUGBeaming
   47 #define BEAMING_TIMEOUT   120
   48 #else
   49 #define BEAMING_TIMEOUT   20
   50 #endif
   51 
   52 // Variable to store sensor value at Get?_????() methods.
   53 uns16 sensorValue;
   54 
   55 // Beaming function
   56 void Beaming();
   57 
   58 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   59 //############################################################################################
   60 // https://doc.iqrf.org/DpaTechGuide/pages/custom-dpa-handler.html
   61 bit CustomDpaHandler()
   62 //############################################################################################
   63 {
   64 #ifndef DpaEvent_MenuActivated
   65   static bit buttonOnInit;
   66 #else
   67   static bit startBeamingAtIdle;
   68 #endif
   69 
   70   // Handler presence mark
   71   clrwdt();
   72 
   73   // Detect DPA event to handle (unused event handlers can be commented out or even deleted)
   74   switch ( GetDpaEvent() )
   75   {
   76     // -------------------------------------------------
   77     case DpaEvent_Interrupt:
   78       // Do an extra quick background interrupt work
   79       // ! 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.
   80       // ! 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.
   81       // ! 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.
   82       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   83       // ! Make sure race condition does not occur when accessing those variables at other places.
   84       // ! 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.
   85       // ! Do not call any OS functions except setINDFx().
   86       // ! Do not use any OS variables especially for writing access.
   87       // ! 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.
   88       // https://doc.iqrf.org/DpaTechGuide/pages/EventInterrupt.html
   89       return Carry;
   90 
   91       // -------------------------------------------------
   92     case DpaEvent_Idle:
   93       // Do a quick background work when RF packet is not received
   94       // https://doc.iqrf.org/DpaTechGuide/pages/idle.html
   95 
   96 #ifdef DEBUGBeaming
   97       // On-line mode indication
   98       pulseLEDG();
   99 #endif
  100 
  101 #ifndef DpaEvent_MenuActivated
  102       if ( buttonPressed )
  103       {
  104         if ( !buttonOnInit && ntwADDR != TEMPORARY_ADDRESS && buttonPressed )
  105           // Go to Beaming mode
  106           Beaming();
  107       }
  108       else
  109         buttonOnInit = FALSE;
  110 #else
  111       if ( startBeamingAtIdle )
  112       {
  113         startBeamingAtIdle = FALSE;
  114         // Go to Beaming mode
  115         Beaming();
  116       }
  117 #endif
  118 
  119       // Start beaming after a defined inactivity time
  120       captureTicks();
  121       if ( param3 > (uns16)BEAMING_TIMEOUT * 100 )
  122       {
  123         if ( ntwADDR != TEMPORARY_ADDRESS )
  124           Beaming();
  125         else
  126           goto _startCapture;
  127       }
  128 
  129       break;
  130 
  131       // -------------------------------------------------
  132     case DpaEvent_Reset:
  133       // Called after module is reset
  134       // https://doc.iqrf.org/DpaTechGuide/pages/ResetEvent.html
  135     {
  136       static bit wasReset;
  137       if ( !wasReset )
  138       {
  139         wasReset = TRUE;
  140 
  141         // To minimize the power consumption, no MCU pin must be left as a digital input without defined input level value.
  142         // So, unused pins in given hardware should be set as outputs:
  143 #if defined( TR72G ) || defined( TR72D ) // Symbols are generated by IQRF IDE according to the TR selection in a project
  144         // TR pin C1 (MCU pin RA0): should be set as an output
  145         LATA.0 = 0;                     // Low level
  146         TRISA.0 = 0;                    // Output
  147 
  148         // TR pin C2 (MCU pin RC2): should be set as an output
  149         LATC.2 = 0;                     // Low level
  150         TRISC.2 = 0;                    // Output
  151 
  152         // TR pin C5 (MCU pins RA5, RB4 and RC6 connected in parallel):
  153         //   All MCU pins can be set as an input, but pin RB4 must be configured with internal pull-up (default activated).
  154         TRISA.5 = 1;                    // Input
  155         TRISB.4 = 1;                    // Input
  156         TRISC.6 = 1;                    // Input
  157 
  158         // TR pin C6 (MCU pin RC3): should be set as an output
  159         LATC.3 = 0;                     // Low level
  160         TRISC.3 = 0;                    // Output
  161 
  162         // TR pin C7 (MCU pin RC4): should be set as an output
  163         LATC.4 = 0;                     // Low level
  164         TRISC.4 = 0;                    // Output
  165 
  166         // TR pin C8 (MCU pins RC5 and RC7 connected in parallel):
  167         //   Only one MCU pin should be set as an output
  168         LATC.5 = 0;                     // Low level
  169         TRISC.5 = 0;                    // Output
  170         TRISC.7 = 1;                    // Input
  171 #elif defined( TR76G ) || defined( TR76D )
  172         // TR pin Q14 (MCU pin RA0): should be set as an output
  173         LATA.0 = 0;                     // Low level
  174         TRISA.0 = 0;                    // Output
  175 
  176         // TR pin Q15 (MCU pin RC2): should be set as an output
  177         LATC.2 = 0;                     // Low level
  178         TRISC.2 = 0;                    // Output
  179 
  180         // TR pin Q4 (MCU pin RC6): should be set as an output
  181         LATC.6 = 0;                     // Low level
  182         TRISC.6 = 0;                    // Output
  183 
  184         // TR pin Q5 (MCU pin RC7): should be set as an output
  185         LATC.7 = 0;                     // Low level
  186         TRISC.7 = 0;                    // Output
  187 
  188         // TR pin Q6 (MCU pin RC3): should be set as an output
  189         LATC.3 = 0;                     // Low level
  190         TRISC.3 = 0;                    // Output
  191 
  192         // TR pin Q7 (MCU pin RC4): should be set as an output
  193         LATC.4 = 0;                     // Low level
  194         TRISC.4 = 0;                    // Output
  195 
  196         // TR pin Q8 (MCU pin RC5): should be set as an output
  197         LATC.5 = 0;                     // Low level
  198         TRISC.5 = 0;                    // Output
  199 
  200         // TR pin Q9 (MCU pin RA5): should be set as an output
  201         LATA.5 = 0;                     // Low level
  202         TRISA.5 = 0;                    // Output
  203 
  204         // TR LED pins Q10 and Q11 (MCU pins RB7 and RA2) are set as outputs by OS.
  205         // TR pin Q12 (MCU pin RB4) is set as an input with internal pull-up activated as default.
  206 #else
  207         #warning Low power consumption by treating unused pins is not implemented for the selected TR module
  208 #endif
  209       }
  210 
  211       //goto DpaHandleReturnTRUE; // return TRUE only if you handle node bonding/unbonding at TRxD
  212       break;
  213     }
  214 
  215     // -------------------------------------------------
  216 #ifdef DpaEvent_BondingButton
  217     case DpaEvent_BondingButton:
  218       // Called to allow a bonding button customization
  219       // https://doc.iqrf.org/DpaTechGuide/pages/bondingbutton.html
  220       //goto DpaHandleReturnTRUE; // return TRUE to handle bonding button
  221       break;
  222 #endif
  223 
  224       // -------------------------------------------------
  225     case DpaEvent_Indicate:
  226       // Called to allow a customization of the device indication
  227       // https://doc.iqrf.org/DpaTechGuide/pages/IndicateEvent.html
  228       //goto DpaHandleReturnTRUE; // return TRUE to skip default indication
  229       break;
  230 
  231       // -------------------------------------------------
  232     case DpaEvent_AfterSleep:
  233       // Called after woken up after sleep
  234       // https://doc.iqrf.org/DpaTechGuide/pages/aftersleep.html
  235 
  236       // ! Fall through !
  237 
  238       // -------------------------------------------------
  239     case DpaEvent_Init:
  240       // Do a one time initialization before main loop starts
  241       // https://doc.iqrf.org/DpaTechGuide/pages/init.html
  242 
  243 #ifndef DpaEvent_MenuActivated
  244       if ( buttonPressed )
  245         buttonOnInit = TRUE;
  246 #endif
  247 
  248       goto _startCapture;
  249 
  250       // -------------------------------------------------
  251     case DpaEvent_ReceiveDpaRequest:
  252       // Called after DPA request was received
  253       // https://doc.iqrf.org/DpaTechGuide/pages/receivedparequest.html
  254 
  255       // Start inactivity timer
  256       if ( _ROUTEF )
  257       {
  258 _startCapture:
  259         startCapture();
  260       }
  261 
  262       //goto DpaHandleReturnTRUE; // return TRUE to skip default processing
  263       break;
  264 
  265       // -------------------------------------------------
  266     case DpaEvent_BeforeSendingDpaResponse:
  267       // Called before sending DPA response back to originator of DPA response
  268       // https://doc.iqrf.org/DpaTechGuide/pages/beforesendingdparesponse.html
  269       break;
  270 
  271       // -------------------------------------------------
  272     case DpaEvent_Notification:
  273       // Called after DPA request was processed and after DPA response was sent
  274       // https://doc.iqrf.org/DpaTechGuide/pages/notification.html
  275       break;
  276 
  277       // -------------------------------------------------
  278     case DpaEvent_AfterRouting:
  279       // Called after Notification and after routing of the DPA response was finished
  280       // https://doc.iqrf.org/DpaTechGuide/pages/afterrouting.html
  281       break;
  282 
  283       // -------------------------------------------------
  284     case DpaEvent_FrcValue:
  285       // Called to get FRC value
  286       // https://doc.iqrf.org/DpaTechGuide/pages/frcvalue.html
  287       break;
  288 
  289       // -------------------------------------------------
  290     case DpaEvent_FrcResponseTime:
  291       // Called to get FRC response time
  292       // https://doc.iqrf.org/DpaTechGuide/pages/frcresponsetime.html
  293       break;
  294 
  295       // -------------------------------------------------
  296     case DpaEvent_BeforeSleep:
  297       // Called before going to sleep
  298       // https://doc.iqrf.org/DpaTechGuide/pages/beforesleep.html
  299       break;
  300 
  301       // -------------------------------------------------
  302     case DpaEvent_DisableInterrupts:
  303       // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond and run RFPGM)
  304       // https://doc.iqrf.org/DpaTechGuide/pages/eventDisableInterrupts.html
  305       break;
  306 
  307       // -------------------------------------------------
  308     case DpaEvent_PeerToPeer:
  309       // Called when peer-to-peer (non-networking) packet is received
  310       // https://doc.iqrf.org/DpaTechGuide/pages/peertopeer.html
  311       break;
  312 
  313       // -------------------------------------------------
  314     case DpaEvent_UserDpaValue:
  315       // Called when DPA is required to return User defined DPA value in the response
  316       // https://doc.iqrf.org/DpaTechGuide/pages/userdpavalue.html
  317       break;
  318 
  319       // -------------------------------------------------
  320     case DpaEvent_VerifyLocalFrc:
  321       // Called to verify local FRC command
  322       // https://doc.iqrf.org/DpaTechGuide/pages/verifylocalfrc.html
  323 
  324       //goto DpaHandleReturnTRUE; // return TRUE allow FRC command
  325       break;
  326 
  327       // -------------------------------------------------
  328 #ifdef DpaEvent_MenuActivated
  329     case DpaEvent_MenuActivated:
  330       // Called to customize DPA menu
  331       // https://doc.iqrf.org/DpaTechGuide/pages/menuactivated.html
  332 
  333       switch ( userReg1 )
  334       {
  335         case DMENU_Online:
  336           userReg1 = DMENU_Item_Implemented_Beaming;
  337           goto DpaHandleReturnTRUE; // return TRUE to allow customizing menu specified by userReg1
  338       }
  339       break;
  340 #endif
  341 
  342       // -------------------------------------------------
  343 #ifdef DpaEvent_MenuItemSelected
  344     case DpaEvent_MenuItemSelected:
  345       // Called to indicate "OK" or "Error" for selected menu item
  346       // https://doc.iqrf.org/DpaTechGuide/pages/menuitemselected.html
  347 
  348       switch ( userReg1 )
  349       {
  350         case MakeDMenuAndItem( DMENU_Online, DMENU_Item_Beaming ):
  351           if ( amIBonded() )
  352           {
  353             startBeamingAtIdle = TRUE;
  354             goto DpaHandleReturnTRUE; // return TRUE to indicate "OK" for menu item specified by userReg1, otherwise to indicate Error
  355           }
  356           break;
  357       }
  358       break;
  359 #endif
  360 
  361       // -------------------------------------------------
  362 #ifdef DpaEvent_MenuItemFinalize
  363     case DpaEvent_MenuItemFinalize:
  364       // Called to finalize menu item execution
  365       // https://doc.iqrf.org/DpaTechGuide/pages/menuitemfinalize.html
  366 
  367       break;
  368 #endif
  369 
  370       // -------------------------------------------------
  371     case DpaEvent_DpaRequest:
  372       // Called to interpret DPA request for peripherals
  373       // https://doc.iqrf.org/DpaTechGuide/pages/EventDpaRequest.html
  374       IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest()
  375       {
  376         // -------------------------------------------------
  377         // Peripheral enumeration
  378         // https://doc.iqrf.org/DpaTechGuide/pages/enumerate-peripherals.html
  379 
  380         // We implement 1 standard peripheral
  381         _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1;
  382         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  383         _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_;
  384         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= _HWPIDver_;
  385 
  386 DpaHandleReturnTRUE:
  387         return TRUE;
  388       }
  389       else
  390       {
  391         // -------------------------------------------------
  392         // Get information about peripheral
  393         // https://doc.iqrf.org/DpaTechGuide/pages/get-peripheral-info.html
  394 
  395         if ( _PNUM == PNUM_STD_SENSORS )
  396         {
  397           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS;
  398           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ;
  399           // Set standard version
  400           _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION;
  401           goto DpaHandleReturnTRUE;
  402         }
  403 
  404         break;
  405       }
  406 
  407       // -------------------------------------------------
  408       // Handle peripheral command
  409       // https://doc.iqrf.org/DpaTechGuide/pages/handle-peripheral-request.html
  410 
  411       // Supported peripheral number?
  412       if ( _PNUM == PNUM_STD_SENSORS )
  413       {
  414         // Supported commands?
  415         switch ( _PCMD )
  416         {
  417           // Invalid command
  418           default:
  419             // Return error
  420             W = ERROR_PCMD;
  421 _ERROR_W:
  422             DpaApiReturnPeripheralError( W );
  423             break;
  424 
  425             // Sensor enumeration
  426           case PCMD_STD_ENUMERATE:
  427             if ( _DpaDataLength != 0 )
  428             {
  429               W = ERROR_DATA_LEN;
  430               goto _ERROR_W;
  431             }
  432 
  433             // Then just enumerate their types
  434             // -------------------------------------------------
  435             _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_EXTRA_LOW_VOLTAGE;
  436             _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_TEMPERATURE;
  437             _DpaDataLength |= 2;
  438             // -------------------------------------------------
  439             goto DpaHandleReturnTRUE;
  440         }
  441       }
  442 
  443       break;
  444   }
  445 
  446 DpaHandleReturnFALSE:
  447   return FALSE;
  448 }
  449 
  450 //############################################################################################
  451 void RandomWait()
  452 //############################################################################################
  453 {
  454   FirstDpaApiSleep = TRUE;
  455   // Time 32.768 ms * ( 30 + rand(0...31) ) i.e. 983 - 1999 ms
  456   uns8 loop = ( DpaApiRandom() & 0x1F ) + 30;
  457   do
  458   {
  459     _DpaApiSleep( WDTCON_32ms );
  460   } while ( --loop != 0 );
  461   _DpaApiAfterSleep();
  462 }
  463 
  464 //############################################################################################
  465 void Get_Temperature()
  466 //############################################################################################
  467 {
  468   // https://doc.iqrf.org/IQRF-Standards/StandardSensor/pages/0x01-temperature.html
  469 
  470   // Return standard error value if there was an error
  471   sensorValue = FRC_STD_FRC_ERROR_VALUE;
  472   // Error reading temperature? Note: param3 holds finer temperature value after calling getTemperature()
  473   if ( getTemperature() != -128 )
  474   {
  475     // Extent minus sign bit #11 to the bits #12-15
  476     if ( param3.11 )
  477       param3 |= 0xF000;
  478     // Make a FRC value from the raw value
  479     sensorValue = param3 ^ 0x8000;
  480   }
  481 }
  482 
  483 //############################################################################################
  484 void Get_ExtraLowVoltage()
  485 //############################################################################################
  486 {
  487   // https://doc.iqrf.org/IQRF-Standards/StandardSensor/pages/0x04-extra-low-voltage.html
  488 
  489   // Voltage [V] = 261.12 / (127 - getSupplyVoltage)
  490   uns8 div = 127 - getSupplyVoltage();
  491   // For expected voltage ~3.0V, the divider is 127-40=87, so we will add 1/2 of it for more precise rounding
  492   sensorValue = (uns24)( 261.120 * 1000 + 87.0 / 2 ) / div;
  493   // Make a FRC value from the raw value
  494   sensorValue ^= 0x8000;
  495 }
  496 
  497 //############################################################################################
  498 void ReleaseButton()
  499 //############################################################################################
  500 {
  501   do
  502   {
  503     clrwdt();
  504   } while ( buttonPressed );
  505 }
  506 
  507 //############################################################################################
  508 void Beaming()
  509 //############################################################################################
  510 {
  511   // Indicate start of beaming
  512   setLEDR();
  513 
  514   // Wait for button release
  515   ReleaseButton();
  516   // 1st voltage readout
  517   Get_ExtraLowVoltage();
  518 
  519   for ( ;; )
  520   {
  521     // Do beaming
  522     clrwdt();
  523 
  524     // Check for the locked Spirit1 RF chip
  525     if ( wasRFICrestarted() )
  526       DpaApiSetRfDefaults();
  527 
  528     // Required time for the temperature sensor after wake-up from sleep
  529     waitDelay( 31 ); // Note: in real application do sleep instead of active waiting to lower the consumption
  530 
  531     // Prepare beaming data
  532     // Voltage was read 1st time when the device starts beaming and then after every TX in the beaming when the power consumption was the highest
  533     _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_EXTRA_LOW_VOLTAGE;
  534     _DpaMessage.Response.PData[1] = sensorValue.low8;
  535     _DpaMessage.Response.PData[2] = sensorValue.high8;
  536 
  537     Get_Temperature();
  538     _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_TEMPERATURE;
  539     _DpaMessage.Response.PData[4] = sensorValue.low8;
  540     _DpaMessage.Response.PData[5] = sensorValue.high8;
  541 
  542     // Do simple LBT
  543     uns8 loop = 3;
  544     do
  545     {
  546       if ( !checkRF( RxFilter + 10 ) )
  547         break;
  548 
  549       RandomWait();
  550     } while ( --loop != 0 );
  551 
  552 
  553 #ifdef DEBUGBeaming
  554     // Indicate every beaming
  555     setLEDG();
  556 #endif
  557 
  558     // STD TX
  559     // !!! Note: we expect that the aggregating repeaters can RX at STD mode !!!
  560     setRFmode( _TX_STD );
  561 
  562     // Force not routed packet to be sent from N by DPA API
  563     NonroutedRfTxDpaPacket = TRUE;
  564 
  565     // Prepare off-line sensor beaming packet
  566 
  567     // HW profile ID
  568     _HWPID = _HWPID_;
  569 
  570     // No DPA Params used
  571     _DpaParams = 0;
  572 
  573     // Beaming is broadcast
  574     _NADR = BROADCAST_ADDRESS;
  575     _NADRhigh = 0;
  576 
  577     // Prepare sensor packet type and quantity data
  578     _PNUM = PNUM_STD_SENSORS;
  579     _PCMD = PCMD_STD_SENSORS_READ_TYPES_AND_FRC_VALUES | RESPONSE_FLAG;
  580 
  581     _DpaDataLength = 1 + 2/*EXTRA_LOW_VOLTAGE*/ + 1 + 2/*TEMPERATURE*/;
  582 
  583     // TX DPA message with zero DPA Value and asynchronous
  584     // Note: Use DpaValue = 0x01 to indicate asynchronous i.e. non-regular beaming
  585     DpaApiRfTxDpaPacket( 0x00 /*DpaValue*/, 0 );
  586 
  587     // Measure voltage just after TX
  588     Get_ExtraLowVoltage();
  589 
  590     // Do a sleep between two beamings
  591 #ifndef DEBUGBeaming
  592     loop = 60;
  593 #else
  594     loop = 5;
  595 #endif
  596     FirstDpaApiSleep = TRUE;
  597     do
  598     {
  599       _DpaApiSleep( WDTCON_1s );
  600 
  601 #ifndef DpaEvent_MenuActivated
  602       if ( buttonPressed )
  603       {
  604         // Button indication
  605         setLEDG();
  606         // No more sleeps
  607         _DpaApiAfterSleep();
  608         // Restore RF settings
  609         DpaApiSetRfDefaults();
  610         // Wait for button release
  611         ReleaseButton();
  612         // Start inactivity timer
  613         startCapture();
  614         // End of button indication
  615         stopLEDG();
  616         // Abort beaming
  617         return;
  618       }
  619 #else
  620       uns8 menuAndItem = DpaApiMenu( DMENU_Beaming, 0/*Beaming DPA menu is not customized*/ );
  621       switch ( menuAndItem )
  622       {
  623         // ConnectivityCheck
  624         case MakeDMenuAndItem( DMENU_Beaming, DMENU_Item_ConnectivityCheck ):
  625           // Stop beaming sleeps
  626           _DpaApiAfterSleep();
  627           // Voluntary indication of the TestRange execution
  628           pulsingLEDR();
  629           // Repeaters to test
  630           clearBufferINFO();
  631           bufferINFO[0 / 8] = 0b1111.1110;   // 1...7
  632           // Do the test and result indication
  633           DpaApiMenuIndicateResult( DpaApiLocalFrc( FRC_Ping, TX_POWER_MAX ) );
  634           // Continue regular beaming sleeps
  635           FirstDpaApiSleep = TRUE;
  636           break;
  637 
  638           // Other menu items
  639         default:
  640           // Stop beaming sleeps
  641           _DpaApiAfterSleep();
  642           // Execute menu
  643           DpaApiMenuExecute( menuAndItem );
  644           // Continue regular beaming sleeps
  645           FirstDpaApiSleep = TRUE;
  646           break;
  647 
  648           // No menu item was selected
  649         case MakeDMenuAndItem( DMENU_Beaming, DMENU_Item_None ):
  650           break;
  651       }
  652 #endif
  653     } while ( --loop != 0 );
  654     // No more sleeps
  655     _DpaApiAfterSleep();
  656   }
  657 }
  658 
  659 //############################################################################################
  660 // Uncomment the following includes if the respective library is needed
  661 //#include "NFC.c"
  662 
  663 // 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)
  664 #include "DPAcustomHandler.h"
  665 //############################################################################################