1 // ********************************************************************************
    2 //   Custom DPA Handler code example - Standard HW UART RX + SW TX                *
    3 // ********************************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-UartHwRxSwTx.c,v $
    7 // Version: $Revision: 1.29 $
    8 // Date:    $Date: 2022/02/25 09:41:25 $
    9 //
   10 // Revision history:
   11 //   2022/02/24  Release for DPA 4.17
   12 //   2020/09/03  Release for DPA 4.15
   13 //   2019/12/11  Release for DPA 4.11
   14 //   2018/10/25  Release for DPA 3.03
   15 //   2017/03/14  Release for DPA 3.00
   16 //
   17 // ********************************************************************************
   18 
   19 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   20 
   21 // Default IQRF include (modify the path according to your setup)
   22 #include "IQRF.h"
   23 
   24 // Default DPA header (modify the path according to your setup)
   25 #include "DPA.h"
   26 // Default Custom DPA Handler header (modify the path according to your setup)
   27 #include "DPAcustomHandler.h"
   28 // PIC instructions (header from CC5X)
   29 #include "hexcodes.h"
   30 
   31 // This example shows how to use standard DPA UART RX but SW TX in order to make HW TX pin free for other use (e.g. PWM).
   32 // Note: On TR7xG modules SW TX is not used but redirecting TX using PIC build-in PPS feature
   33 // This example works only at STD mode, not at LP mode.
   34 // Make sure the embedded UART peripheral is enabled
   35 // !!! Make sure the UART peripheral baud rate set at the Node configuration matches BaudRateValue value from below
   36 
   37 // SW TX pin
   38 #if defined( TR7xG )
   39 #define SWTXpps   RC2PPS
   40 #else
   41 #define SWTX      LATC.2
   42 #define SWTXtris  TRISC.2
   43 #endif
   44 
   45 // Default HW TX pin, that will not be used by UART peripheral
   46 #define HWTX      LATC.6
   47 #define HWTXtris  TRISC.6
   48 #if defined( TR7xG )
   49 #define HWTXpps   RC6PPS
   50 #endif
   51 
   52 #if !defined( TR7xG )
   53 
   54 // Fixed baud-rate
   55 #define BaudRateValue   57600L
   56 
   57 // Division macro with rounding
   58 #define DIV(Dividend,Divisor) (((Dividend+((Divisor)>>1))/(Divisor)))
   59 // Instructions by one baud
   60 #define INSTRperBAUDmul(mul)    ( DIV( ( (F_OSC) * (mul) ), ( 4L * (BaudRateValue) ) ) )
   61 #define INSTRperBAUD            INSTRperBAUDmul(1L)
   62 
   63 // Delay macro
   64 #define SwUartDelayInst(instr) \
   65 #if (instr) != 0 \
   66 #if (instr) < 0 \
   67 #error SwUartDelayInst is negative \
   68 #elif (instr) == 3 \
   69   nop(); \
   70   nop2(); \
   71 #elif (instr) == 4 \
   72   nop2(); \
   73   nop2(); \
   74 #elif (instr) == 5 \
   75   nop(); \
   76   nop2(); \
   77   nop2(); \
   78 #else \
   79 #if (instr) % 3 == 1 \
   80   nop(); \
   81 #elif (instr) % 3 == 2 \
   82   nop2(); \
   83 #endif /* (instr) % 3 == 1 */ \
   84 #if (instr) / 3 != 0 \
   85 #asm \
   86   DW  __MOVLW( (instr) / 3 ) \
   87   DW  __DECFSZ( __WREG, 1 ) \
   88   DW  __BRA( -2 ) \
   89 #endasm \
   90 #endif /* (instr) / 3 != 0 */ \
   91 #endif \
   92 #endif /* (instr) != 0 */ \
   93 
   94 #endif
   95 
   96 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   97 //############################################################################################
   98 bit CustomDpaHandler()
   99 //############################################################################################
  100 {
  101   // Handler presence mark
  102   clrwdt();
  103 
  104   // Detect DPA event to handle
  105   switch ( GetDpaEvent() )
  106   {
  107     // -------------------------------------------------
  108     case DpaEvent_Interrupt:
  109       // Do an extra quick background interrupt work
  110       return Carry;
  111 
  112       // -------------------------------------------------
  113     case DpaEvent_Idle:
  114       // Do a quick background work when RF packet is not received
  115     {
  116       static bit wasIdle;
  117       // After UART was opened by DPA (_after_ Init event), make sure HW TX pin is free to use by other code but not by UART peripheral
  118       if ( !wasIdle )
  119       {
  120         wasIdle = TRUE;
  121         goto _DisableDefaultTX;
  122       }
  123 
  124       // ####################################
  125       // Shows free use of normally HW TX pin
  126       HWTXtris = 0;
  127       HWTX = !HWTX;
  128       // ####################################
  129       break;
  130     }
  131 
  132     // -------------------------------------------------
  133     case DpaEvent_AfterSleep:
  134       // Called after woken up after sleep
  135 
  136       // UART is closed before sleep, we must reconfigure it
  137       goto _DisableDefaultTX;
  138 
  139 #if !defined( TR7xG )
  140       // -------------------------------------------------
  141     case DpaEvent_ReceiveDpaRequest:
  142       // Called after DPA request was received
  143 
  144       if ( _PNUM == PNUM_UART )
  145         switch ( _PCMD )
  146         {
  147           // Not implemented
  148           case CMD_UART_CLEAR_WRITE_READ:
  149             W = ERROR_PCMD;
  150 
  151 _ERR_ReceiveDpaRequest:
  152             DpaApiSetPeripheralError( W );
  153             _PCMD |= RESPONSE_FLAG;
  154             return TRUE;
  155 
  156             // Handle TX by SW solution, RX by default HW solution
  157           case CMD_UART_WRITE_READ:
  158           {
  159             // Fail if HW UART not open
  160             if ( !RCIE )
  161             {
  162               W = ERROR_FAIL;
  163               goto _ERR_ReceiveDpaRequest;
  164             }
  165 
  166             // Optimization?
  167 #if &_DpaMessage.PerUartWriteRead_Request.WrittenData[-1] == &bufferRF[0]
  168             setFSR0( _FSR_RF );
  169 #else
  170             FSR0 = &_DpaMessage.PerUartWriteRead_Request.WrittenData[-1];
  171 #endif
  172             // Decrease size by ReadTimeout field but 1 byte
  173             _DpaDataLength -= sizeof( _DpaMessage.PerUartWriteRead_Request.ReadTimeout ) - 1;
  174             // Send every TX byte by SW
  175             while ( --_DpaDataLength != 0 )
  176             {
  177               // Byte to TX (must be at common RAM to avoid MOVLB)
  178               userReg0 = *++FSR0;
  179               // Disable interrupts for precise timing
  180               GIE = FALSE;
  181               // Start bit
  182               SWTX = 0;
  183               // Bank update can be forced off as we know that only one bank (with SWTX pin) is used in the loop
  184 #pragma updateBank 0 /* OFF */
  185               SwUartDelayInst( INSTRperBAUD - 6 );
  186               // Bit loop variable (must be at common RAM to avoid MOVLB)
  187               uns8 loop @ userReg1;
  188               // 8 bits
  189               loop = 8;
  190               do
  191               {
  192                 if ( userReg0.0 )
  193                 {
  194                   userReg0 = rr( userReg0 );
  195                   SWTX = 1;
  196                 }
  197                 else
  198                 {
  199                   SWTX = 0;
  200                   userReg0 = rr( userReg0 );
  201                   nop();
  202                 }
  203 
  204                 SwUartDelayInst( INSTRperBAUD - 9 );
  205               } while ( --loop != 0 );
  206               SwUartDelayInst( 9 - 5 );
  207               // Stop bit
  208               SWTX = 1;
  209               // Relax timing
  210               GIE = TRUE;
  211               SwUartDelayInst( 3 * INSTRperBAUD );
  212 #pragma updateBank 1 /* ON */
  213             }
  214 
  215             // Pass the request to the default DPA but without TX data
  216             _DpaDataLength = sizeof( _DpaMessage.PerUartWriteRead_Request.ReadTimeout );
  217             break;
  218           }
  219         }
  220 
  221       break;
  222 #endif
  223 
  224     case DpaEvent_BeforeSendingDpaResponse:
  225       // Called before sending DPA response back to originator of DPA response
  226 
  227       // After UART was opened by DPA, make sure HW TX pin is free to use by other code but not by UART peripheral
  228       if ( _PNUM == PNUM_UART && _PCMD == CMD_UART_OPEN )
  229       {
  230 _DisableDefaultTX:
  231 
  232 #if defined( TR7xG )
  233         unlockPPS();
  234         // Control default TX by LATx.y
  235         HWTXpps = 0x00;
  236         // Redirect TX to our pin
  237         SWTXpps = 0x10;
  238         lockPPS();
  239 #else
  240         // Initialize SW TX pin
  241         SWTXtris = 0;
  242         SWTX = 1;
  243         // Disable UART HW TX
  244         TXEN = 0;
  245 #endif
  246 
  247         // Set default TX as output
  248         HWTXtris = 0;
  249       }
  250       break;
  251   }
  252 
  253   return FALSE;
  254 }
  255 
  256 //############################################################################################
  257 // 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)
  258 #include "DPAcustomHandler.h"
  259 //############################################################################################