-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
493 lines (426 loc) · 17.5 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
// *********************************************************************
// Sketch to cooperate with CustomDpaHandler-Bridge-UART.c *
// *********************************************************************
// Copyright (c) IQRF Tech s.r.o.
//
// File: $RCSfile: CustomDpaHandler-Bridge-UART.ino,v $
// Version: $Revision: 1.7 $
// Date: $Date: 2021/02/22 17:55:18 $
//
// Revision history:
// 2019/03/01 Release for DPA 4.01
// 2018/10/25 Release for DPA 3.03
//
// *********************************************************************
// Please see CustomDpaHandler-Bridge-UART.c for implementation details.
// This Sketch implements one standard IQRF sensor
// Type of the sensor is Binary7
// include necessary core libraries
#include "stdint.h"
#include "Arduino.h"
// Include IQRF DPA headers
#include "DPA.h"
#include "IQRFstandard.h"
#include "IQRF_HWPID.h"
// include own created libraries
#include "IQRFservo.h"
#include "IQRFbattery.h"
// number of sensors currently in use (for future use - to be implemented)
#define SENSORS_NR 2
//############################################################################################
// servo - specific declarations
//############################################################################################
// IQRF-specific type of servo object
IQRFservo servo ;
// Declare a pin which the servo should be connected to (currently pin D9)
int servoPin = 9 ;
// Servo position as demanded from coordinator
byte servoPos = 0;
// Delay in [ms] that affects the servo turning speed.
// Higher value means slower speed.
// Please choose value from the interval of <10,100>.
int delayTime = 10;
//############################################################################################
// battery - specific declarations
//############################################################################################
// IQRF-specific type of battery object
IQRFbattery battery ;
//############################################################################################
void setup()
//############################################################################################
{
Serial.begin ( 115200 );
// Setup UART to connect to IQRF TR module
Serial1.begin ( 115200 );
// initialise servo object with the selected pin to attach
servo.init ( servoPin );
// perform a battery voltage check after boot
battery.checkBatteryLevel () ;
}
//############################################################################################
// Returns sensor value
byte GetSensor0Value()
{
return 0;
}
//############################################################################################
// HDLC byte stuffing bytes
// Flag Sequence
#define HDLC_FRM_FLAG_SEQUENCE 0x7e
// Asynchronous Control Escape
#define HDLC_FRM_CONTROL_ESCAPE 0x7d
// Asynchronous transparency modifier
#define HDLC_FRM_ESCAPE_BIT 0x20
// Flag to DpaEvent_DpaRequest event value to indicate return TRUE not FALSE
#define EVENT_RETURN_TRUE 0x80
// Flag to DpaEvent_DpaRequest event value to report error, error value is the 1st data byte
#define EVENT_RESPONSE_ERROR 0x40
// Received data from IQRF
byte RxBuffer[2 * sizeof( byte ) + sizeof( TDpaIFaceHeader ) + sizeof( TDpaMessage )];
// Data from IQRF length limits
#define MIN_RX_PACKET_DATA_LENGTH 2
#define MAX_RX_PACKET_DATA_LENGTH sizeof( RxBuffer )
//############################################################################################
// Sends one byte to IQRF
void TxByte( byte data )
//############################################################################################
{
Serial1.write( data );
}
//############################################################################################
// Sends one HDLC byte to IQRF
void TxHdlcByte( byte data )
//############################################################################################
{
switch ( data )
{
default:
TxByte( data );
return;
case HDLC_FRM_FLAG_SEQUENCE:
case HDLC_FRM_CONTROL_ESCAPE:
{
TxByte( HDLC_FRM_CONTROL_ESCAPE );
TxByte( data ^ HDLC_FRM_ESCAPE_BIT );
return;
}
}
}
//############################################################################################
// Returns FRC value back to IQRF
void ResponseFRCvalue( unsigned long frcValue )
//############################################################################################
{
// Start packet
TxByte( HDLC_FRM_FLAG_SEQUENCE );
// Send event value
TxHdlcByte( DpaEvent_FrcValue );
// Send FRC value up to 4 bytes
TxHdlcByte( frcValue & 0xFF );
TxHdlcByte( ( frcValue >> 8 ) & 0xFF );
TxHdlcByte( ( frcValue >> 16 ) & 0xFF );
TxHdlcByte( ( frcValue >> 24 ) & 0xFF );
// Stop packet
TxByte( HDLC_FRM_FLAG_SEQUENCE );
}
//############################################################################################
// Return DPA response back to IQRF
void ResponseCommand( byte returnFlags, byte _DpaDataLength, byte dataLength, byte *pData )
//############################################################################################
{
// Start packet
TxByte( HDLC_FRM_FLAG_SEQUENCE );
// Send event value
TxHdlcByte( DpaEvent_DpaRequest | returnFlags );
// Send DPA variable data length (must not equal to the actual data length sent)
TxHdlcByte( _DpaDataLength );
// Send DPA response data
for ( ; dataLength != 0; dataLength-- )
TxHdlcByte( *pData++ );
// Stop packet
TxByte( HDLC_FRM_FLAG_SEQUENCE );
}
//############################################################################################
// Packet from Custom DPA Handler was received
void CustomDpaHandler( byte dataLength )
//############################################################################################
{
// if true, then set the servo to requested position after performing DPA response
// otherwise, delays during servo operation could cause DPA General Fail (timeout)
bool turnServo = false ;
// Which Custom DPA Handler event to handle?
switch ( RxBuffer[0] )
{
// Prepare DPA response to DPA request
case DpaEvent_DpaRequest:
if ( dataLength >= ( 2 * sizeof( byte ) + sizeof( TDpaIFaceHeader ) ) )
{
// 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
#define _DpaDataLength (RxBuffer[1])
#define _NADR (RxBuffer[2])
#define _NADRhigh (RxBuffer[3])
#define _PNUM (RxBuffer[4])
#define _PCMD (RxBuffer[5])
#define _HWPIDlow (RxBuffer[6])
#define _HWPIDhigh (RxBuffer[7])
#define _DpaMessage (*((TDpaMessage*)(RxBuffer+8)))
// Fake Custom DPA Handler macro to return DPA error (this macro does not do return the same way the DPA original macro)
#define DpaApiReturnPeripheralError(error) do { \
_DpaMessage.ErrorAnswer.ErrN = error; \
returnDataLength = _DpaDataLength = sizeof( _DpaMessage.ErrorAnswer.ErrN ); \
returnFlags = EVENT_RESPONSE_ERROR | EVENT_RETURN_TRUE; \
} while( 0 )
// Value or error flag to return from Custom DPA handler
byte returnFlags = 0;
// Length data to return (may not equal to _DpaDataLength)
byte returnDataLength = 0;
// Device enumeration?
if ( IsDpaEnumPeripheralsRequest() )
{
// We implement 1 user peripheral
_DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
_DpaMessage.EnumPeripheralsAnswer.HWPID = 0x123F;
_DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0xABCD;
// Return the enumeration structure but do not modify _DpaDataLength
returnDataLength = sizeof( _DpaMessage.EnumPeripheralsAnswer );
// Return TRUE
returnFlags = EVENT_RETURN_TRUE;
}
// Get information about peripherals?
else if ( IsDpaPeripheralInfoRequest() )
{
if ( _PNUM == PNUM_STD_SENSORS )
{
_DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS;
_DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
// Set standard version
_DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION;
// Return the information structure but do not modify _DpaDataLength
returnDataLength = sizeof( _DpaMessage.PeripheralInfoAnswer );
// Return TRUE
returnFlags = EVENT_RETURN_TRUE;
}
}
else
{
// Handle peripheral command
// Supported peripheral number?
if ( _PNUM == PNUM_STD_SENSORS )
{
// Supported commands?
switch ( _PCMD )
{
// Invalid command
default:
// Return error
DpaApiReturnPeripheralError( ERROR_PCMD );
break;
// Sensor enumeration
case PCMD_STD_ENUMERATE:
// Check data request length
if ( _DpaDataLength != 0 )
{
DpaApiReturnPeripheralError( ERROR_DATA_LEN );
break;
}
// 1st byte is sensor type
_DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_HUMIDITY;
_DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_LOW_VOLTAGE;
// _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7;
// Return just one sensor type
returnDataLength = _DpaDataLength = sizeof ( _DpaMessage.Response.PData[0] ) + sizeof ( _DpaMessage.Response.PData[1] ) ;
// Return TRUE
returnFlags = EVENT_RETURN_TRUE;
break;
// Supported commands. They are handled almost the same way
case PCMD_STD_SENSORS_READ_VALUES:
case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
{
Serial.println ();
Serial.print ("_DpaDataLength: ");
Serial.println (_DpaDataLength);
// No sensor bitmap specified?
if ( _DpaDataLength == 0 )
{
// Bitmap is 32 bits long = 4
_DpaDataLength = 4;
// Simulate 1st sensor in the bitmap (states of the other unimplemented sensors do not care)
_DpaMessage.Request.PData[0] = 1; // Note: must not modify W
}
// Valid bitmap length?
else if ( _DpaDataLength != 4 && _DpaDataLength != 9 && _DpaDataLength != 14 )
{
// Return error
DpaApiReturnPeripheralError( ERROR_DATA_LEN );
break;
}
// write request for sensor #1 (servo control)
if ( ( _DpaDataLength == 9 || _DpaDataLength == 14 ) && _DpaMessage.Request.PData[4] == 1 )
{
// sensor type == [0x80] Relative Humidity
// hence we are interested only in the first data byte [6]
servoPos = _DpaMessage.Request.PData[5] ;
// turn servo to the requested position
turnServo = true ;
}
// Pointer to the response data
byte *pResponseData = _DpaMessage.Response.PData;
// Is my only sensor selected?
if ( _DpaMessage.Request.PData[0] == 1 )
{
// Return also sensor type?
if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
*pResponseData++ = STD_SENSOR_TYPE_HUMIDITY ;
if ( ( _DpaDataLength == 9 || _DpaDataLength == 14 ) && _DpaMessage.Request.PData[4] == 1 )
*pResponseData++ = servoPos ;
else
*pResponseData++ = servo.getAngle () ;
}
if ( _DpaMessage.Request.PData[0] == 2 )
{
if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
*pResponseData++ = STD_SENSOR_TYPE_LOW_VOLTAGE;
// Return sensor data
battery.checkBatteryLevel ();
*pResponseData++ = battery.battLow; // little endian => low goes first
*pResponseData++ = battery.battHigh;
}
if ( _DpaMessage.Request.PData[0] == 3 || _DpaMessage.Request.PData[0] == 255 )
{
// Return also sensor type?
if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
*pResponseData++ = STD_SENSOR_TYPE_HUMIDITY ;
if ( ( _DpaDataLength == 9 || _DpaDataLength == 14 ) && _DpaMessage.Request.PData[4] == 1 )
*pResponseData++ = servoPos ;
else
*pResponseData++ = servo.getAngle () ;
if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
*pResponseData++ = STD_SENSOR_TYPE_LOW_VOLTAGE;
// Return sensor data
battery.checkBatteryLevel ();
*pResponseData++ = battery.battLow; // little endian => low goes first
*pResponseData++ = battery.battHigh;
}
// Returned data length
returnDataLength = _DpaDataLength = ( pResponseData - _DpaMessage.Response.PData );
// Return TRUE
returnFlags = EVENT_RETURN_TRUE;
break;
}
}
}
}
// Return DPA response
ResponseCommand( returnFlags, _DpaDataLength, returnDataLength, (byte*)&_DpaMessage );
if ( turnServo ) servo.setAngle ( servoPos, delayTime ) ; // finally, turn the servo
}
break;
// Return FRC Value
case DpaEvent_FrcValue:
// Check for the minimum length (FRC command and at least 2 bytes of data)
if ( dataLength >= ( 2 + 1 + 2 ) )
{
// Fake important DPA variables for the DPA FRC handling
#define FrcCommand (RxBuffer[1])
#define DataOutBeforeResponseFRC ((byte*)( &RxBuffer[2] ))
// Check the correct FRC request
if ( DataOutBeforeResponseFRC[0] == PNUM_STD_SENSORS &&
( DataOutBeforeResponseFRC[1] == 0x00 || DataOutBeforeResponseFRC[1] == STD_SENSOR_TYPE_LOW_VOLTAGE ) &&
( DataOutBeforeResponseFRC[2] & 0x1f ) == 0 )
{
// Which FRC command to handle?
switch ( FrcCommand )
{
case FRC_STD_SENSORS_1B:
ResponseFRCvalue( GetSensor0Value() + 4 );
break;
case FRC_STD_SENSORS_BIT:
ResponseFRCvalue( ( GetSensor0Value() & ( 0x01 << ( DataOutBeforeResponseFRC[2] >> 5 ) ) ) != 0 ? 0x03 : 0x01 );
break;
}
}
}
break;
}
}
//############################################################################################
void loop()
//############################################################################################
{
// Byte received from the IQRF?
while ( Serial1.available() )
{
// HDLC machine states
typedef enum { RXstateWaitHead, RXstatePacket, RXstateEscape } TState;
// HDLC state
static byte state = RXstateWaitHead;
// Length of the already received data
static byte rxLength;
// Pointer to the received data
static byte *pRxBuffer;
// Read the byte from IQRF
byte oneByte = Serial1.read();
Serial.print(oneByte);
switch ( state )
{
// Waiting for the HDLC header
case RXstateWaitHead:
{
if ( oneByte == HDLC_FRM_FLAG_SEQUENCE )
{
_SetRXstatePacket:
rxLength = 0;
pRxBuffer = RxBuffer;
state = RXstatePacket;
}
break;
}
// Handling packet data byte
case RXstatePacket:
{
switch ( oneByte )
{
case HDLC_FRM_CONTROL_ESCAPE:
// RXstateEscape
state++;
goto _ExitMachine;
case HDLC_FRM_FLAG_SEQUENCE:
{
if ( rxLength >= MIN_RX_PACKET_DATA_LENGTH )
// Packet received, handle it
CustomDpaHandler( rxLength );
goto _SetRXstatePacket;
}
}
_StoreByte:
if ( rxLength == ( MAX_RX_PACKET_DATA_LENGTH + 2 ) )
goto _SetRXstateWaitHead;
*pRxBuffer++ = oneByte;
rxLength++;
_ExitMachine:
break;
}
// Handle escaped byte
case RXstateEscape:
{
switch ( oneByte )
{
case HDLC_FRM_FLAG_SEQUENCE:
goto _SetRXstatePacket;
case HDLC_FRM_CONTROL_ESCAPE:
_SetRXstateWaitHead:
state = RXstateWaitHead;
break;
default:
// RXstatePacket
state--;
oneByte ^= HDLC_FRM_ESCAPE_BIT;
goto _StoreByte;
}
break;
}
}
}
}
//############################################################################################