1 // *********************************************************************
    2 //   Main Custom DPA Handler header                                    *
    3 // *********************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: DPAcustomHandler.h,v $
    7 // Version: $Revision: 1.174 $
    8 // Date:    $Date: 2026/05/18 09:55:27 $
    9 //
   10 // Revision history:
   11 //   2025/05/30  Release for DPA 4.33
   12 //   2024/11/05  Release for DPA 4.32
   13 //   2024/04/17  Release for DPA 4.31
   14 //   2023/03/07  Release for DPA 4.30
   15 //   2022/10/05  Release for DPA 4.18
   16 //   2022/02/24  Release for DPA 4.17
   17 //   2021/08/20  Release for DPA 4.16
   18 //   2020/09/03  Release for DPA 4.15
   19 //   2020/04/03  Release for DPA 4.14
   20 //   2020/02/27  Release for DPA 4.13
   21 //   2020/01/09  Release for DPA 4.12
   22 //   2019/12/11  Release for DPA 4.11
   23 //   2019/10/09  Release for DPA 4.10
   24 //   2019/06/12  Release for DPA 4.03
   25 //   2019/06/03  Release for DPA 4.02
   26 //   2019/03/07  Release for DPA 4.01
   27 //   2019/01/10  Release for DPA 4.00
   28 //   2018/10/25  Release for DPA 3.03
   29 //   2017/11/16  Release for DPA 3.02
   30 //   2017/08/14  Release for DPA 3.01
   31 //   2017/03/13  Release for DPA 3.00
   32 //   2016/09/12  Release for DPA 2.28
   33 //   2016/04/14  Release for DPA 2.27
   34 //   2016/03/03  Release for DPA 2.26
   35 //   2016/01/21  Release for DPA 2.25
   36 //   2015/12/01  Release for DPA 2.24
   37 //   2015/10/23  Release for DPA 2.23
   38 //   2015/09/25  Release for DPA 2.22
   39 //   2015/09/03  Release for DPA 2.21
   40 //   2015/08/05  Release for DPA 2.20
   41 //   2014/10/31  Release for DPA 2.10
   42 //   2014/04/30  Release for DPA 2.00
   43 //   2013/10/03  Release for DPA 1.00
   44 //
   45 // *********************************************************************
   46 
   47 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   48 // IQRF Standards documentation https://doc.iqrf.org/
   49 
   50 #ifndef _CUSTOM_DPA_HANDLER_
   51 #define _CUSTOM_DPA_HANDLER_
   52 
   53 //############################################################################################
   54 // 1st include
   55 
   56 // Custom DPA Handler routine declaration
   57 bit CustomDpaHandler();
   58 
   59 // Various DPA flags shared between DPA and Custom DPA Handler
   60 uns8 DpaFlags @ usedBank4[0];
   61 
   62 // [C][N] TRUE if I2C timeout occurred at the last DpaApiI2C?() call
   63 bit I2CwasTimeout @ DpaFlags.0;
   64 // [N] Flag for the 1st DpaApiSleep
   65 bit FirstDpaApiSleep @ DpaFlags.1;
   66 
   67 #ifdef COORDINATOR_CUSTOM_HANDLER
   68 // [C] TRUE if interface master is not connected (detected)
   69 bit IFaceMasterNotConnected @ DpaFlags.2;
   70 #endif
   71 // [N] DPA by interface notification is sent also when there was a "reading" like DPA request
   72 bit EnableIFaceNotificationOnRead @ DpaFlags.3;
   73 // [N] TRUE when node was just bonded using default bonding procedure
   74 bit NodeWasBonded @ DpaFlags.4;
   75 // [N] When TRUE, then next call of DpaApiRfTxDpaPacket sends non-routed packet
   76 bit NonroutedRfTxDpaPacket @ DpaFlags.7;
   77 
   78 // [C] Ticks (decrementing) counter usable for timing in the coordinator's Customer DPA Handler
   79 uns16 DpaTicks @ usedBank4[1];
   80 // [N] toutRF for LP mode, read from configuration memory after reset
   81 uns8 LPtoutRF @ usedBank4[3];
   82 // DPA Request/Response HWPID
   83 uns16 _HWPID @ usedBank4[4];
   84 // Identifies type of reset (stored at UserReg0 upon module reset). See Reset chapter at IQRF User's Guide for more information
   85 uns8 ResetType @ usedBank4[6];
   86 // User DPA Values to return
   87 uns8 UserDpaValue @ usedBank4[7];
   88 // Network depth of the DPA request/response, increases on bridging, decreases on back-bridging
   89 uns8 NetDepth @ usedBank4[8];
   90 // TRUE when node was at DPA Service Mode after last boot
   91 bit DSMactivated @ usedBank4[9].0;
   92 // If set to TRUE, then LP RX mode in the main loop can be terminated by pin, see _RLPMAT
   93 bit LpRxPinTerminate @ usedBank4[9].1;
   94 // If set to TRUE, then [C] executes asynchronous DPA requests received from [N]
   95 bit AsyncReqAtCoordinator @ usedBank4[9].2;
   96 // RX filter used at the DPA main loop checkRF call
   97 uns8 RxFilter @ usedBank4[11];
   98 // Countdown variable for button bonding before going to deep sleep
   99 uns16 BondingSleepCountdown @ usedBank4[12];
  100 #define BONDING_SLEEP_COUNTDOWN_UNIT  290
  101 // Non-zero pseudo-random value, read-only, updated on every Reset and Idle event, at [N] only.
  102 uns16 Random @ usedBank4[14];
  103 // DPA value from the received packet or just to be sent to the interface.
  104 uns8 DpaValue @ usedBank4[16];
  105 // If non-zero then timeout value for DpaApiI2C?() calls
  106 uns8 I2Ctimeout @ usedBank4[17];
  107 #if !defined( TR7xD )
  108 // Current DPA Menu
  109 uns8 CurrentDpaMenu @  usedBank4[19];
  110 #endif
  111 
  112 // Macro to return an error from the peripheral handler. If the code size is not an issue this macro is the right choice.
  113 #define DpaApiReturnPeripheralError(error) do { \
  114     DpaApiSetPeripheralError( error ); \
  115     return Carry; \
  116   } while( 0 )
  117 
  118 // DPA API functions, see documentation for details
  119 #define DpaApiRfTxDpaPacket( dpaValue, netDepthAndFlags ) DpaApiEntry( dpaValue, netDepthAndFlags, DPA_API_RFTX_DPAPACKET )
  120 #define DpaApiReadConfigByte( index )                     DpaApiEntry( index, param3.low8, DPA_API_READ_CONFIG_BYTE )
  121 #define DpaApiLocalRequest()                              DpaApiEntry( param2, param3.low8, DPA_API_LOCAL_REQUEST )
  122 #define DpaApiSetPeripheralError( error )                 DpaApiEntry( error, param3.low8, DPA_API_SET_PERIPHERAL_ERROR )
  123 #define DpaApiSendToIFaceMaster( dpaValue, flags )        DpaApiEntry( dpaValue, flags, DPA_API_SEND_TO_IFACEMASTER )
  124 #define DpaApiSetRfDefaults()                             DpaApiEntry( param2, param3.low8, DPA_API_SET_RF_DEFAULTS )
  125 #define DpaApiLocalFrc( frcCommand, replyTxPower )        DpaApiEntry( frcCommand, replyTxPower, DPA_API_LOCAL_FRC )
  126 
  127 #define DpaApiLocalFrc_StackSaver( frcCommand, replyTxPower ) do { \
  128   param2 = frcCommand; \
  129   param3.low8 = replyTxPower; \
  130   W = DPA_API_LOCAL_FRC; \
  131   #asm \
  132     DW  __MOVLP( DPA_API_ADDRESS >> 8 ); \
  133     DW  __CALL( DPA_API_ADDRESS ); \
  134     DW  __MOVLP( CUSTOM_HANDLER_ADDRESS >> 8 ); \
  135   #endasm \
  136   } while(0)
  137 
  138 #define DpaApiCrc8( crc8, data )                          DpaApiEntry( crc8, data, DPA_API_CRC8 )
  139 #define DpaApiAggregateFrc()                              DpaApiEntry( param2, param3.low8, DPA_API_AGGREGATE_FRC )
  140 #define DpaApiSetOTK()                                    DpaApiEntry( param2, param3.low8, DPA_API_SET_OTK )
  141 #define DpaApiI2Cinit( frequency )                        DpaApiEntry( frequency, param3.low8, DPA_API_I2C_INIT )
  142 #define DpaApiI2Cstart( address )                         DpaApiEntry( address, param3.low8, DPA_API_I2C_START )
  143 #define DpaApiI2Cwrite( data )                            DpaApiEntry( data, param3.low8, DPA_API_I2C_WRITE )
  144 #define DpaApiI2Cread( ack )                              DpaApiEntry( ack, param3.low8, DPA_API_I2C_READ )
  145 #define DpaApiI2Cstop()                                   DpaApiEntry( param2, param3.low8, DPA_API_I2C_STOP )
  146 #define DpaApiI2CwaitForACK( address )                    DpaApiEntry( address, param3.low8, DPA_API_I2C_WAIT_FOR_ACK )
  147 #define DpaApiI2Cshutdown()                               DpaApiEntry( param2, param3.low8, DPA_API_I2C_SHUTDOWN )
  148 #define DpaApiI2CwaitForIdle()                            DpaApiEntry( param2, param3.low8, DPA_API_I2C_WAIT_FOR_IDLE )
  149 #define DpaApiSleep( wdtcon )                             DpaApiEntry( wdtcon, param3.low8, DPA_API_SLEEP )
  150 
  151 #define DpaApiSleep_StackSaver( wdtcon ) do { \
  152   param2 = wdtcon; \
  153   W = DPA_API_SLEEP; \
  154   #asm \
  155     DW  __MOVLP( DPA_API_ADDRESS >> 8 ); \
  156     DW  __CALL( DPA_API_ADDRESS ); \
  157     DW  __MOVLP( CUSTOM_HANDLER_ADDRESS >> 8 ); \
  158   #endasm \
  159   } while(0)
  160 
  161 #define DpaApiAfterSleep()                                DpaApiEntry( param2, param3.low8, DPA_API_AFTER_SLEEP )
  162 
  163 #define DpaApiAfterSleep_StackSaver() do { \
  164   W = DPA_API_AFTER_SLEEP; \
  165   #asm \
  166     DW  __MOVLP( DPA_API_ADDRESS >> 8 ); \
  167     DW  __CALL( DPA_API_ADDRESS ); \
  168     DW  __MOVLP( CUSTOM_HANDLER_ADDRESS >> 8 ); \
  169   #endasm \
  170   } while(0)
  171 
  172 #define DpaApiRandom()                                    DpaApiEntry( param2, param3.low8, DPA_API_RANDOM )
  173 
  174 #ifdef COORDINATOR_CUSTOM_HANDLER
  175 #define DpaApiRfTxDpaPacketCoordinator()                  DpaApiEntry( param2, param3.low8, DPA_API_COORDINATOR_RFTX_DPAPACKET )
  176 #endif
  177 
  178 #if !defined( TR7xD )
  179 #define DpaApiMenu( menu, flags )                         DpaApiEntry( menu, flags, DPA_API_MENU )
  180 #define DpaApiMenuIndicateResult( ok )                    DpaApiEntry( ok, param3.low8, DPA_API_MENU_INDICATE_RESULT )
  181 #define DpaApiMenuExecute( menuAndItem )                  DpaApiEntry( menuAndItem, param3.low8, DPA_API_MENU_EXECUTE )
  182 
  183 #define DpaApiMenuExecute_StackSaver( menuAndItem ) do { \
  184   param2 = menuAndItem; \
  185   W = DPA_API_MENU_EXECUTE; \
  186   #asm \
  187     DW  __MOVLP( DPA_API_ADDRESS >> 8 ); \
  188     DW  __CALL( DPA_API_ADDRESS ); \
  189     DW  __MOVLP( CUSTOM_HANDLER_ADDRESS >> 8 ); \
  190   #endasm \
  191   } while(0)
  192 
  193 #define DpaApiDeepSleep( wdtcon )                         DpaApiEntry( wdtcon, param3.low8, DPA_API_DEEP_SLEEP )
  194 #endif
  195 
  196 #define I2CcomputeFrequency( I2Cfrequency)                ( ( ( F_OSC ) / ( ( I2Cfrequency ) * 4 ) ) - 1 )
  197 
  198 // Wrapper routines to be called instead of DpaApi??? macros to decrease code size if more than ~2 calls are needed
  199 void _DpaApiI2Cinit( uns8 frequency );
  200 void _DpaApiI2Cstart( uns8 address );
  201 void _DpaApiI2Cwrite( uns8 data );
  202 uns8 _DpaApiI2Cread( uns8 ack );
  203 void _DpaApiI2Cstop();
  204 void _DpaApiI2CwaitForACK( uns8 address );
  205 void _DpaApiI2Cshutdown();
  206 void _DpaApiI2CwaitForIdle();
  207 void _DpaApiSleep( uns8 wdtcon );
  208 #if !defined( TR7xD )
  209 void _DpaApiDeepSleep( uns8 wdtcon );
  210 void _DpaApiMenuIndicateResult( uns8 ok );
  211 #endif
  212 void _DpaApiSleepFirst( uns8 wdtcon );
  213 void _DpaApiAfterSleep();
  214 uns8 _DpaApiRandom();
  215 void _DpaApiSetRfDefaults();
  216 
  217 // Helper "multi" function to decrease code size if used more times
  218 void _DpaApiI2Cwrite0();
  219 void _DpaApiI2CwriteAndStop( uns8 data );
  220 uns8 _DpaApiI2CreadACK();
  221 uns8 _DpaApiI2CreadNACK();
  222 uns8 _DpaApiI2CreadNACKandStop();
  223 
  224 #ifdef COORDINATOR_CUSTOM_HANDLER
  225 #undef  DpaEvent_Interrupt
  226 #undef  DpaEvent_BeforeSleep
  227 #undef  DpaEvent_AfterSleep
  228 #undef  DpaEvent_FrcValue
  229 #undef  DpaEvent_FrcResponseTime
  230 #else
  231 #undef  DpaEvent_ReceiveDpaResponse
  232 #undef  DpaEvent_IFaceReceive
  233 #endif
  234 
  235 // To detect overlapping code in case someone would put some code before this header by mistake
  236 #pragma origin __APPLICATION_ADDRESS
  237 #pragma updateBank 0
  238 
  239 //############################################################################################
  240 // Main IQRF entry point jumps to the main DPA entry point
  241 void APPLICATION()
  242 //############################################################################################
  243 {
  244   #asm
  245     DW  __MOVLP( MAIN_DPA_ADDRESS >> 8 );
  246   DW  __GOTO( MAIN_DPA_ADDRESS );
  247   #endasm
  248 
  249 #ifndef NO_CUSTOM_DPA_HANDLER
  250     // Fake call to force CustomDpaHandler() compilation
  251     CustomDpaHandler();
  252 #endif
  253 
  254   // Fake call to force DpaApiEntry() compilation
  255   DpaApiEntry( param2, param3.low8, W );
  256 }
  257 
  258 //############################################################################################
  259 // Entry stub to the real DPA API entry
  260 #pragma origin DPA_API_ADDRESS_ENTRY
  261 uns8  DpaApiEntry( uns8 par1 @ param2, uns8 par2 @ param3.low8, uns8 apiIndex @ W )
  262 //############################################################################################
  263 {
  264   #asm
  265     DW  __MOVLP( DPA_API_ADDRESS >> 8 );
  266   DW  __CALL( DPA_API_ADDRESS );
  267   DW  __MOVLP( DPA_API_ADDRESS_ENTRY >> 8 );
  268   #endasm
  269 
  270     return W;
  271 }
  272 
  273 //############################################################################################
  274 #pragma origin DPA_API_ADDRESS_ENTRY + 0x08
  275 
  276 //############################################################################################
  277 
  278 #ifndef NO_CUSTOM_DPA_HANDLER
  279 // Next comes Custom DPA handler routine
  280 #pragma origin CUSTOM_HANDLER_ADDRESS
  281 #endif
  282 
  283 #pragma updateBank 1
  284 
  285 //############################################################################################
  286 #else // _CUSTOM_DPA_HANDLER_
  287 //############################################################################################
  288 // 2nd include
  289 
  290 #ifndef NO_CUSTOM_DPA_HANDLER
  291 
  292 // Library wrappers and helpers to decrease code size
  293 //############################################################################################
  294 #pragma library 1
  295 //############################################################################################
  296 uns8 _DpaApiUserBank_01( uns8 apiIndex @ W )
  297 //############################################################################################
  298 {
  299 #pragma updateBank exit = UserBank_01
  300   return DpaApiEntry( param2, param3.low8, apiIndex );
  301 }
  302 //############################################################################################
  303 void _DpaApiI2Cinit( uns8 frequency @ W )
  304 //############################################################################################
  305 {
  306 #pragma updateBank exit = UserBank_01
  307   param2 = frequency;
  308   _DpaApiUserBank_01( DPA_API_I2C_INIT );
  309 }
  310 //############################################################################################
  311 void _DpaApiI2Cstart( uns8 address @ W )
  312 //############################################################################################
  313 {
  314 #pragma updateBank exit = UserBank_01
  315   param2 = address;
  316   _DpaApiUserBank_01( DPA_API_I2C_START );
  317 }
  318 //############################################################################################
  319 void _DpaApiI2Cwrite0()
  320 //############################################################################################
  321 {
  322 #pragma updateBank exit = UserBank_01
  323   _DpaApiI2Cwrite( 0 );
  324 }
  325 //############################################################################################
  326 void _DpaApiI2Cwrite( uns8 data @ W )
  327 //############################################################################################
  328 {
  329 #pragma updateBank exit = UserBank_01
  330   param2 = data;
  331   _DpaApiUserBank_01( DPA_API_I2C_WRITE );
  332 }
  333 //############################################################################################
  334 uns8 _DpaApiI2CreadNACKandStop()
  335 //############################################################################################
  336 {
  337 #pragma updateBank exit = UserBank_01
  338   param2 = _DpaApiI2CreadNACK();
  339   _DpaApiI2Cstop(); /* Must not use param2 */
  340   return param2;
  341 }
  342 //############################################################################################
  343 uns8 _DpaApiI2CreadACK()
  344 //############################################################################################
  345 {
  346 #pragma updateBank exit = UserBank_01
  347   return _DpaApiI2Cread( 1 );
  348 }
  349 //############################################################################################
  350 uns8 _DpaApiI2CreadNACK()
  351 //############################################################################################
  352 {
  353 #pragma updateBank exit = UserBank_01
  354   return _DpaApiI2Cread( 0 );
  355 }
  356 //############################################################################################
  357 uns8 _DpaApiI2Cread( uns8 ack @ W )
  358 //############################################################################################
  359 {
  360 #pragma updateBank exit = UserBank_01
  361   param2 = ack;
  362   return _DpaApiUserBank_01( DPA_API_I2C_READ );
  363 }
  364 //############################################################################################
  365 void _DpaApiI2CwriteAndStop( uns8 data @ W )
  366 //############################################################################################
  367 {
  368 #pragma updateBank exit = UserBank_01
  369   _DpaApiI2Cwrite( data );
  370   _DpaApiI2Cstop();
  371 }
  372 //############################################################################################
  373 void _DpaApiI2Cstop()
  374 //############################################################################################
  375 {
  376 #pragma updateBank exit = UserBank_01
  377   _DpaApiUserBank_01( DPA_API_I2C_STOP );
  378 }
  379 //############################################################################################
  380 void _DpaApiI2CwaitForACK( uns8 address @ W )
  381 //############################################################################################
  382 {
  383 #pragma updateBank exit = UserBank_01
  384   DpaApiI2CwaitForACK( address );
  385 }
  386 //############################################################################################
  387 void _DpaApiI2Cshutdown()
  388 //############################################################################################
  389 {
  390 #pragma updateBank exit = UserBank_01
  391   _DpaApiUserBank_01( DPA_API_I2C_SHUTDOWN );
  392 }
  393 //############################################################################################
  394 void _DpaApiI2CwaitForIdle()
  395 //############################################################################################
  396 {
  397 #pragma updateBank exit = UserBank_01
  398   _DpaApiUserBank_01( DPA_API_I2C_WAIT_FOR_IDLE );
  399 }
  400 //############################################################################################
  401 void _DpaApiSleep( uns8 wdtcon @ W )
  402 //############################################################################################
  403 {
  404 #pragma updateBank exit = UserBank_01
  405   param2 = wdtcon;
  406   _DpaApiUserBank_01( DPA_API_SLEEP );
  407 }
  408 #if !defined( TR7xD )
  409 //############################################################################################
  410 void _DpaApiDeepSleep( uns8 wdtcon @ W )
  411 //############################################################################################
  412 {
  413 #pragma updateBank exit = UserBank_01
  414   param2 = wdtcon;
  415   _DpaApiUserBank_01( DPA_API_DEEP_SLEEP );
  416 }
  417 #endif
  418 //############################################################################################
  419 void _DpaApiSleepFirst( uns8 wdtcon @ W )
  420 //############################################################################################
  421 {
  422 #pragma updateBank exit = UserBank_01
  423   FirstDpaApiSleep = TRUE;
  424   _DpaApiSleep( wdtcon );
  425 }
  426 //############################################################################################
  427 void _DpaApiAfterSleep()
  428 //############################################################################################
  429 {
  430 #pragma updateBank exit = UserBank_01
  431   _DpaApiUserBank_01( DPA_API_AFTER_SLEEP );
  432 }
  433 //############################################################################################
  434 uns8 _DpaApiRandom()
  435 //############################################################################################
  436 {
  437 #pragma updateBank exit = UserBank_01
  438   return _DpaApiUserBank_01( DPA_API_RANDOM );
  439 }
  440 //############################################################################################
  441 void _DpaApiSetRfDefaults()
  442 //############################################################################################
  443 {
  444 #pragma updateBank exit = UserBank_01
  445   _DpaApiUserBank_01( DPA_API_SET_RF_DEFAULTS );
  446 }
  447 #if !defined( TR7xD )
  448 //############################################################################################
  449 void _DpaApiMenuIndicateResult( uns8 ok @ W )
  450 //############################################################################################
  451 {
  452 #pragma updateBank exit = UserBank_01
  453   param2 = ok;
  454   _DpaApiUserBank_01( DPA_API_MENU_INDICATE_RESULT );
  455 }
  456 #endif
  457 //############################################################################################
  458 
  459 
  460 
  461 // Code bumper to detect too long code of Custom DPA handler + other routines
  462 #pragma origin CUSTOM_HANDLER_ADDRESS_END
  463 // To avoid adding some code after handler by mistake
  464 #pragma origin __MAX_FLASH_ADDRESS
  465 #endif
  466 
  467 #endif  // _CUSTOM_DPA_HANDLER_
  468 //############################################################################################