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