1 // ********************************************************************* 2 // Custom DPA Handler - Bridge using UART * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-Bridge-UART.c,v $ 7 // Version: $Revision: 1.11 $ 8 // Date: $Date: 2019/02/28 09:11:23 $ 9 // 10 // Revision history: 11 // 2018/10/25 Release for DPA 3.03 12 // 13 // ********************************************************************* 14 15 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 16 17 // Default IQRF include (modify the path according to your setup) 18 #include "IQRF.h" 19 20 // Default DPA header (modify the path according to your setup) 21 #include "DPA.h" 22 // Default Custom DPA Handler header (modify the path according to your setup) 23 #include "DPAcustomHandler.h" 24 25 //############################################################################################ 26 /* 27 This handler forwards [1] DpaEvent_DpaRequest and [2] DpaEvent_FrcValue events via UART to the external device. See UART_BAUD for the baud rate setting. 28 The external device is responsible for preparing the proper responses to these events. It sends the response back to the handler via UART. 29 Handler then responses with the response prepared by the external device back to the IQRF network. 30 31 There is an example CustomDpaHandler-Bridge-UART.ino for Arduino that shows how the external device prepares the response. In this case the device behaves as Standard IQRF Sensor. 32 Use an IQRF Breakout board IQRF-BB-01 or IQRF-SHIELD-02 containing the level shifters to connect TR module (3.3 V logic) to the Arduino board (5 V logic): 33 #IQRF-BB-01 Arduino 34 GND GND 35 +3V3/+5V 3.3V 36 MISO (C8=RX) TX -> Digital 1 37 SS (C5=TX) RX <- Digital 0 38 39 This handler and the external device exchange data (packets) using the HDLC protocol the same way the DPA UART Interface except the CRC is not used. 40 Please see https://www.iqrf.org/DpaTechGuide/#2.3.2%20UART for details. 41 42 The handler and the external device pack a different set of information to the packet depending on the event. 43 44 [1] DpaEvent_DpaRequest 45 The packet (data part) sent to the device has the following structure: 46 #Byte Content Notes 47 0 0 = DpaEvent_DpaRequest 48 1 _DpaDataLength 49 2 NADR 50 3 NADRhigh 51 4 PNUM 52 5 PCMD 53 6 HWPID.low8 54 7 HWPID.high8 55 8... PDATA Optional DPA Request data. 56 57 Please note that _DpaDataLength does not have to equal (in case of enumeration DPA Requests) length of PDATA. 58 The handler waits maximum RESPONSE_TIMEOUT ms for the response from the external device otherwise ERROR_FAIL is returned. 59 60 The device responses with a packet of the following structure: 61 #Byte Content Notes 62 0 see Notes = DpaEvent_DpaRequest with ORed optional flags. When bit7 set, the handler returns TRUE otherwise returns FALSE. When bit6 is set, the handler returns DPA error specified at byte #2 i.e. PDATA[0] 63 1 _DpaDataLength 64 2... PDATA Optional DPA Response data. 65 66 [2] DpaEvent_FrcValue 67 The 32 bytes long packet (data part) sent to the device has the following structure: 68 #Byte Content Notes 69 0 10 = DpaEvent_FrcValue 70 1 RFC Command 71 2...31 FRC user data 72 73 The handler waits maximum FRC_RESPONSE_TIMEOUT ms for the response from the external device otherwise the FRC is not handled and the default DPA value (bit0=1) is returned. 74 75 The device responses with a 5 bytes long packet of the following structure: 76 #Byte Content Notes 77 0 10 DpaEvent_DpaRequest 78 1...4 FRC value Content will be written to the responseFRCvalue, responseFRCvalue2B, responseFRCvalue4B variables. Coded using Little Endian. 79 */ 80 //############################################################################################ 81 82 // UART baud rate 83 #define UART_BAUD 115200 84 85 // DPA response timeout from external device [ms] 86 #define RESPONSE_TIMEOUT ( 30 / 10 ) 87 // FRC value response timeout from external device [ms] 88 #define FRC_RESPONSE_TIMEOUT ( 20 / 10 ) 89 // DPA reported fixed FRC response time 90 #define _FRC_RESPONSE_TIME_FIXED _FRC_RESPONSE_TIME_40_MS 91 92 //############################################################################################ 93 94 // Division macro with rounding 95 #define DIV(Dividend,Divisor) (((Dividend+((Divisor)>>1))/(Divisor))) 96 // PIC baud register computation 97 #define UART_SPBRG_VALUE( Baud ) ( DIV( F_OSC, ( ( ( uns24 )4 ) * ( Baud ) ) ) - 1 ) 98 99 // HDLC byte stuffing bytes 100 // Flag Sequence 101 #define HDLC_FRM_FLAG_SEQUENCE 0x7e 102 // Asynchronous Control Escape 103 #define HDLC_FRM_CONTROL_ESCAPE 0x7d 104 // Asynchronous transparency modifier 105 #define HDLC_FRM_ESCAPE_BIT 0x20 106 107 // Flag to DpaEvent_DpaRequest event value to indicate return TRUE not FALSE 108 #define EVENT_RETURN_TRUE 0x80 109 // Flag to DpaEvent_DpaRequest event value to report error, error value is the 1st data byte 110 #define EVENT_RESPONSE_ERROR 0x40 111 112 //############################################################################################ 113 114 // Buffer used for exchange data with external device 115 #define RxBuffer bufferCOM 116 // Sends byte to the external device 117 void TxByte( uns8 data ); 118 // Sends HDLC byte to the external device 119 void TxHdlcByte( uns8 data ); 120 // Receives data from external device, returns length, 0 if timeout occurred 121 uns8 RxPacket( uns8 timeout ); 122 // Initialization 123 void Init(); 124 125 //############################################################################################ 126 bit CustomDpaHandler() 127 //############################################################################################ 128 { 129 // Handler presence mark 130 clrwdt(); 131 132 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 133 switch ( GetDpaEvent() ) 134 { 135 // ------------------------------------------------- 136 // Handler these unused events as fast as possible 137 case DpaEvent_Idle: 138 Init(); 139 140 case DpaEvent_Interrupt: 141 return Carry; 142 143 // ------------------------------------------------- 144 case DpaEvent_FrcValue: 145 // Called to get FRC value 146 147 // Initialize HW if needed 148 Init(); 149 // Start measuring timeout for RxPacket() function 150 startCapture(); 151 152 // Start packet 153 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 154 // Send event value 155 TxHdlcByte( DpaEvent_FrcValue ); 156 // Send FRC command 157 TxHdlcByte( _PCMD ); 158 // Now send all FRC user data 159 uns8 loop = sizeof( DataOutBeforeResponseFRC ); 160 FSR0 = &DataOutBeforeResponseFRC[0]; 161 do 162 { 163 TxHdlcByte( *FSR0++ ); 164 } while ( --loop != 0 ); 165 // Stop packet 166 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 167 168 // Receive the FRC value from the device via UART, length must equal to the event value + 4 FRC value bytes 169 if ( RxPacket( FRC_RESPONSE_TIMEOUT ) == ( sizeof( uns8 ) + sizeof( uns32 ) ) && RxBuffer[0] == DpaEvent_FrcValue ) 170 { 171 // Return FRC values to DPA 172 #if IQRFOS >= 403 173 responseFRCvalue4B.low8 = RxBuffer[1]; 174 responseFRCvalue4B.midL8 = RxBuffer[2]; 175 responseFRCvalue4B.midH8 = RxBuffer[3]; 176 responseFRCvalue4B.high8 = RxBuffer[4]; 177 #else 178 responseFRCvalue = RxBuffer[1]; 179 responseFRCvalue2B.low8 = RxBuffer[1]; 180 responseFRCvalue2B.high8 = RxBuffer[2]; 181 #endif 182 } 183 184 break; 185 186 // ------------------------------------------------- 187 case DpaEvent_FrcResponseTime: 188 // Called to get FRC response time 189 // ToDo - Improve, make value dynamic? 190 responseFRCvalue = _FRC_RESPONSE_TIME_FIXED; 191 break; 192 193 // ------------------------------------------------- 194 case DpaEvent_DpaRequest: 195 // Called to interpret DPA request for peripherals 196 197 // Initialize HW if needed 198 Init(); 199 // Pass the request to the connected device via UART (must not modify FSR0 till it is used) 200 // Start packet 201 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 202 // Send event value 203 TxHdlcByte( DpaEvent_DpaRequest ); 204 // Send DPA variable data length (must not equal to the actual data length sent) 205 TxHdlcByte( _DpaDataLength ); 206 // Send DPA message fields 207 TxHdlcByte( _NADR ); 208 TxHdlcByte( _NADRhigh ); 209 TxHdlcByte( _PNUM ); 210 TxHdlcByte( _PCMD ); 211 TxHdlcByte( _HWPID.low8 ); 212 TxHdlcByte( _HWPID.high8 ); 213 214 // How much data to pass to the device? 215 uns8 dataLength; 216 if ( IsDpaEnumPeripheralsRequest() ) 217 dataLength = sizeof( _DpaMessage.EnumPeripheralsAnswer ); 218 else if ( IsDpaPeripheralInfoRequest() ) 219 dataLength = sizeof( _DpaMessage.PeripheralInfoAnswer ); 220 else 221 // Same amount as available 222 dataLength = _DpaDataLength; 223 224 // FSRx might have been destroyed by Init() 225 setFSR01( _FSR_RF, _FSR_RF ); 226 // Now send the data byte by byte 227 for ( ; dataLength != 0; dataLength-- ) 228 TxHdlcByte( *FSR0++ ); 229 // Stop packet 230 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 231 232 // Start measuring timeout for RxPacket() function 233 startCapture(); 234 235 // Receive the response from the device via UART 236 dataLength = RxPacket( RESPONSE_TIMEOUT ); 237 // Check for timeout and correct event 238 if ( dataLength == 0 || ( RxBuffer[0] & ~( EVENT_RETURN_TRUE | EVENT_RESPONSE_ERROR ) ) != DpaEvent_DpaRequest ) 239 DpaApiReturnPeripheralError( ERROR_FAIL ); 240 241 // Report DPA error? 242 if ( ( RxBuffer[0] & EVENT_RESPONSE_ERROR ) != 0 ) 243 DpaApiReturnPeripheralError( RxBuffer[2] ); 244 245 // Get DPA data length field 246 _DpaDataLength = RxBuffer[1]; 247 // Copy DPA response data (all data minus event value and _DpaDataLength value) 248 copyMemoryBlock( &RxBuffer[2], &_DpaMessage.Response.PData[0], dataLength - 2 ); 249 250 // Return TRUE or FALSE 251 #if EVENT_RETURN_TRUE != 0x80 252 #error Cannot optimize 253 #endif 254 // Carry = TRUE of FALSE to return, got from EVENT_RETURN_TRUE part of the 1st byte which is header 255 W = rl( RxBuffer[0] ); 256 return Carry; 257 } 258 259 return FALSE; 260 } 261 262 //############################################################################################ 263 uns8 RxByteValue; 264 bit RxByte() 265 //############################################################################################ 266 { 267 if ( !RCIF ) 268 goto _returnFALSE; 269 270 if ( FERR ) 271 { 272 W = RCREG; 273 goto _returnFALSE; 274 } 275 276 RxByteValue = RCREG; 277 278 if ( OERR ) 279 { 280 CREN = 0; 281 CREN = 1; 282 _returnFALSE: 283 return FALSE; 284 } 285 286 return TRUE; 287 } 288 289 //############################################################################################ 290 uns8 RxPacket( uns8 timeout ) 291 //############################################################################################ 292 { 293 #define MIN_RX_PACKET_DATA_LENGTH 1 294 #define MAX_RX_PACKET_DATA_LENGTH sizeof( RxBuffer ) 295 296 typedef enum { RXstateWaitHead, RXstatePacket, RXstateEscape } TState; 297 298 // Make sure buffered UART RX is empty 299 RxByte(); 300 RxByte(); 301 302 TState state = RXstateWaitHead; 303 uns8 rxLength; 304 for ( ; ; ) 305 { 306 clrwdt(); 307 // Timeout? 308 captureTicks(); // Note: must not modify FSR0 309 if ( param3 > timeout ) 310 return 0; 311 312 // If anything received via UART 313 if ( RxByte() ) 314 { 315 // HDLC machine 316 skip( (uns8)state ); 317 #pragma computedGoto 1 318 goto _RXstateWaitHead; 319 goto _RXstatePacket; 320 goto _RXstateEscape; 321 #pragma computedGoto 0 322 ; 323 // --------------------------- 324 _RXstateEscape: 325 switch ( RxByteValue ) 326 { 327 case HDLC_FRM_FLAG_SEQUENCE: 328 goto _SetRXstatePacket; 329 330 case HDLC_FRM_CONTROL_ESCAPE: 331 _SetRXstateWaitHead: 332 state = RXstateWaitHead; 333 continue; 334 } 335 336 state--; // RXstatePacket 337 RxByteValue ^= HDLC_FRM_ESCAPE_BIT; 338 goto _StoreByte; 339 340 // --------------------------- 341 _RXstatePacket: 342 switch ( RxByteValue ) 343 { 344 case HDLC_FRM_CONTROL_ESCAPE: 345 // RXstateEscape 346 state++; 347 continue; 348 349 case HDLC_FRM_FLAG_SEQUENCE: 350 { 351 if ( rxLength >= MIN_RX_PACKET_DATA_LENGTH ) 352 return rxLength; 353 354 goto _SetRXstatePacket; 355 } 356 } 357 358 _StoreByte: 359 if ( rxLength == ( MAX_RX_PACKET_DATA_LENGTH + 2 ) ) 360 goto _SetRXstateWaitHead; 361 362 setINDF0( RxByteValue ); 363 FSR0++; 364 rxLength++; 365 continue; 366 367 // --------------------------- 368 _RXstateWaitHead: 369 if ( RxByteValue == HDLC_FRM_FLAG_SEQUENCE ) 370 { 371 _SetRXstatePacket: 372 rxLength = 0; 373 FSR0 = RxBuffer; 374 state = RXstatePacket; 375 } 376 377 continue; 378 } 379 } 380 } 381 382 //############################################################################################ 383 void TxByte( uns8 data ) 384 //############################################################################################ 385 { 386 while ( !TXIF ); 387 TXREG = data; 388 } 389 390 //############################################################################################ 391 void TxHdlcByte( uns8 data ) 392 //############################################################################################ 393 { 394 switch ( data ) 395 { 396 default: 397 TxByte( data ); 398 return; 399 400 case HDLC_FRM_FLAG_SEQUENCE: 401 case HDLC_FRM_CONTROL_ESCAPE: 402 { 403 TxByte( HDLC_FRM_CONTROL_ESCAPE ); 404 TxByte( data ^ HDLC_FRM_ESCAPE_BIT ); 405 return; 406 } 407 } 408 } 409 410 //############################################################################################ 411 void Init() 412 //############################################################################################ 413 { 414 // Initialize UART 415 if ( !SPEN ) 416 { 417 // Connected TR pins (e.g. TR72D)? 418 moduleInfo(); 419 if ( !bufferINFO[5].7 ) 420 { 421 // Set them as inputs 422 TRISC.5 = 1; 423 TRISA.5 = 1; 424 TRISB.4 = 1; 425 } 426 427 // RX input 428 TRISC.7 = 1; 429 // TX output 430 TRISC.6 = 0; 431 432 // Set baud rate 433 SPBRGL = UART_SPBRG_VALUE( UART_BAUD ) & 0xff; 434 SPBRGH = UART_SPBRG_VALUE( UART_BAUD ) >> 8; 435 // baud rate control setup: BRG16 = 1 436 BAUDCON = 0b0000.1.000; 437 438 // CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D 439 // TXEN = 1 440 // BRGH = 1 441 // async UART, high speed, 8 bit, TX enabled 442 TXSTA = 0b0010.0100; 443 444 // SPEN RX9 SREN CREN ADDEN FERR OERR RX9D 445 // SPEN = 1 446 // CREN = 1 447 // Continuous receive, enable port, 8 bit 448 RCSTA = 0b1001.0000; 449 } 450 } 451 452 //############################################################################################ 453 // 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) 454 #include "DPAcustomHandler.h" 455 //############################################################################################