1 // *********************************************************************
    2 //   Custom DPA Handler code example - Local FRC Controller            *
    3 // *********************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-LocalFRC-Controller.c,v $
    7 // Version: $Revision: 1.11 $
    8 // Date:    $Date: 2021/05/07 11:09:28 $
    9 //
   10 // Revision history:
   11 //   2020/09/03  Release for DPA 4.15
   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 
   20 // Default DPA header (modify the path according to your setup)
   21 #include "DPA.h"
   22 // Default Custom DPA Handler header (modify the path according to your setup)
   23 #include "DPAcustomHandler.h"
   24 // IQRF standards header (modify the path according to your setup)
   25 #include "Standard\IQRFstandard.h"
   26 
   27 //############################################################################################
   28 
   29 // This example implements configurable Local FRC Controller
   30 
   31 // When a IQRF button is pressed, the controller sends Local FRC command to switch on/off configurable FRC commands to the selected [Ns]
   32 
   33 // Structure with the controller settings stored at EEPROM from address 0
   34 typedef struct
   35 {
   36   // Selected nodes (actuators)
   37   uns8  Nodes[sizeof( _DpaMessage.PerFrcSendSelective_Request.SelectedNodes )];
   38   // RF power used
   39   uns8  RfPower;
   40   // Number of retries if all Ns do not respond
   41   uns8  Retries;
   42   // Auto power-off time [10 ms] (0 => no auto power-off)
   43   uns16 PowerOffTime;
   44   // Local FRC command used
   45   uns8  FrcCommand;
   46   // ON and OFF user data for the FRC command, 1st byte is the total data length including the length byte
   47   uns8  OnOffData[0];
   48 } TLocalFrcCtrl;
   49 
   50 //############################################################################################
   51 
   52 #pragma cdata[ __EESTART + PERIPHERAL_EEPROM_START ] = \
   53 /* uns8  Nodes[sizeof( _DpaMessage.PerFrcSendSelective_Request.SelectedNodes )]; */ \
   54 /* example: only N#1 is selected */ \
   55 0x02, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, \
   56 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, \
   57 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, \
   58 /* uns8  RfPower; */ \
   59 1, \
   60 /* uns8  Retries; */ \
   61 1, \
   62 /* uns16 PowerOffTime; */ \
   63 ( 10 * (uns16)100 ) & 0xFF, ( 10 * (uns16)100 ) >> 8 /* example: 10 s */
   64 
   65 // DALI Example using FRC_STD_DALI_SEND
   66 #if 0
   67 #pragma cdata[ __EESTART + PERIPHERAL_EEPROM_START + offsetof( TLocalFrcCtrl, FrcCommand )] = \
   68 /* uns8  FrcCommand; */ \
   69 FRC_STD_DALI_SEND, \
   70 /* uns8  OnOffData[2 * ( sizeof( uns8 ) + sizeof( _DpaMessage.PerFrcSendSelective_Request.UserData ) )]; */ \
   71 /* ON  */ 5, PNUM_STD_DALI, 0xFF, 0x05, 0, \
   72 /* OFF */ 5, PNUM_STD_DALI, 0xFF, 0x00, 0
   73 #endif
   74 
   75 // LEDR Example using FRC_AcknowledgedBroadcastBits
   76 #if 1
   77 #pragma cdata[ __EESTART + PERIPHERAL_EEPROM_START + offsetof( TLocalFrcCtrl, FrcCommand )] = \
   78 /* uns8  FrcCommand; */ \
   79 FRC_AcknowledgedBroadcastBits, \
   80 /* uns8  OnOffData[2 * ( sizeof( uns8 ) + sizeof( _DpaMessage.PerFrcSendSelective_Request.UserData ) )]; */ \
   81 /* ON  */ 6, 5, PNUM_LEDG, CMD_LED_SET_ON,  HWPID_DoNotCheck & 0xFF, HWPID_DoNotCheck >> 8, \
   82 /* OFF */ 6, 5, PNUM_LEDG, CMD_LED_SET_OFF, HWPID_DoNotCheck & 0xFF, HWPID_DoNotCheck >> 8
   83 #endif
   84 
   85 //############################################################################################
   86 
   87 // The FRC settings stored in the bufferINFo after read from the EEPROM
   88 shadowDef TLocalFrcCtrl LocalFrcCtrl @ bufferINFO;
   89 
   90 // Calculates the structure field address in the EEPROM
   91 #define LocalFrcCtrlEeAddr( field ) ( offsetof( TLocalFrcCtrl, field ) + PERIPHERAL_EEPROM_START )
   92 
   93 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   94 //############################################################################################
   95 bit CustomDpaHandler()
   96 //############################################################################################
   97 {
   98   // Handler presence mark
   99   clrwdt();
  100 
  101   // Detect DPA event to handle (unused event handlers can be commented out or even deleted)
  102   switch ( GetDpaEvent() )
  103   {
  104     // -------------------------------------------------
  105     case DpaEvent_Interrupt:
  106       // Do an extra quick background interrupt work
  107       return Carry;
  108 
  109       // -------------------------------------------------
  110     case DpaEvent_Idle:
  111       // Do a quick background work when RF packet is not received
  112     {
  113       // On/Off actuator state
  114       static bit offOrOn;
  115       // On start time from captureTicks()
  116       static uns16 timerStart;
  117       // Auto power-off time in ticks, zero if no timer is running
  118       static uns16 timerValue;
  119 
  120       // Check the auto power-off timer if it is running
  121       if ( timerValue != 0 )
  122       {
  123         // Timer is over?
  124         captureTicks();
  125         param3 -= timerStart;
  126         if ( param3 > timerValue )
  127         {
  128           // Yes, switch off the actuator
  129           offOrOn = FALSE;
  130           goto _sendLocalFrc;
  131         }
  132       }
  133 
  134       // If the button is pressed for some time, send appropriate Local FRC command to switch on/off the actuator
  135       static uns8 buttonCnt;
  136       if ( buttonPressed )
  137       {
  138         // Button was longer pressed?
  139 #define BUTTON_CNT  8
  140         if ( buttonCnt < BUTTON_CNT && ++buttonCnt == BUTTON_CNT )
  141         {
  142           // Toggle actuator's state
  143           offOrOn = !offOrOn;
  144 
  145 _sendLocalFrc:
  146           // Read the FRC structure up to the FRC user data
  147           eeReadData( LocalFrcCtrlEeAddr( Nodes ), offsetof( TLocalFrcCtrl, OnOffData ) );
  148           // Read retries counter
  149           uns8 retries = LocalFrcCtrl.Retries;
  150           // Read timer value
  151           timerValue = LocalFrcCtrl.PowerOffTime;
  152           // Do local FRC
  153           do
  154           {
  155             // Indicated LED and get the FRC user data address in the EEPROM according the ON or OFF state
  156             if ( offOrOn )
  157             {
  158               setLEDG();
  159               // Store timer's start time
  160               captureTicks();
  161               timerStart = param3;
  162               // FRC-On user data offset
  163               W = LocalFrcCtrlEeAddr( OnOffData ) + sizeof( uns8 );
  164             }
  165             else
  166             {
  167               stopLEDG();
  168               // No auto power-off timer when switched off
  169               timerValue = 0;
  170               // FRC-Off user data offset
  171               W = eeReadByte( LocalFrcCtrlEeAddr( OnOffData ) ) + LocalFrcCtrlEeAddr( OnOffData ) + sizeof( uns8 );
  172             }
  173 
  174             // Read the FRC user data
  175             eeReadData( W, sizeof( _DpaMessage.PerFrcSendSelective_Request.UserData ) );
  176             setFSR0( _FSR_INFO );
  177             // And copy the FRC user data to the FRC data structure
  178             copyMemoryBlock( FSR0, DataInSendFRC, sizeof( _DpaMessage.PerFrcSendSelective_Request.UserData ) );
  179 
  180             // Read the starting rest the FRC structure up to the FRC user data
  181             eeReadData( LocalFrcCtrlEeAddr( Nodes ), offsetof( TLocalFrcCtrl, OnOffData ) );
  182 
  183             // Set configured RF power
  184             setRFpower( LocalFrcCtrl.RfPower );
  185             // Now call the local FRC and exit "retry loop" if all nodes answered
  186             if ( DpaApiLocalFrc( LocalFrcCtrl.FrcCommand, LocalFrcCtrl.RfPower ) == param2 )
  187               break;
  188 
  189             // More retries? Indicate it.
  190             pulseLEDR();
  191             // Just for sure...
  192             clrwdt();
  193           } while ( --retries != (uns8)-1 );
  194 
  195           // Note: workaround to resolve the missing internal reset of the _localFRC variable at IQRF OS 4.04D
  196           _localFRC = FALSE;
  197 
  198           // Restore original configured RF power
  199           DpaApiSetRfDefaults();
  200         }
  201       }
  202       else
  203         // Button is not pressed
  204         buttonCnt = 0;
  205 
  206       break;
  207     }
  208 
  209     // -------------------------------------------------
  210     case DpaEvent_DpaRequest:
  211       // Called to interpret DPA request for peripherals
  212       if ( IsDpaEnumPeripheralsRequest() )
  213       {
  214         // -------------------------------------------------
  215         // Peripheral enumeration
  216         _DpaMessage.EnumPeripheralsAnswer.HWPID |= 0xF2CF;
  217 
  218 DpaHandleReturnTRUE:
  219         return TRUE;
  220       }
  221 
  222       break;
  223   }
  224 
  225 DpaHandleReturnFALSE:
  226   return FALSE;
  227 }
  228 
  229 //############################################################################################
  230 // 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)
  231 #include "DPAcustomHandler.h"
  232 //############################################################################################