1 // *********************************************************************
    2 //   Custom DPA Handler - Beaming example                              *
    3 // *********************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-SensorBeaming.c,v $
    7 // Version: $Revision: 1.27 $
    8 // Date:    $Date: 2026/02/11 13:54:37 $
    9 //
   10 // Revision history:
   11 //   2023/03/07  Release for DPA 4.30
   12 //   2022/02/24  Release for DPA 4.17
   13 //   2020/09/03  Release for DPA 4.15
   14 //
   15 // *********************************************************************
   16 
   17 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   18 
   19 /*
   20 * This is public example of the beaming sensor code.
   21 * The actual beamed quantities' values are fake. Please see the code below.
   22 * TR7xD: After the button is pressed for a longer time the LEDR pulses and data are beamed.
   23 * TR7xG: After selecting 1st DPA menu item Beaming the data are once beamed.
   24 */
   25 
   26 // Default IQRF include (modify the path according to your setup)
   27 #include "IQRF.h"
   28 
   29 // Default DPA header (modify the path according to your setup)
   30 #include "DPA.h"
   31 // Default Custom DPA Handler header (modify the path according to your setup)
   32 #include "DPAcustomHandler.h"
   33 // IQRF standards header (modify the path according to your setup)
   34 #include "standard/IQRFstandard.h"
   35 #include "standard/IQRF_HWPID.h"
   36 
   37 // This HWPID
   38 #define _HWPID_             0x123F
   39 
   40 // Define to return sensors in error
   41 //#define SENSOR_ERRORS
   42 
   43 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   44 //############################################################################################
   45 bit CustomDpaHandler()
   46 //############################################################################################
   47 {
   48 #pragma updateBank default = UserBank_01
   49 
   50 #ifdef DpaEvent_MenuActivated
   51   static beamOnceAtIdle;
   52 #endif
   53 
   54   // Handler presence mark
   55   clrwdt();
   56 
   57   // Detect DPA event to handle (unused event handlers can be commented out or even deleted)
   58   switch ( GetDpaEvent() )
   59   {
   60     // -------------------------------------------------
   61     case DpaEvent_Interrupt:
   62       // Do an extra quick background interrupt work
   63       return Carry;
   64 
   65       // -------------------------------------------------
   66     case DpaEvent_Idle:
   67       // Do a quick background work when RF packet is not received
   68     {
   69 #ifndef DpaEvent_MenuActivated
   70       if ( amIBonded() )
   71       {
   72         // To detect long button press
   73         static uns8 buttonCnt;
   74 
   75         if ( !buttonPressed )
   76           buttonCnt = 0;
   77         else
   78         {
   79           // Note: when run at LP mode, than the press time must be adjusted for shorter counts that even depends on LPtoutRF value
   80           if ( ++buttonCnt == 0 )
   81 #else
   82       if ( beamOnceAtIdle )
   83       {
   84         beamOnceAtIdle = FALSE;
   85 #endif
   86         { // Beam once
   87             // Indicate button was pressed for the longer time and then wait for its release
   88           setLEDR();
   89           do
   90           {
   91             clrwdt();
   92           } while ( buttonPressed );
   93           stopLEDR();
   94 
   95           // Set STD RF mode
   96           uns8 rfmode = RFmodeByte;
   97           setRFmode( _TX_STD );
   98 
   99           // Prepare off-line sensor packet
  100 
  101           // No DPA Params used
  102           _DpaParams = 0;
  103 
  104           // Beaming is broadcast (could be unicast too)
  105           _NADR = BROADCAST_ADDRESS;
  106           _NADRhigh = 0;
  107 
  108           // Prepare sensor packet type and quantity data
  109 
  110           _PNUM = PNUM_STD_SENSORS;
  111           _PCMD = PCMD_STD_SENSORS_READ_TYPES_AND_FRC_VALUES | RESPONSE_FLAG;
  112           // HW profile ID
  113           _HWPID = _HWPID_;
  114 
  115           { // 1st sensor/quantity
  116             // Fake "living" temperature value = NodeAddress + [0-15]/16;
  117             _DpaMessage.Request.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  118             shadowDef uns16 temperature @ ( &_DpaMessage.Request.PData[1] );
  119 #ifndef SENSOR_ERRORS
  120             temperature = (uns16)ntwADDR * 16;
  121             temperature |= ( Random.low8 & ( 16 - 1 ) );
  122             temperature |= 0x8000;
  123 #else
  124             temperature = FRC_STD_FRC_ERROR_VALUE;
  125 #endif
  126             // Length of the data inside DPA Request message
  127             _DpaDataLength = sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_TEMPERATURE );
  128           }
  129 
  130           { // Optional 2nd sensor/quantity
  131             // Fake "living" humidity value = NodeAddress + [0-1]/2;
  132             _DpaMessage.Request.PData[3] = STD_SENSOR_TYPE_HUMIDITY;
  133 #ifndef SENSOR_ERRORS
  134             _DpaMessage.Request.PData[4] = 4 + ( ntwADDR & 0x3F ) * 2;
  135             _DpaMessage.Request.PData[4] |= Random.high8 & 0x01;
  136 #else
  137             _DpaMessage.Request.PData[4] = FRC_STD_FRC_ERROR_VALUE;
  138 #endif
  139             // Length of the data inside DPA Request message
  140             _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_HUMIDITY );
  141           }
  142 
  143           { // Optional 3rd sensor/quantity
  144             // Fake CO2 value
  145             _DpaMessage.Request.PData[5] = STD_SENSOR_TYPE_CO2;
  146             shadowDef uns16 co2 @ ( &_DpaMessage.Request.PData[6] );
  147 #ifndef SENSOR_ERRORS
  148             co2 = 2345 + 4;
  149 #else
  150             co2 = FRC_STD_FRC_ERROR_VALUE;
  151 #endif
  152             // Length of the data inside DPA Request message
  153             _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_CO2 );
  154           }
  155 
  156           { // Optional 4th sensor/quantity
  157             // Fake Binary30
  158             _DpaMessage.Request.PData[8] = STD_SENSOR_TYPE_BINARYDATA30;
  159             shadowDef uns32 bin30 @ ( &_DpaMessage.Request.PData[9] );
  160 #ifndef SENSOR_ERRORS
  161 #if !defined( __CC5XFREE__ ) // CC5X free edition does not support 32bit assignment
  162             bin30 = 0x3456789A + 4;
  163 #else
  164             bin30.low16 = ( 0x3456789A + 4 ) & 0xFfFf;
  165             bin30.high16 = ( 0x3456789A + 4 ) >> 16;
  166 #endif
  167 #else
  168 #if !defined( __CC5XFREE__ ) // CC5X free edition does not support 32bit assignment
  169             bin30 = FRC_STD_FRC_ERROR_VALUE;
  170 #else
  171             bin30.low16 = FRC_STD_FRC_ERROR_VALUE;
  172             bin30.high16 = 0;
  173 #endif
  174 #endif
  175             // Length of the data inside DPA Request message
  176             _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_BINARYDATA30 );
  177           }
  178 
  179           { // Optional 5th sensor/quantity
  180             // Fake Binary7
  181             _DpaMessage.Request.PData[13] = STD_SENSOR_TYPE_BINARYDATA7;
  182 #ifndef SENSOR_ERRORS
  183             _DpaMessage.Request.PData[14] = ( ntwADDR & 0x7F ) + 4;
  184 #else
  185             _DpaMessage.Request.PData[14] = FRC_STD_FRC_ERROR_VALUE;
  186 #endif
  187             // Length of the data inside DPA Request message
  188             _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_BINARYDATA7 );
  189           }
  190 
  191           // Do simplified LBT
  192           uns8 loop = 3;
  193           do
  194           {
  195             if ( !checkRF( RxFilter + 10 ) )
  196               break;
  197 
  198             // Do some wait (better to do a random time sleep)
  199             waitMS( 5 );
  200           } while ( --loop != 0 );
  201 
  202           // Force not routed packet to be sent from N by DPA API
  203           NonroutedRfTxDpaPacket = TRUE;
  204 
  205           // TX DPA message with zero DPA Value and asynchronous
  206           // Note: Use DpaValue = 0x01 to indicate asynchronous i.e. non-regular beaming
  207           DpaApiRfTxDpaPacket( 0 /*DpaValue*/, 0 );
  208           // Beaming indication
  209           pulseLEDG();
  210           // Restore RF mode
  211           setRFmode( rfmode );
  212         }
  213         }
  214 #ifndef DpaEvent_MenuActivated
  215       }
  216 #endif
  217     break;
  218     }
  219 
  220       // -------------------------------------------------
  221     case DpaEvent_FrcValue:
  222       // Called to get FRC value
  223       // https://doc.iqrf.org/DpaTechGuide/pages/frcvalue.html
  224 
  225       // Do not respond directly to the sensor FRCs
  226       if ( DataOutBeforeResponseFRC[0] == PNUM_STD_SENSORS )
  227       {
  228         // Test for un-supported FRC commands
  229         switch ( _PCMD )
  230         {
  231           case FRC_STD_SENSORS_BIT:
  232           case FRC_STD_SENSORS_1B:
  233           case FRC_STD_SENSORS_2B:
  234           case FRC_STD_SENSORS_4B:
  235 
  236             // Let's wait longer than FRC response time to cause responseFRC timeout to return nothing at all
  237             do {
  238               clrwdt();
  239             } while ( isDelay() );
  240 
  241             break;
  242         }
  243       }
  244       break;
  245 
  246       // -------------------------------------------------
  247 #ifdef DpaEvent_MenuActivated
  248     case DpaEvent_MenuActivated:
  249       // Called to customize DPA menu
  250       // https://doc.iqrf.org/DpaTechGuide/pages/menuactivated.html
  251 
  252       switch ( userReg1 )
  253       {
  254         case DMENU_Online:
  255           userReg1 = DMENU_Item_Implemented_Beaming;
  256           goto DpaHandleReturnTRUE; // return TRUE to allow customizing menu specified by userReg1
  257       }
  258       break;
  259 #endif
  260 
  261       // -------------------------------------------------
  262 #ifdef DpaEvent_MenuItemSelected
  263     case DpaEvent_MenuItemSelected:
  264       // Called to indicate "OK" or "Error" for selected menu item
  265       // https://doc.iqrf.org/DpaTechGuide/pages/menuitemselected.html
  266 
  267       switch ( userReg1 )
  268       {
  269         case MakeDMenuAndItem( DMENU_Online, DMENU_Item_Beaming ):
  270           if ( amIBonded() )
  271           {
  272             beamOnceAtIdle = TRUE;
  273             goto DpaHandleReturnTRUE; // return TRUE to indicate "OK" for menu item specified by userReg1, otherwise to indicate Error
  274           }
  275           break;
  276       }
  277       break;
  278 #endif
  279 
  280       // -------------------------------------------------
  281     case DpaEvent_DpaRequest:
  282       // Called to interpret DPA request for peripherals
  283       if ( IsDpaEnumPeripheralsRequest() )
  284       {
  285         // -------------------------------------------------
  286         // Peripheral enumeration
  287         _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_;
  288         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0;
  289 
  290 DpaHandleReturnTRUE:
  291         return TRUE;
  292       }
  293 
  294       break;
  295   }
  296 
  297 DpaHandleReturnFALSE:
  298 return FALSE;
  299 }
  300 
  301 //############################################################################################
  302 // 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)
  303 #include "DPAcustomHandler.h"
  304 //############################################################################################