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.26 $
    8 // Date:    $Date: 2023/03/07 08:03:13 $
    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 
   70 #ifndef DpaEvent_MenuActivated
   71       if ( amIBonded() )
   72       {
   73         // To detect long button press
   74         static uns8 buttonCnt;
   75 
   76         if ( !buttonPressed )
   77           buttonCnt = 0;
   78         else
   79         {
   80           // Note: when run at LP mode, than the press time must be adjusted for shorter counts that even depends on LPtoutRF value
   81           if ( ++buttonCnt == 0 )
   82 #else
   83       if ( beamOnceAtIdle )
   84       {
   85         beamOnceAtIdle = FALSE;
   86 #endif
   87         { // Beam once
   88             // Indicate button was pressed for the longer time and then wait for its release
   89             setLEDR();
   90             do
   91             {
   92               clrwdt();
   93             } while ( buttonPressed );
   94             stopLEDR();
   95 
   96             // Prepare off-line sensor packet
   97 
   98             // No DPA Params used
   99             _DpaParams = 0;
  100 
  101             // Beaming is broadcast (could be unicast too)
  102             _NADR = BROADCAST_ADDRESS;
  103             _NADRhigh = 0;
  104 
  105             // Prepare sensor packet type and quantity data
  106 
  107             _PNUM = PNUM_STD_SENSORS;
  108             _PCMD = PCMD_STD_SENSORS_READ_TYPES_AND_FRC_VALUES | RESPONSE_FLAG;
  109             // HW profile ID
  110             _HWPID = _HWPID_;
  111 
  112             { // 1st sensor/quantity
  113               // Fake "living" temperature value = NodeAddress + [0-15]/16;
  114               _DpaMessage.Request.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  115               shadowDef uns16 temperature @ ( &_DpaMessage.Request.PData[1] );
  116 #ifndef SENSOR_ERRORS
  117               temperature = (uns16)ntwADDR * 16;
  118               temperature |= ( Random.low8 & ( 16 - 1 ) );
  119               temperature |= 0x8000;
  120 #else
  121               temperature = FRC_STD_FRC_ERROR_VALUE;
  122 #endif
  123               // Length of the data inside DPA Request message
  124               _DpaDataLength = sizeof( uns8 ) + sizeof( uns16 );
  125             }
  126 
  127             { // Optional 2nd sensor/quantity
  128               // Fake "living" humidity value = NodeAddress + [0-1]/2;
  129               _DpaMessage.Request.PData[3] = STD_SENSOR_TYPE_HUMIDITY;
  130 #ifndef SENSOR_ERRORS
  131               _DpaMessage.Request.PData[4] = 4 + ( ntwADDR & 0x3F ) * 2;
  132               _DpaMessage.Request.PData[4] |= Random.high8 & 0x01;
  133 #else
  134               _DpaMessage.Request.PData[4] = FRC_STD_FRC_ERROR_VALUE;
  135 #endif
  136               // Length of the data inside DPA Request message
  137               _DpaDataLength += sizeof( uns8 ) + sizeof( uns8 );
  138             }
  139 
  140             { // Optional 3rd sensor/quantity
  141               // Fake CO2 value
  142               _DpaMessage.Request.PData[5] = STD_SENSOR_TYPE_CO2;
  143               shadowDef uns16 co2 @ ( &_DpaMessage.Request.PData[6] );
  144 #ifndef SENSOR_ERRORS
  145               co2 = 2345 + 4;
  146 #else
  147               co2 = FRC_STD_FRC_ERROR_VALUE;
  148 #endif
  149               // Length of the data inside DPA Request message
  150               _DpaDataLength += sizeof( uns8 ) + sizeof( uns16 );
  151             }
  152 
  153             { // Optional 4th sensor/quantity
  154               // Fake Binary30
  155               _DpaMessage.Request.PData[8] = STD_SENSOR_TYPE_BINARYDATA30;
  156               shadowDef uns32 bin30 @ ( &_DpaMessage.Request.PData[9] );
  157 #ifndef SENSOR_ERRORS
  158 #if !defined( __CC5XFREE__ ) // CC5X free edition does not support 32bit assignment
  159               bin30 = 0x3456789A + 4;
  160 #else
  161               bin30.low16 = ( 0x3456789A + 4 ) & 0xFfFf;
  162               bin30.high16 = ( 0x3456789A + 4 ) >> 16;
  163 #endif
  164 #else
  165 #if !defined( __CC5XFREE__ ) // CC5X free edition does not support 32bit assignment
  166               bin30 = FRC_STD_FRC_ERROR_VALUE;
  167 #else
  168               bin30.low16 = FRC_STD_FRC_ERROR_VALUE;
  169               bin30.high16 = 0;
  170 #endif
  171 #endif
  172               // Length of the data inside DPA Request message
  173               _DpaDataLength += sizeof( uns8 ) + sizeof( uns32 );
  174             }
  175 
  176             { // Optional 5th sensor/quantity
  177               // Fake Binary7
  178               _DpaMessage.Request.PData[13] = STD_SENSOR_TYPE_BINARYDATA7;
  179 #ifndef SENSOR_ERRORS
  180               _DpaMessage.Request.PData[14] = ( ntwADDR & 0x7F ) + 4;
  181 #else
  182               _DpaMessage.Request.PData[14] = FRC_STD_FRC_ERROR_VALUE;
  183 #endif
  184               // Length of the data inside DPA Request message
  185               _DpaDataLength += sizeof( uns8 ) + sizeof( uns8 );
  186             }
  187 
  188             // Do simplified LBT
  189             uns8 loop = 3;
  190             do
  191             {
  192               if ( !checkRF( RxFilter + 10 ) )
  193                 break;
  194 
  195               // Do some wait (better to do a random time sleep)
  196               waitMS( 5 );
  197             } while ( --loop != 0 );
  198 
  199             // Force not routed packet to be sent from N by DPA API
  200             NonroutedRfTxDpaPacket = TRUE;
  201 
  202             // TX DPA message with zero DPA Value and asynchronous
  203             // Note: Use DpaValue = 0x01 to indicate asynchronous i.e. non-regular beaming
  204             DpaApiRfTxDpaPacket( 0 /*DpaValue*/, 0 );
  205             // Beaming indication
  206             pulseLEDG();
  207           }
  208         }
  209 #ifndef DpaEvent_MenuActivated
  210       }
  211 #endif
  212       break;
  213     }
  214 
  215     // -------------------------------------------------
  216 #ifdef DpaEvent_MenuActivated
  217     case DpaEvent_MenuActivated:
  218       // Called to customize DPA menu
  219       // https://doc.iqrf.org/DpaTechGuide/pages/menuactivated.html
  220 
  221       switch ( userReg1 )
  222       {
  223         case DMENU_Online:
  224           userReg1 = DMENU_Item_Implemented_Beaming;
  225           goto DpaHandleReturnTRUE; // return TRUE to allow customizing menu specified by userReg1
  226       }
  227       break;
  228 #endif
  229 
  230       // -------------------------------------------------
  231 #ifdef DpaEvent_MenuItemSelected
  232     case DpaEvent_MenuItemSelected:
  233       // Called to indicate "OK" or "Error" for selected menu item
  234       // https://doc.iqrf.org/DpaTechGuide/pages/menuitemselected.html
  235 
  236       switch ( userReg1 )
  237       {
  238         case MakeDMenuAndItem( DMENU_Online, DMENU_Item_Beaming ):
  239           if ( amIBonded() )
  240           {
  241             beamOnceAtIdle = TRUE;
  242             goto DpaHandleReturnTRUE; // return TRUE to indicate "OK" for menu item specified by userReg1, otherwise to indicate Error
  243           }
  244           break;
  245       }
  246       break;
  247 #endif
  248 
  249       // -------------------------------------------------
  250     case DpaEvent_DpaRequest:
  251       // Called to interpret DPA request for peripherals
  252       if ( IsDpaEnumPeripheralsRequest() )
  253       {
  254         // -------------------------------------------------
  255         // Peripheral enumeration
  256         _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_;
  257         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0;
  258 
  259 DpaHandleReturnTRUE:
  260         return TRUE;
  261       }
  262 
  263       break;
  264   }
  265 
  266 DpaHandleReturnFALSE:
  267   return FALSE;
  268 }
  269 
  270 //############################################################################################
  271 // 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)
  272 #include "DPAcustomHandler.h"
  273 //############################################################################################