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