Skip to content

Commit 9314b22

Browse files
Dan-LightsourceBrian Baltz
authored and
Brian Baltz
committed
ble: address code review comments from Manoel Ramon
- Added checks in example sketches for API return values - Applying Public MAC address if present in factory data - Applying default device name if user doesn't provide one - Only issuing notifications/indications if enabled by peer - Re-sync'd with latest BLE code from Thunderdome - Added basic DTM support for use in sketch (for internal testing) - Other minor updates, corrections and clarifications Signed-off-by: Dan O'Donovan <dan@emutex.com>
1 parent a709e25 commit 9314b22

22 files changed

+1493
-358
lines changed

libraries/CurieBle/examples/AutomationIO/AutomationIO.ino

Lines changed: 119 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323

2424
/*
2525
* 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+
*
2629
* For more information: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
2730
*/
2831

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 */
3033
#define DEVICE_NAME "AE_IO"
3134
/* UUID for Automation I/O service */
3235
#define SERVICE_UUID_AUTOMATIONIO (0x1815)
@@ -41,19 +44,28 @@
4144
* This helps us to build lists of pins below to allow
4245
* flexible pin assignments to different modes of operation
4346
*/
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 {
4556
unsigned pin;
4657
const char *name;
4758
BleCharacteristic characteristic;
59+
uint16_t val;
4860
};
4961

5062
/* Macros to simplify the definition of a new PinConfig struct for a given pin number
5163
* Note that input pins are only readable by the remote device, while output pins are
5264
* only writable. Different characteristic UUIDs are used for digital and analog pins */
5365
#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} }
5567
#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} }
5769
#define ANALOG_INPUT_PINCONFIG(pin) \
5870
{ (pin), #pin, {CHAR_UUID_ANALOG, sizeof(uint16_t), BLE_CLIENT_ACCESS_READ_ONLY, BLE_CLIENT_NOTIFY_ENABLED} }
5971
#define ANALOG_OUTPUT_PINCONFIG(pin) \
@@ -68,39 +80,38 @@ struct PinConfig {
6880
* - pins 0-19 are valid for digital input/output
6981
* - pins 14-19 are valid for analog input
7082
* - pins 3,5,6,9 are valid for analog output
83+
* - a maximum of 16 pins are currently supported (limited by number of characteristics)
7184
*/
72-
struct PinConfig digitalInputPins[] = {
85+
struct DigitalPinConfig digitalInputPins[] = {
7386
DIGITAL_INPUT_PINCONFIG(2),
7487
DIGITAL_INPUT_PINCONFIG(4),
7588
DIGITAL_INPUT_PINCONFIG(7),
7689
};
7790

78-
struct PinConfig digitalOutputPins[] = {
91+
struct DigitalPinConfig digitalOutputPins[] = {
7992
DIGITAL_OUTPUT_PINCONFIG(8),
8093
DIGITAL_OUTPUT_PINCONFIG(10),
8194
DIGITAL_OUTPUT_PINCONFIG(11),
8295
DIGITAL_OUTPUT_PINCONFIG(12),
8396
DIGITAL_OUTPUT_PINCONFIG(13),
8497
};
8598

86-
struct PinConfig analogInputPins[] = {
99+
struct AnalogPinConfig analogInputPins[] = {
87100
ANALOG_INPUT_PINCONFIG(14),
88101
ANALOG_INPUT_PINCONFIG(15),
89102
ANALOG_INPUT_PINCONFIG(16),
90103
ANALOG_INPUT_PINCONFIG(17),
91-
ANALOG_INPUT_PINCONFIG(18),
92-
ANALOG_INPUT_PINCONFIG(19),
93104
};
94105

95-
struct PinConfig analogOutputPins[] = {
106+
struct AnalogPinConfig analogOutputPins[] = {
96107
ANALOG_OUTPUT_PINCONFIG(3),
97108
ANALOG_OUTPUT_PINCONFIG(5),
98109
ANALOG_OUTPUT_PINCONFIG(6),
99110
ANALOG_OUTPUT_PINCONFIG(9),
100111
};
101112

102113
/* BLE Peripheral Device (this Intel Curie device) */
103-
BlePeripheral bleDevice(DEVICE_NAME);
114+
BlePeripheral bleDevice;
104115

105116
/* BLE Automation I/O Service */
106117
BleService ioService(SERVICE_UUID_AUTOMATIONIO);
@@ -115,16 +126,33 @@ BleService ioService(SERVICE_UUID_AUTOMATIONIO);
115126

116127
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x)[0])
117128

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+
118146
/* This function will be called when a BLE GAP event is detected by the
119147
* Intel Curie BLE device */
120148
void blePeripheralEventCb(BlePeripheral &peripheral, BlePeripheralEvent event, void *arg)
121149
{
122150
if (BLE_PERIPH_EVENT_CONNECTED == event) {
123-
Serial.println("Got CONNECTED event");
151+
LOG_SERIAL.println("Got CONNECTED event");
124152
} else if (BLE_PERIPH_EVENT_DISCONNECTED == event) {
125-
Serial.println("Got DISCONNECTED event");
153+
LOG_SERIAL.println("Got DISCONNECTED event");
126154
} else {
127-
Serial.println("Got UNKNOWN peripheral event");
155+
LOG_SERIAL.println("Got UNKNOWN peripheral event");
128156
}
129157
}
130158

@@ -140,7 +168,7 @@ void digitalOutputCharEventCb(BleCharacteristic &characteristic, BleCharacterist
140168
/* Update the state of the pin to reflect the new value */
141169
digitalWrite(pin, VAL_TO_DIGITAL_PIN_STATE(pin, val));
142170
} else
143-
Serial.println("Got UNKNOWN characteristic event");
171+
LOG_SERIAL.println("Got UNKNOWN characteristic event");
144172
}
145173

146174
/* 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
156184
analogWrite(pin, val);
157185
}
158186
else
159-
Serial.println("Got UNKNOWN characteristic event");
187+
LOG_SERIAL.println("Got UNKNOWN characteristic event");
160188
}
161189

162190
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));
164195

165196
/* First, initialise the BLE device */
166-
bleDevice.init();
197+
CHECK_STATUS(bleDevice.init());
167198

168199
/* Set a function to be called whenever a BLE GAP event occurs */
169200
bleDevice.setEventCallback(blePeripheralEventCb);
170201

171202
/* 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));
173204

174205
/* Add characteristics for the Digital Inputs */
175206
for (unsigned i = 0; i < ARRAY_SIZE(digitalInputPins); i++) {
176-
PinConfig *pin = &digitalInputPins[i];
207+
DigitalPinConfig *pin = &digitalInputPins[i];
177208

178209
/* Configure this pin as an input */
179210
pinMode(pin->pin, INPUT);
180211

181212
/* 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));
185222
/* Add the characteristic for this pin */
186-
ioService.addCharacteristic(pin->characteristic);
223+
CHECK_STATUS(ioService.addCharacteristic(pin->characteristic));
187224
/* 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)));
189227
/* 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+
}
194231

195232
/* Add characteristics for the Digital Outputs */
196233
for (unsigned i = 0; i < ARRAY_SIZE(digitalOutputPins); i++) {
197-
PinConfig *pin = &digitalOutputPins[i];
234+
DigitalPinConfig *pin = &digitalOutputPins[i];
198235

199236
/* Configure this pin as an output */
200237
pinMode(pin->pin, OUTPUT);
201238

202239
/* 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));
206249
/* Add the characteristic for this pin */
207-
ioService.addCharacteristic(pin->characteristic);
250+
CHECK_STATUS(ioService.addCharacteristic(pin->characteristic));
208251
/* Add a callback to be triggered if the remote device updates the value for this pin */
209252
pin->characteristic.setEventCallback(digitalOutputCharEventCb, (void*)pin->pin);
210253
/* 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));
214256
}
215257

216258
/* Add characteristics for the Analog Inputs */
217259
for (unsigned i = 0; i < ARRAY_SIZE(analogInputPins); i++) {
218-
PinConfig *pin = &analogInputPins[i];
260+
AnalogPinConfig *pin = &analogInputPins[i];
219261

220262
/* 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));
224272
/* Add the characteristic for this pin */
225-
ioService.addCharacteristic(pin->characteristic);
273+
CHECK_STATUS(ioService.addCharacteristic(pin->characteristic));
226274
/* 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));
228277
}
229278

230279
/* Add characteristics for the Analog Outputs */
231280
for (unsigned i = 0; i < ARRAY_SIZE(analogOutputPins); i++) {
232-
PinConfig *pin = &analogOutputPins[i];
281+
AnalogPinConfig *pin = &analogOutputPins[i];
233282

234283
/* 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));
238293
/* Add the characteristic for this pin */
239-
ioService.addCharacteristic(pin->characteristic);
294+
CHECK_STATUS(ioService.addCharacteristic(pin->characteristic));
240295
/* Add a callback to be triggered if the remote device updates the value for this pin */
241296
pin->characteristic.setEventCallback(analogOutputCharEventCb, (void*)pin->pin);
242297
}
243298

244299
/* Now activate the BLE device. It will start continuously transmitting BLE
245300
* advertising packets and thus become visible to remote BLE central devices
246301
* (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...");
249304
}
250305

251306
void loop() {
252307
/* Update the digital input characteristics based on current pin reading */
253308
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+
}
256315
}
257316
/* Update the analog input characteristics based on current pin reading*/
258317
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+
}
261324
}
262325

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);
265328
}

0 commit comments

Comments
 (0)