23
23
24
24
/*
25
25
* This sketch partially implements the standard Bluetooth Low-Energy "Automation IO" service.
26
+ * It is a relatively complex example which demonstrates use of BLE descriptors and
27
+ * multi-instance characteristics for data input and data output.
28
+ *
26
29
* For more information: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
27
30
*/
28
31
29
- /* Device name: Appears in advertising packets. Should not exceed 13 characters in length */
32
+ /* Device name: Appears in advertising packets. Must not exceed 16 characters in length */
30
33
#define DEVICE_NAME " AE_IO"
31
34
/* UUID for Automation I/O service */
32
35
#define SERVICE_UUID_AUTOMATIONIO (0x1815 )
41
44
* This helps us to build lists of pins below to allow
42
45
* flexible pin assignments to different modes of operation
43
46
*/
44
- struct PinConfig {
47
+ struct DigitalPinConfig {
48
+ unsigned pin;
49
+ const char *name;
50
+ BleCharacteristic characteristic;
51
+ BleDescriptor numDigitalsDesc;
52
+ uint8_t val;
53
+ };
54
+
55
+ struct AnalogPinConfig {
45
56
unsigned pin;
46
57
const char *name;
47
58
BleCharacteristic characteristic;
59
+ uint16_t val;
48
60
};
49
61
50
62
/* Macros to simplify the definition of a new PinConfig struct for a given pin number
51
63
* Note that input pins are only readable by the remote device, while output pins are
52
64
* only writable. Different characteristic UUIDs are used for digital and analog pins */
53
65
#define DIGITAL_INPUT_PINCONFIG (pin ) \
54
- { (pin), #pin, {CHAR_UUID_DIGITAL, sizeof (uint8_t ), BLE_CLIENT_ACCESS_READ_ONLY, BLE_CLIENT_NOTIFY_ENABLED} }
66
+ { (pin), #pin, {CHAR_UUID_DIGITAL, sizeof (uint8_t ), BLE_CLIENT_ACCESS_READ_ONLY, BLE_CLIENT_NOTIFY_ENABLED}, {DESC_UUID_NUMDIGITALS, sizeof ( uint8_t ), BLE_CLIENT_ACCESS_READ_ONLY} }
55
67
#define DIGITAL_OUTPUT_PINCONFIG (pin ) \
56
- { (pin), #pin, {CHAR_UUID_DIGITAL, sizeof (uint8_t ), BLE_CLIENT_ACCESS_WRITE_ONLY, BLE_CLIENT_NOTIFY_DISABLED} }
68
+ { (pin), #pin, {CHAR_UUID_DIGITAL, sizeof (uint8_t ), BLE_CLIENT_ACCESS_WRITE_ONLY, BLE_CLIENT_NOTIFY_DISABLED}, {DESC_UUID_NUMDIGITALS, sizeof ( uint8_t ), BLE_CLIENT_ACCESS_READ_ONLY} }
57
69
#define ANALOG_INPUT_PINCONFIG (pin ) \
58
70
{ (pin), #pin, {CHAR_UUID_ANALOG, sizeof (uint16_t ), BLE_CLIENT_ACCESS_READ_ONLY, BLE_CLIENT_NOTIFY_ENABLED} }
59
71
#define ANALOG_OUTPUT_PINCONFIG (pin ) \
@@ -68,39 +80,38 @@ struct PinConfig {
68
80
* - pins 0-19 are valid for digital input/output
69
81
* - pins 14-19 are valid for analog input
70
82
* - pins 3,5,6,9 are valid for analog output
83
+ * - a maximum of 16 pins are currently supported (limited by number of characteristics)
71
84
*/
72
- struct PinConfig digitalInputPins[] = {
85
+ struct DigitalPinConfig digitalInputPins[] = {
73
86
DIGITAL_INPUT_PINCONFIG (2 ),
74
87
DIGITAL_INPUT_PINCONFIG (4 ),
75
88
DIGITAL_INPUT_PINCONFIG (7 ),
76
89
};
77
90
78
- struct PinConfig digitalOutputPins[] = {
91
+ struct DigitalPinConfig digitalOutputPins[] = {
79
92
DIGITAL_OUTPUT_PINCONFIG (8 ),
80
93
DIGITAL_OUTPUT_PINCONFIG (10 ),
81
94
DIGITAL_OUTPUT_PINCONFIG (11 ),
82
95
DIGITAL_OUTPUT_PINCONFIG (12 ),
83
96
DIGITAL_OUTPUT_PINCONFIG (13 ),
84
97
};
85
98
86
- struct PinConfig analogInputPins[] = {
99
+ struct AnalogPinConfig analogInputPins[] = {
87
100
ANALOG_INPUT_PINCONFIG (14 ),
88
101
ANALOG_INPUT_PINCONFIG (15 ),
89
102
ANALOG_INPUT_PINCONFIG (16 ),
90
103
ANALOG_INPUT_PINCONFIG (17 ),
91
- ANALOG_INPUT_PINCONFIG (18 ),
92
- ANALOG_INPUT_PINCONFIG (19 ),
93
104
};
94
105
95
- struct PinConfig analogOutputPins[] = {
106
+ struct AnalogPinConfig analogOutputPins[] = {
96
107
ANALOG_OUTPUT_PINCONFIG (3 ),
97
108
ANALOG_OUTPUT_PINCONFIG (5 ),
98
109
ANALOG_OUTPUT_PINCONFIG (6 ),
99
110
ANALOG_OUTPUT_PINCONFIG (9 ),
100
111
};
101
112
102
113
/* BLE Peripheral Device (this Intel Curie device) */
103
- BlePeripheral bleDevice (DEVICE_NAME) ;
114
+ BlePeripheral bleDevice;
104
115
105
116
/* BLE Automation I/O Service */
106
117
BleService ioService (SERVICE_UUID_AUTOMATIONIO);
@@ -115,16 +126,33 @@ BleService ioService(SERVICE_UUID_AUTOMATIONIO);
115
126
116
127
#define ARRAY_SIZE (x ) (sizeof (x)/sizeof (x)[0 ])
117
128
129
+ /* Serial port to use for printing informational messages to the user */
130
+ #define LOG_SERIAL Serial
131
+
132
+ /* For convenience, this macro will invoke a specified function call and will
133
+ * check the status value returned to ensure it is successful. If not, it will
134
+ * print an error message to the serial port and will return from the current function
135
+ */
136
+ #define CHECK_STATUS (op ) \
137
+ do { \
138
+ BleStatus status = op; \
139
+ if (BLE_STATUS_SUCCESS != status) { \
140
+ LOG_SERIAL.print (#op" returned error status: " ); \
141
+ LOG_SERIAL.println (status); \
142
+ return ; \
143
+ } \
144
+ } while (0 )
145
+
118
146
/* This function will be called when a BLE GAP event is detected by the
119
147
* Intel Curie BLE device */
120
148
void blePeripheralEventCb (BlePeripheral &peripheral, BlePeripheralEvent event, void *arg)
121
149
{
122
150
if (BLE_PERIPH_EVENT_CONNECTED == event) {
123
- Serial .println (" Got CONNECTED event" );
151
+ LOG_SERIAL .println (" Got CONNECTED event" );
124
152
} else if (BLE_PERIPH_EVENT_DISCONNECTED == event) {
125
- Serial .println (" Got DISCONNECTED event" );
153
+ LOG_SERIAL .println (" Got DISCONNECTED event" );
126
154
} else {
127
- Serial .println (" Got UNKNOWN peripheral event" );
155
+ LOG_SERIAL .println (" Got UNKNOWN peripheral event" );
128
156
}
129
157
}
130
158
@@ -140,7 +168,7 @@ void digitalOutputCharEventCb(BleCharacteristic &characteristic, BleCharacterist
140
168
/* Update the state of the pin to reflect the new value */
141
169
digitalWrite (pin, VAL_TO_DIGITAL_PIN_STATE (pin, val));
142
170
} else
143
- Serial .println (" Got UNKNOWN characteristic event" );
171
+ LOG_SERIAL .println (" Got UNKNOWN characteristic event" );
144
172
}
145
173
146
174
/* This function will be called when a connected remote peer sets a new value for an analog output characteristic */
@@ -156,110 +184,145 @@ void analogOutputCharEventCb(BleCharacteristic &characteristic, BleCharacteristi
156
184
analogWrite (pin, val);
157
185
}
158
186
else
159
- Serial .println (" Got UNKNOWN characteristic event" );
187
+ LOG_SERIAL .println (" Got UNKNOWN characteristic event" );
160
188
}
161
189
162
190
void setup () {
163
- Serial.begin (115200 );
191
+ LOG_SERIAL.begin (115200 );
192
+
193
+ /* Set a name for the BLE device */
194
+ CHECK_STATUS (bleDevice.setName (DEVICE_NAME));
164
195
165
196
/* First, initialise the BLE device */
166
- bleDevice.init ();
197
+ CHECK_STATUS ( bleDevice.init () );
167
198
168
199
/* Set a function to be called whenever a BLE GAP event occurs */
169
200
bleDevice.setEventCallback (blePeripheralEventCb);
170
201
171
202
/* Add the Automation I/O Service, and include the UUID in BLE advertising data */
172
- bleDevice.addPrimaryService (ioService, true );
203
+ CHECK_STATUS ( bleDevice.addPrimaryService (ioService, true ) );
173
204
174
205
/* Add characteristics for the Digital Inputs */
175
206
for (unsigned i = 0 ; i < ARRAY_SIZE (digitalInputPins); i++) {
176
- PinConfig *pin = &digitalInputPins[i];
207
+ DigitalPinConfig *pin = &digitalInputPins[i];
177
208
178
209
/* Configure this pin as an input */
179
210
pinMode (pin->pin , INPUT);
180
211
181
212
/* Add the User-Description for this pin */
182
- pin->characteristic .addUserDescription (pin->name );
183
- /* Add the Presentation-Format for this pin */
184
- pin->characteristic .addPresentationFormat (0x2 , 0 , 0x2700 , 0x1 , pin->pin + 1 );
213
+ CHECK_STATUS (pin->characteristic .addUserDescription (pin->name ));
214
+ /* Add the Presentation-Format for this pin
215
+ * format: 0x2 (unsigned 2-bit integer)
216
+ * exponent: 0 (Not Applicable)
217
+ * unit: 0x2700 (BLE GATT Unit UUID: unitless)
218
+ * nameSpace: 0x1 (Bluetooth standard namespace)
219
+ * description: pin+1 (Instance number of this characteristic)
220
+ */
221
+ CHECK_STATUS (pin->characteristic .addPresentationFormat (0x2 , 0 , 0x2700 , 0x1 , pin->pin + 1 ));
185
222
/* Add the characteristic for this pin */
186
- ioService.addCharacteristic (pin->characteristic );
223
+ CHECK_STATUS ( ioService.addCharacteristic (pin->characteristic ) );
187
224
/* Set an initial value for this characteristic; refreshed later in the loop() function */
188
- pin->characteristic .setValue (DIGITAL_PIN_STATE_TO_VAL (pin->pin , digitalRead (pin->pin )));
225
+ pin->val = digitalRead (pin->pin );
226
+ CHECK_STATUS (pin->characteristic .setValue (DIGITAL_PIN_STATE_TO_VAL (pin->pin , pin->val )));
189
227
/* Add a number_of_digitals descriptor for this characteristic */
190
- BleDescriptor numDigitalsDesc (DESC_UUID_NUMDIGITALS, sizeof (uint8_t ), BLE_CLIENT_ACCESS_READ_ONLY);
191
- pin->characteristic .addDescriptor (numDigitalsDesc);
192
- numDigitalsDesc.setValue ((uint8_t ) 1 );
193
- }
228
+ CHECK_STATUS (pin->characteristic .addDescriptor (pin->numDigitalsDesc ));
229
+ CHECK_STATUS (pin->numDigitalsDesc .setValue ((uint8_t ) 1 ));
230
+ }
194
231
195
232
/* Add characteristics for the Digital Outputs */
196
233
for (unsigned i = 0 ; i < ARRAY_SIZE (digitalOutputPins); i++) {
197
- PinConfig *pin = &digitalOutputPins[i];
234
+ DigitalPinConfig *pin = &digitalOutputPins[i];
198
235
199
236
/* Configure this pin as an output */
200
237
pinMode (pin->pin , OUTPUT);
201
238
202
239
/* Add the User-Description for this pin */
203
- pin->characteristic .addUserDescription (pin->name );
204
- /* Add the Presentation-Format for this pin */
205
- pin->characteristic .addPresentationFormat (0x2 , 0 , 0x2700 , 0x1 , pin->pin + 1 );
240
+ CHECK_STATUS (pin->characteristic .addUserDescription (pin->name ));
241
+ /* Add the Presentation-Format for this pin
242
+ * format: 0x2 (unsigned 2-bit integer)
243
+ * exponent: 0 (Not Applicable)
244
+ * unit: 0x2700 (BLE GATT Unit UUID: unitless)
245
+ * nameSpace: 0x1 (Bluetooth standard namespace)
246
+ * description: pin+1 (Instance number of this characteristic)
247
+ */
248
+ CHECK_STATUS (pin->characteristic .addPresentationFormat (0x2 , 0 , 0x2700 , 0x1 , pin->pin + 1 ));
206
249
/* Add the characteristic for this pin */
207
- ioService.addCharacteristic (pin->characteristic );
250
+ CHECK_STATUS ( ioService.addCharacteristic (pin->characteristic ) );
208
251
/* Add a callback to be triggered if the remote device updates the value for this pin */
209
252
pin->characteristic .setEventCallback (digitalOutputCharEventCb, (void *)pin->pin );
210
253
/* Add a number_of_digitals descriptor for this characteristic */
211
- BleDescriptor numDigitalsDesc (DESC_UUID_NUMDIGITALS, sizeof (uint8_t ), BLE_CLIENT_ACCESS_READ_ONLY);
212
- pin->characteristic .addDescriptor (numDigitalsDesc);
213
- numDigitalsDesc.setValue ((uint8_t ) 1 );
254
+ CHECK_STATUS (pin->characteristic .addDescriptor (pin->numDigitalsDesc ));
255
+ CHECK_STATUS (pin->numDigitalsDesc .setValue ((uint8_t ) 1 ));
214
256
}
215
257
216
258
/* Add characteristics for the Analog Inputs */
217
259
for (unsigned i = 0 ; i < ARRAY_SIZE (analogInputPins); i++) {
218
- PinConfig *pin = &analogInputPins[i];
260
+ AnalogPinConfig *pin = &analogInputPins[i];
219
261
220
262
/* Add the User-Description for this pin */
221
- pin->characteristic .addUserDescription (pin->name );
222
- /* Add the Presentation-Format for this pin */
223
- pin->characteristic .addPresentationFormat (0x6 , 0 , 0x2700 , 0x1 , pin->pin + 1 );
263
+ CHECK_STATUS (pin->characteristic .addUserDescription (pin->name ));
264
+ /* Add the Presentation-Format for this pin
265
+ * format: 0x6 (unsigned 16-bit integer)
266
+ * exponent: 0 (Not Applicable)
267
+ * unit: 0x2700 (BLE GATT Unit UUID: unitless)
268
+ * nameSpace: 0x1 (Bluetooth standard namespace)
269
+ * description: pin+1 (Instance number of this characteristic)
270
+ */
271
+ CHECK_STATUS (pin->characteristic .addPresentationFormat (0x6 , 0 , 0x2700 , 0x1 , pin->pin + 1 ));
224
272
/* Add the characteristic for this pin */
225
- ioService.addCharacteristic (pin->characteristic );
273
+ CHECK_STATUS ( ioService.addCharacteristic (pin->characteristic ) );
226
274
/* Set an initial value for this characteristic; refreshed later in the loop() function */
227
- pin->characteristic .setValue ((uint16_t )analogRead (pin->pin ));
275
+ pin->val = analogRead (pin->pin );
276
+ CHECK_STATUS (pin->characteristic .setValue (pin->val ));
228
277
}
229
278
230
279
/* Add characteristics for the Analog Outputs */
231
280
for (unsigned i = 0 ; i < ARRAY_SIZE (analogOutputPins); i++) {
232
- PinConfig *pin = &analogOutputPins[i];
281
+ AnalogPinConfig *pin = &analogOutputPins[i];
233
282
234
283
/* Add the User-Description for this pin */
235
- pin->characteristic .addUserDescription (pin->name );
236
- /* Add the Presentation-Format for this pin */
237
- pin->characteristic .addPresentationFormat (0x6 , 0 , 0x2700 , 0x1 , pin->pin + 1 );
284
+ CHECK_STATUS (pin->characteristic .addUserDescription (pin->name ));
285
+ /* Add the Presentation-Format for this pin
286
+ * format: 0x6 (unsigned 16-bit integer)
287
+ * exponent: 0 (Not Applicable)
288
+ * unit: 0x2700 (BLE GATT Unit UUID: unitless)
289
+ * nameSpace: 0x1 (Bluetooth standard namespace)
290
+ * description: pin+1 (Instance number of this characteristic)
291
+ */
292
+ CHECK_STATUS (pin->characteristic .addPresentationFormat (0x6 , 0 , 0x2700 , 0x1 , pin->pin + 1 ));
238
293
/* Add the characteristic for this pin */
239
- ioService.addCharacteristic (pin->characteristic );
294
+ CHECK_STATUS ( ioService.addCharacteristic (pin->characteristic ) );
240
295
/* Add a callback to be triggered if the remote device updates the value for this pin */
241
296
pin->characteristic .setEventCallback (analogOutputCharEventCb, (void *)pin->pin );
242
297
}
243
298
244
299
/* Now activate the BLE device. It will start continuously transmitting BLE
245
300
* advertising packets and thus become visible to remote BLE central devices
246
301
* (e.g smartphones) until it receives a new connection */
247
- if (BLE_STATUS_SUCCESS == bleDevice.start ())
248
- Serial .println (" Bluetooth device active, waiting for connections..." );
302
+ CHECK_STATUS ( bleDevice.start ());
303
+ LOG_SERIAL .println (" Bluetooth device active, waiting for connections..." );
249
304
}
250
305
251
306
void loop () {
252
307
/* Update the digital input characteristics based on current pin reading */
253
308
for (unsigned i = 0 ; i < ARRAY_SIZE (digitalInputPins); i++) {
254
- PinConfig *pin = &digitalInputPins[i];
255
- pin->characteristic .setValue (DIGITAL_PIN_STATE_TO_VAL (pin->pin , digitalRead (pin->pin )));
309
+ DigitalPinConfig *pin = &digitalInputPins[i];
310
+ uint8_t newVal = digitalRead (pin->pin );
311
+ if (newVal != pin->val ) {
312
+ CHECK_STATUS (pin->characteristic .setValue (DIGITAL_PIN_STATE_TO_VAL (pin->pin , newVal)));
313
+ pin->val = newVal;
314
+ }
256
315
}
257
316
/* Update the analog input characteristics based on current pin reading*/
258
317
for (unsigned i = 0 ; i < ARRAY_SIZE (analogInputPins); i++) {
259
- PinConfig *pin = &analogInputPins[i];
260
- pin->characteristic .setValue ((uint16_t )analogRead (pin->pin ));
318
+ AnalogPinConfig *pin = &analogInputPins[i];
319
+ uint16_t newVal = analogRead (pin->pin );
320
+ if (newVal != pin->val ) {
321
+ CHECK_STATUS (pin->characteristic .setValue (newVal));
322
+ pin->val = newVal;
323
+ }
261
324
}
262
325
263
- /* Repeat the loop every 200ms - can be changed if desired */
264
- delay (200 );
326
+ /* Repeat the loop every 500ms - can be changed if desired */
327
+ delay (500 );
265
328
}
0 commit comments