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.22 $ 8 // Date: $Date: 2021/04/26 15:13:51 $ 9 // 10 // Revision history: 11 // 2020/09/03 Release for DPA 4.15 12 // 2019/12/11 Release for DPA 4.11 13 // 2018/10/25 Release for DPA 3.03 14 // 2017/03/14 Release for DPA 3.00 15 // 16 // ******************************************************************************** 17 18 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 19 20 // Default IQRF include (modify the path according to your setup) 21 #include "IQRF.h" 22 23 // Default DPA header (modify the path according to your setup) 24 #include "DPA.h" 25 // Default Custom DPA Handler header (modify the path according to your setup) 26 #include "DPAcustomHandler.h" 27 // PIC instructions (header from CC5X) 28 #include "hexcodes.h" 29 30 // 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). 31 // This example works only at STD mode, not at LP mode. 32 // !!! Make sure the UART peripheral baud rate set at the Node configuration matches BaudRateValue value from below 33 34 // Fixed baud-rate 35 #define BaudRateValue 57600L 36 #define BaudRateDPA DpaBaud_57600 37 38 // SW TX pin 39 #define SWTX LATA.0 40 #define SWTXtris TRISA.0 41 42 // Default HW TX pin, that will not be used for UART 43 #define HWTX LATC.6 44 #define HWTXtris TRISC.6 45 46 // Division macro with rounding 47 #define DIV(Dividend,Divisor) (((Dividend+((Divisor)>>1))/(Divisor))) 48 // Instructions by one baud 49 #define INSTRperBAUDmul(mul) ( DIV( ( (F_OSC) * (mul) ), ( 4L * (BaudRateValue) ) ) ) 50 #define INSTRperBAUD INSTRperBAUDmul(1L) 51 52 // Delay macro 53 #define SwUartDelayInst(instr) \ 54 #if (instr) != 0 \ 55 #if (instr) < 0 \ 56 #error SwUartDelayInst is negative \ 57 #elif (instr) == 3 \ 58 nop(); \ 59 nop2(); \ 60 #elif (instr) == 4 \ 61 nop2(); \ 62 nop2(); \ 63 #elif (instr) == 5 \ 64 nop(); \ 65 nop2(); \ 66 nop2(); \ 67 #else \ 68 #if (instr) % 3 == 1 \ 69 nop(); \ 70 #elif (instr) % 3 == 2 \ 71 nop2(); \ 72 #endif /* (instr) % 3 == 1 */ \ 73 #if (instr) / 3 != 0 \ 74 #asm \ 75 DW __MOVLW( (instr) / 3 ) \ 76 DW __DECFSZ( __WREG, 1 ) \ 77 DW __BRA( -2 ) \ 78 #endasm \ 79 #endif /* (instr) / 3 != 0 */ \ 80 #endif \ 81 #endif /* (instr) != 0 */ \ 82 83 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 84 //############################################################################################ 85 bit CustomDpaHandler() 86 //############################################################################################ 87 { 88 // Handler presence mark 89 clrwdt(); 90 91 // Detect DPA event to handle 92 switch ( GetDpaEvent() ) 93 { 94 // ------------------------------------------------- 95 case DpaEvent_Interrupt: 96 // Do an extra quick background interrupt work 97 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 98 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 99 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 100 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 101 // ! Make sure race condition does not occur when accessing those variables at other places. 102 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 103 // ! Do not call any OS functions except setINDFx(). 104 // ! Do not use any OS variables especially for writing access. 105 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 106 return Carry; 107 108 // ------------------------------------------------- 109 case DpaEvent_Idle: 110 // Do a quick background work when RF packet is not received 111 112 // #################################### 113 // Shows free use of normally HW TX pin 114 HWTXtris = 0; 115 HWTX = !HWTX; 116 // #################################### 117 break; 118 119 // ------------------------------------------------- 120 case DpaEvent_Init: 121 // Do a one time initialization before main loop starts 122 123 // After UART was opened by DPA, make sure HW TX pin is free to use by other code but not by UART peripheral 124 TXEN = 0; 125 HWTXtris = 0; 126 127 // Initialize SW TX pin 128 SWTXtris = 0; 129 SWTX = 1; 130 break; 131 132 // ------------------------------------------------- 133 case DpaEvent_ReceiveDpaRequest: 134 // Called after DPA request was received 135 136 if ( _PNUM == PNUM_UART ) 137 switch ( _PCMD ) 138 { 139 // Not implemented 140 case CMD_UART_CLEAR_WRITE_READ: 141 DpaApiSetPeripheralError( ERROR_PCMD ); 142 _PCMD |= RESPONSE_FLAG; 143 return TRUE; 144 145 // Handle TX by SW solution, RX by default HW solution 146 case CMD_UART_WRITE_READ: 147 { 148 // Optimization? 149 #if &_DpaMessage.PerUartWriteRead_Request.WrittenData[-1] == &bufferRF[0] 150 setFSR0( _FSR_RF ); 151 #else 152 FSR0 = &_DpaMessage.PerUartWriteRead_Request.WrittenData[-1]; 153 #endif 154 // Decrease size by ReadTimeout field but 1 byte 155 _DpaDataLength -= sizeof( _DpaMessage.PerUartWriteRead_Request.ReadTimeout ) - 1; 156 // Send every TX byte by SW 157 while ( --_DpaDataLength != 0 ) 158 { 159 // Byte to TX (must be at common RAM to avoid MOVLB) 160 userReg0 = *++FSR0; 161 // Disable interrupts for precise timing 162 GIE = FALSE; 163 // Start bit 164 SWTX = 0; 165 // Bank update can be forced off as we know that only one bank (with SWTX pin) is used in the loop 166 #pragma updateBank 0 /* OFF */ 167 SwUartDelayInst( INSTRperBAUD - 6 ); 168 // Bit loop variable (must be at common RAM to avoid MOVLB) 169 uns8 loop @ userReg1; 170 // 8 bits 171 loop = 8; 172 do 173 { 174 if ( userReg0.0 ) 175 { 176 userReg0 = rr( userReg0 ); 177 SWTX = 1; 178 } 179 else 180 { 181 SWTX = 0; 182 userReg0 = rr( userReg0 ); 183 nop(); 184 } 185 186 SwUartDelayInst( INSTRperBAUD - 9 ); 187 } while ( --loop != 0 ); 188 SwUartDelayInst( 9 - 5 ); 189 // Stop bit 190 SWTX = 1; 191 // Relax timing 192 GIE = TRUE; 193 SwUartDelayInst( 3 * INSTRperBAUD ); 194 #pragma updateBank 1 /* ON */ 195 } 196 197 // Pass the request to the default DPA but without TX data 198 _DpaDataLength = sizeof( _DpaMessage.PerUartWriteRead_Request.ReadTimeout ); 199 break; 200 } 201 } 202 203 break; 204 205 case DpaEvent_BeforeSendingDpaResponse: 206 // Called before sending DPA response back to originator of DPA response 207 208 // After UART was opened by DPA, make sure HW TX pin is free to use by other code but not by UART peripheral 209 if ( _PNUM == PNUM_UART && _PCMD == CMD_UART_OPEN ) 210 { 211 TXEN = 0; 212 HWTXtris = 0; 213 } 214 break; 215 } 216 217 return FALSE; 218 } 219 220 //############################################################################################ 221 // 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) 222 #include "DPAcustomHandler.h" 223 //############################################################################################