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 //############################################################################################