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