1 // ********************************************************************* 2 // Sketch to cooperate with CustomDpaHandler-Bridge-UART.c * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-Bridge-UART.ino,v $ 7 // Version: $Revision: 1.9 $ 8 // Date: $Date: 2022/01/21 10:12:15 $ 9 // 10 // Revision history: 11 // 2021/11/05 Release for DPA 4.17 12 // 2019/03/01 Release for DPA 4.01 13 // 2018/10/25 Release for DPA 3.03 14 // 15 // ********************************************************************* 16 17 // Please see CustomDpaHandler-Bridge-UART.c for implementation details. 18 19 // This Sketch implements one standard IQRF sensor 20 // Type of the sensor is Binary7 21 22 // Include IQRF DPA headers 23 #include "DPA.h" 24 #include "IQRFstandard.h" 25 #include "IQRF_HWPID.h" 26 27 //############################################################################################ 28 void setup() 29 //############################################################################################ 30 { 31 // Setup UART to connect to IQRF TR module 32 Serial.begin( 115200 ); 33 } 34 35 //############################################################################################ 36 // Returns sensor value 37 byte GetSensor0Value() 38 //############################################################################################ 39 { 40 // Remap values from Alcohol Gas Sensor MQ-3 connected to the analog input 0 41 return map( analogRead( 0 ), 500, 1023, 0, 127 ); 42 } 43 44 //############################################################################################ 45 46 // HDLC byte stuffing bytes 47 // Flag Sequence 48 #define HDLC_FRM_FLAG_SEQUENCE 0x7e 49 // Asynchronous Control Escape 50 #define HDLC_FRM_CONTROL_ESCAPE 0x7d 51 // Asynchronous transparency modifier 52 #define HDLC_FRM_ESCAPE_BIT 0x20 53 54 // Flag to DpaEvent_DpaRequest event value to indicate return TRUE not FALSE 55 #define EVENT_RETURN_TRUE 0x80 56 // Flag to DpaEvent_DpaRequest event value to report error, error value is the 1st data byte 57 #define EVENT_RESPONSE_ERROR 0x40 58 59 // Received data from IQRF 60 byte RxBuffer[2 * sizeof( byte ) + sizeof( TDpaIFaceHeader ) + sizeof( TDpaMessage )]; 61 62 // Data from IQRF length limits 63 #define MIN_RX_PACKET_DATA_LENGTH 2 64 #define MAX_RX_PACKET_DATA_LENGTH sizeof( RxBuffer ) 65 66 //############################################################################################ 67 // Sends one byte to IQRF 68 void TxByte( byte data ) 69 //############################################################################################ 70 { 71 Serial.write( data ); 72 } 73 74 //############################################################################################ 75 // Sends one HDLC byte to IQRF 76 void TxHdlcByte( byte data ) 77 //############################################################################################ 78 { 79 switch ( data ) 80 { 81 default: 82 TxByte( data ); 83 return; 84 85 case HDLC_FRM_FLAG_SEQUENCE: 86 case HDLC_FRM_CONTROL_ESCAPE: 87 { 88 TxByte( HDLC_FRM_CONTROL_ESCAPE ); 89 TxByte( data ^ HDLC_FRM_ESCAPE_BIT ); 90 return; 91 } 92 } 93 } 94 95 //############################################################################################ 96 // Returns FRC value back to IQRF 97 void ResponseFRCvalue( unsigned long frcValue ) 98 //############################################################################################ 99 { 100 // Start packet 101 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 102 // Send event value 103 TxHdlcByte( DpaEvent_FrcValue ); 104 // Send FRC value up to 4 bytes 105 TxHdlcByte( frcValue & 0xFF ); 106 TxHdlcByte( ( frcValue >> 8 ) & 0xFF ); 107 TxHdlcByte( ( frcValue >> 16 ) & 0xFF ); 108 TxHdlcByte( ( frcValue >> 24 ) & 0xFF ); 109 // Stop packet 110 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 111 } 112 113 //############################################################################################ 114 // Return DPA response back to IQRF 115 void ResponseCommand( byte returnFlags, byte _DpaDataLength, byte dataLength, byte *pData ) 116 //############################################################################################ 117 { 118 // Start packet 119 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 120 // Send event value 121 TxHdlcByte( DpaEvent_DpaRequest | returnFlags ); 122 // Send DPA variable data length (must not equal to the actual data length sent) 123 TxHdlcByte( _DpaDataLength ); 124 // Send DPA response data 125 for ( ; dataLength != 0; dataLength-- ) 126 TxHdlcByte( *pData++ ); 127 // Stop packet 128 TxByte( HDLC_FRM_FLAG_SEQUENCE ); 129 } 130 131 //############################################################################################ 132 // Packet from Custom DPA Handler was received 133 void CustomDpaHandler( byte dataLength ) 134 //############################################################################################ 135 { 136 // Which Custom DPA Handler event to handle? 137 switch ( RxBuffer[0] ) 138 { 139 case DpaEvent_Init: 140 // ToDo: use data provided by Init message 141 break; 142 143 // Prepare DPA response to DPA request 144 case DpaEvent_DpaRequest: 145 if ( dataLength >= ( 2 * sizeof( byte ) + sizeof( TDpaIFaceHeader ) ) ) 146 { 147 // Fake important DPA variables for the DPA Request/Response so the Custom DPA handler code will can be written almost same way on both platforms 148 #define _DpaDataLength (RxBuffer[1]) 149 #define _NADR (RxBuffer[2]) 150 #define _NADRhigh (RxBuffer[3]) 151 #define _PNUM (RxBuffer[4]) 152 #define _PCMD (RxBuffer[5]) 153 #define _HWPIDlow (RxBuffer[6]) 154 #define _HWPIDhigh (RxBuffer[7]) 155 #define _DpaMessage (*((TDpaMessage*)(RxBuffer+8))) 156 157 // Fake Custom DPA Handler macro to return DPA error (this macro does not do return the same way the DPA original macro) 158 #define DpaApiReturnPeripheralError(error) do { \ 159 _DpaMessage.ErrorAnswer.ErrN = error; \ 160 returnDataLength = _DpaDataLength = sizeof( _DpaMessage.ErrorAnswer.ErrN ); \ 161 returnFlags = EVENT_RESPONSE_ERROR | EVENT_RETURN_TRUE; \ 162 } while( 0 ) 163 164 // Value or error flag to return from Custom DPA handler 165 byte returnFlags = 0; 166 // Length data to return (may not equal to _DpaDataLength) 167 byte returnDataLength = 0; 168 // Device enumeration? 169 if ( IsDpaEnumPeripheralsRequest() ) 170 { 171 // We implement 1 user peripheral 172 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 173 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 174 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x123F; 175 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0xABC0; 176 177 // Return the enumeration structure but do not modify _DpaDataLength 178 returnDataLength = sizeof( _DpaMessage.EnumPeripheralsAnswer ); 179 // Return TRUE 180 returnFlags = EVENT_RETURN_TRUE; 181 } 182 // Get information about peripherals? 183 else if ( IsDpaPeripheralInfoRequest() ) 184 { 185 if ( _PNUM == PNUM_STD_SENSORS ) 186 { 187 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS; 188 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 189 // Set standard version 190 _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION; 191 192 // Return the information structure but do not modify _DpaDataLength 193 returnDataLength = sizeof( _DpaMessage.PeripheralInfoAnswer ); 194 // Return TRUE 195 returnFlags = EVENT_RETURN_TRUE; 196 } 197 } 198 else 199 { 200 // Handle peripheral command 201 202 // Supported peripheral number? 203 if ( _PNUM == PNUM_STD_SENSORS ) 204 { 205 // Supported commands? 206 switch ( _PCMD ) 207 { 208 // Invalid command 209 default: 210 // Return error 211 DpaApiReturnPeripheralError( ERROR_PCMD ); 212 break; 213 214 // Sensor enumeration 215 case PCMD_STD_ENUMERATE: 216 // Check data request length 217 if ( _DpaDataLength != 0 ) 218 { 219 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 220 break; 221 } 222 223 // 1st byte is sensor type 224 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_BINARYDATA7; 225 226 // Return just one sensor type 227 returnDataLength = _DpaDataLength = sizeof( _DpaMessage.Response.PData[0] ); 228 // Return TRUE 229 returnFlags = EVENT_RETURN_TRUE; 230 break; 231 232 // Supported commands. They are handled almost the same way 233 case PCMD_STD_SENSORS_READ_VALUES: 234 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 235 { 236 // No sensor bitmap specified? 237 if ( _DpaDataLength == 0 ) 238 { 239 // Bitmap is 32 bits long = 4 240 _DpaDataLength = 4; 241 // Simulate 1st sensor in the bitmap (states of the other unimplemented sensors do not care) 242 _DpaMessage.Request.PData[0] |= 0x01; // Note: must not modify W 243 } 244 // Valid bitmap length? 245 else if ( _DpaDataLength != 4 ) 246 { 247 // Return error 248 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 249 break; 250 } 251 252 // Pointer to the response data 253 byte *pResponseData = _DpaMessage.Response.PData; 254 // Is my only sensor selected? 255 if ( ( _DpaMessage.Request.PData[0] & 0x01 ) != 0 ) 256 { 257 // Return also sensor type? 258 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 259 *pResponseData++ = STD_SENSOR_TYPE_BINARYDATA7; 260 261 // Return sensor data 262 *pResponseData++ = GetSensor0Value(); 263 } 264 265 // Returned data length 266 returnDataLength = _DpaDataLength = ( pResponseData - _DpaMessage.Response.PData ); 267 // Return TRUE 268 returnFlags = EVENT_RETURN_TRUE; 269 break; 270 } 271 } 272 } 273 } 274 275 // Return DPA response 276 ResponseCommand( returnFlags, _DpaDataLength, returnDataLength, (byte*)&_DpaMessage ); 277 } 278 break; 279 280 // Return FRC Value 281 case DpaEvent_FrcValue: 282 // Check for the minimum length (FRC command and at least 2 bytes of data) 283 if ( dataLength >= ( 2 + 1 + 2 ) ) 284 { 285 // Fake important DPA variables for the DPA FRC handling 286 #define FrcCommand (RxBuffer[1]) 287 #define DataOutBeforeResponseFRC ((byte*)( &RxBuffer[2] )) 288 289 // Check the correct FRC request 290 if ( DataOutBeforeResponseFRC[0] == PNUM_STD_SENSORS && 291 ( DataOutBeforeResponseFRC[1] == 0x00 || DataOutBeforeResponseFRC[1] == STD_SENSOR_TYPE_BINARYDATA7 ) && 292 ( DataOutBeforeResponseFRC[2] & 0x1f ) == 0 ) 293 { 294 // Which FRC command to handle? 295 switch ( FrcCommand ) 296 { 297 case FRC_STD_SENSORS_1B: 298 ResponseFRCvalue( GetSensor0Value() + 4 ); 299 break; 300 301 case FRC_STD_SENSORS_BIT: 302 ResponseFRCvalue( ( GetSensor0Value() & ( 0x01 << ( DataOutBeforeResponseFRC[2] >> 5 ) ) ) != 0 ? 0x03 : 0x01 ); 303 break; 304 } 305 } 306 } 307 break; 308 } 309 } 310 311 //############################################################################################ 312 void loop() 313 //############################################################################################ 314 { 315 // Byte received from the IQRF? 316 while ( Serial.available() ) 317 { 318 // HDLC machine states 319 typedef enum { RXstateWaitHead, RXstatePacket, RXstateEscape } TState; 320 321 // HDLC state 322 static byte state = RXstateWaitHead; 323 // Length of the already received data 324 static byte rxLength; 325 // Pointer to the received data 326 static byte *pRxBuffer; 327 328 // Read the byte from IQRF 329 byte oneByte = Serial.read(); 330 switch ( state ) 331 { 332 // Waiting for the HDLC header 333 case RXstateWaitHead: 334 { 335 if ( oneByte == HDLC_FRM_FLAG_SEQUENCE ) 336 { 337 _SetRXstatePacket: 338 rxLength = 0; 339 pRxBuffer = RxBuffer; 340 state = RXstatePacket; 341 } 342 break; 343 } 344 345 // Handling packet data byte 346 case RXstatePacket: 347 { 348 switch ( oneByte ) 349 { 350 case HDLC_FRM_CONTROL_ESCAPE: 351 // RXstateEscape 352 state++; 353 goto _ExitMachine; 354 355 case HDLC_FRM_FLAG_SEQUENCE: 356 { 357 if ( rxLength >= MIN_RX_PACKET_DATA_LENGTH ) 358 // Packet received, handle it 359 CustomDpaHandler( rxLength ); 360 361 goto _SetRXstatePacket; 362 } 363 } 364 365 _StoreByte: 366 if ( rxLength == ( MAX_RX_PACKET_DATA_LENGTH + 2 ) ) 367 goto _SetRXstateWaitHead; 368 369 *pRxBuffer++ = oneByte; 370 rxLength++; 371 372 _ExitMachine: 373 break; 374 } 375 376 // Handle escaped byte 377 case RXstateEscape: 378 { 379 switch ( oneByte ) 380 { 381 case HDLC_FRM_FLAG_SEQUENCE: 382 goto _SetRXstatePacket; 383 384 case HDLC_FRM_CONTROL_ESCAPE: 385 _SetRXstateWaitHead: 386 state = RXstateWaitHead; 387 break; 388 389 default: 390 // RXstatePacket 391 state--; 392 oneByte ^= HDLC_FRM_ESCAPE_BIT; 393 goto _StoreByte; 394 } 395 break; 396 } 397 } 398 } 399 } 400 401 //############################################################################################