example firmware for nRF51-Dongle to use with Opentrigger

Dependencies:   BLE_API mbed nRF51822

Fork of BLE_Button by Bluetooth Low Energy

http://www.opentrigger.com

Committer:
0xf10
Date:
Tue Jun 14 18:04:25 2016 +0000
Revision:
17:33d38b30e640
Parent:
16:7a9fde930f8a
Child:
18:2b328834f64f
safety

Who changed what in which revision?

UserRevisionLine numberNew contents of line
0xf10 15:9f9f5d82743d 1 /* nRF51 mbed opentrigger example
0xf10 15:9f9f5d82743d 2 * Copyright (c) 2016 Florian Fida
0xf10 15:9f9f5d82743d 3 *
0xf10 15:9f9f5d82743d 4 * based on 'Demo for an Input Service'
0xf10 15:9f9f5d82743d 5 * https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_Button/
0xf10 15:9f9f5d82743d 6 *
rgrover1 0:28f095301cb2 7 *
rgrover1 0:28f095301cb2 8 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 0:28f095301cb2 9 * you may not use this file except in compliance with the License.
rgrover1 0:28f095301cb2 10 * You may obtain a copy of the License at
rgrover1 0:28f095301cb2 11 *
rgrover1 0:28f095301cb2 12 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 0:28f095301cb2 13 *
rgrover1 0:28f095301cb2 14 * Unless required by applicable law or agreed to in writing, software
rgrover1 0:28f095301cb2 15 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 0:28f095301cb2 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 0:28f095301cb2 17 * See the License for the specific language governing permissions and
rgrover1 0:28f095301cb2 18 * limitations under the License.
rgrover1 0:28f095301cb2 19 */
rgrover1 0:28f095301cb2 20
rgrover1 0:28f095301cb2 21 #include "mbed.h"
andresag 10:7943b5c1117a 22 #include "ble/BLE.h"
rgrover1 0:28f095301cb2 23
0xf10 16:7a9fde930f8a 24 DigitalOut led1(LED1); /* RED : Indicating a pressed button */
0xf10 16:7a9fde930f8a 25 DigitalOut led2(LED2); /* GREEN : Blinking to indicate that the device is running */
0xf10 16:7a9fde930f8a 26 DigitalOut led3(LED3); /* BLUE : Only on when advertising */
0xf10 15:9f9f5d82743d 27
0xf10 14:09f208b24460 28 InterruptIn button0(P0_15);
0xf10 14:09f208b24460 29 InterruptIn button1(P0_16);
0xf10 14:09f208b24460 30 InterruptIn button2(P0_17);
0xf10 14:09f208b24460 31 InterruptIn button3(P0_18);
0xf10 14:09f208b24460 32 InterruptIn button4(P0_19);
0xf10 14:09f208b24460 33 InterruptIn button5(P0_20);
rgrover1 0:28f095301cb2 34
0xf10 13:0f26a3fc1f32 35 const uint16_t MIN_ADVERT_INTERVAL = 50; /* msec */
0xf10 16:7a9fde930f8a 36 static uint8_t gpio_states[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; /* initial state is up */
rgrover1 0:28f095301cb2 37
rgrover1 9:0f6951db24f1 38 enum {
rgrover1 9:0f6951db24f1 39 RELEASED = 0,
rgrover1 9:0f6951db24f1 40 PRESSED,
rgrover1 9:0f6951db24f1 41 IDLE
rgrover1 9:0f6951db24f1 42 };
rgrover1 9:0f6951db24f1 43 static uint8_t buttonState = IDLE;
rgrover1 9:0f6951db24f1 44
0xf10 11:5b6d98e98127 45 void blinkLed(void){
0xf10 12:2cb903df877d 46 led2 = !led2;
0xf10 11:5b6d98e98127 47 }
0xf10 11:5b6d98e98127 48
0xf10 14:09f208b24460 49 void button0PressedCallback(void)
rgrover1 0:28f095301cb2 50 {
rgrover1 9:0f6951db24f1 51 /* Note that the buttonPressedCallback() executes in interrupt context, so it is safer to access
rgrover1 9:0f6951db24f1 52 * BLE device API from the main thread. */
rgrover1 9:0f6951db24f1 53 buttonState = PRESSED;
0xf10 16:7a9fde930f8a 54 gpio_states[0]=0x00;
rgrover1 0:28f095301cb2 55 }
rgrover1 0:28f095301cb2 56
0xf10 14:09f208b24460 57 void button0ReleasedCallback(void)
rgrover1 0:28f095301cb2 58 {
rgrover1 9:0f6951db24f1 59 /* Note that the buttonReleasedCallback() executes in interrupt context, so it is safer to access
rgrover1 9:0f6951db24f1 60 * BLE device API from the main thread. */
rgrover1 9:0f6951db24f1 61 buttonState = RELEASED;
0xf10 16:7a9fde930f8a 62 gpio_states[0]=0x01;
rgrover1 0:28f095301cb2 63 }
rgrover1 0:28f095301cb2 64
0xf10 14:09f208b24460 65
0xf10 16:7a9fde930f8a 66 // Callbacks for the other 5 Buttons
0xf10 16:7a9fde930f8a 67 void button1PressedCallback(void) { buttonState = PRESSED; gpio_states[1]=0x00; }
0xf10 16:7a9fde930f8a 68 void button1ReleasedCallback(void){ buttonState = RELEASED; gpio_states[1]=0x01; }
0xf10 16:7a9fde930f8a 69 void button2PressedCallback(void) { buttonState = PRESSED; gpio_states[2]=0x00; }
0xf10 16:7a9fde930f8a 70 void button2ReleasedCallback(void){ buttonState = RELEASED; gpio_states[2]=0x01; }
0xf10 16:7a9fde930f8a 71 void button3PressedCallback(void) { buttonState = PRESSED; gpio_states[3]=0x00; }
0xf10 16:7a9fde930f8a 72 void button3ReleasedCallback(void){ buttonState = RELEASED; gpio_states[3]=0x01; }
0xf10 16:7a9fde930f8a 73 void button4PressedCallback(void) { buttonState = PRESSED; gpio_states[4]=0x00; }
0xf10 16:7a9fde930f8a 74 void button4ReleasedCallback(void){ buttonState = RELEASED; gpio_states[4]=0x01; }
0xf10 16:7a9fde930f8a 75 void button5PressedCallback(void) { buttonState = PRESSED; gpio_states[5]=0x00; }
0xf10 16:7a9fde930f8a 76 void button5ReleasedCallback(void){ buttonState = RELEASED; gpio_states[5]=0x01; }
0xf10 16:7a9fde930f8a 77
0xf10 16:7a9fde930f8a 78 // Just in case
rgrover1 8:a7ba7aaba460 79 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
rgrover1 0:28f095301cb2 80 {
andresag 10:7943b5c1117a 81 BLE::Instance().gap().startAdvertising();
rgrover1 0:28f095301cb2 82 }
rgrover1 0:28f095301cb2 83
rgrover1 0:28f095301cb2 84 void periodicCallback(void)
rgrover1 0:28f095301cb2 85 {
0xf10 12:2cb903df877d 86 blinkLed();
rgrover1 0:28f095301cb2 87 }
rgrover1 0:28f095301cb2 88
andresag 10:7943b5c1117a 89 /**
andresag 10:7943b5c1117a 90 * This function is called when the ble initialization process has failled
andresag 10:7943b5c1117a 91 */
0xf10 14:09f208b24460 92 void onBleInitError(BLE &ble, ble_error_t bt_error)
andresag 10:7943b5c1117a 93 {
andresag 10:7943b5c1117a 94 /* Initialization error handling should go here */
0xf10 15:9f9f5d82743d 95
0xf10 15:9f9f5d82743d 96 printf("bt_error=%i\n\r",bt_error);
0xf10 13:0f26a3fc1f32 97 error("Panic!");
andresag 10:7943b5c1117a 98 }
andresag 10:7943b5c1117a 99
0xf10 16:7a9fde930f8a 100 bool gpioSet(void){
0xf10 16:7a9fde930f8a 101 return
0xf10 16:7a9fde930f8a 102 gpio_states[0] == 0x00 ||
0xf10 16:7a9fde930f8a 103 gpio_states[1] == 0x00 ||
0xf10 16:7a9fde930f8a 104 gpio_states[2] == 0x00 ||
0xf10 16:7a9fde930f8a 105 gpio_states[3] == 0x00 ||
0xf10 16:7a9fde930f8a 106 gpio_states[4] == 0x00 ||
0xf10 16:7a9fde930f8a 107 gpio_states[5] == 0x00
0xf10 16:7a9fde930f8a 108 ;
0xf10 16:7a9fde930f8a 109 }
0xf10 16:7a9fde930f8a 110
0xf10 16:7a9fde930f8a 111 void updateManufacturerData(void){
0xf10 16:7a9fde930f8a 112
0xf10 16:7a9fde930f8a 113 // disable interrupts while building the package to avoid a race condition
0xf10 16:7a9fde930f8a 114 __disable_irq();
0xf10 16:7a9fde930f8a 115
0xf10 14:09f208b24460 116 // http://tokencube.com/bluetooth-sensor.html
0xf10 13:0f26a3fc1f32 117 uint8_t data[] = {
0xf10 13:0f26a3fc1f32 118 0xee, 0xff, // Tokencube Manufacturer ID
0xf10 13:0f26a3fc1f32 119 0x04, // Token Module Version
0xf10 13:0f26a3fc1f32 120 0x01, // Firmware Version
0xf10 13:0f26a3fc1f32 121 0x11, // Page 1 of 1
0xf10 16:7a9fde930f8a 122 0x07, gpioSet() ? 0x01 : 0x00, // pir value (0x00 = off, 0x01 = on)
0xf10 14:09f208b24460 123 // custom data - state of all 6 gpio's
0xf10 16:7a9fde930f8a 124 // 0x00 = down, 0x01 = up
0xf10 14:09f208b24460 125 0x0F, gpio_states[0], gpio_states[1], gpio_states[2], gpio_states[3], gpio_states[4], gpio_states[5]
0xf10 13:0f26a3fc1f32 126 };
0xf10 16:7a9fde930f8a 127
0xf10 16:7a9fde930f8a 128 __enable_irq();
0xf10 11:5b6d98e98127 129 BLE::Instance().gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, data, sizeof(data));
0xf10 11:5b6d98e98127 130 }
0xf10 11:5b6d98e98127 131
andresag 10:7943b5c1117a 132 /**
andresag 10:7943b5c1117a 133 * Callback triggered when the ble initialization process has finished
andresag 10:7943b5c1117a 134 */
andresag 10:7943b5c1117a 135 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
andresag 10:7943b5c1117a 136 {
andresag 10:7943b5c1117a 137 BLE& ble = params->ble;
andresag 10:7943b5c1117a 138 ble_error_t error = params->error;
andresag 10:7943b5c1117a 139
andresag 10:7943b5c1117a 140 if (error != BLE_ERROR_NONE) {
andresag 10:7943b5c1117a 141 /* In case of error, forward the error handling to onBleInitError */
andresag 10:7943b5c1117a 142 onBleInitError(ble, error);
andresag 10:7943b5c1117a 143 return;
andresag 10:7943b5c1117a 144 }
andresag 10:7943b5c1117a 145
andresag 10:7943b5c1117a 146 /* Ensure that it is the default instance of BLE */
andresag 10:7943b5c1117a 147 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
andresag 10:7943b5c1117a 148 return;
andresag 10:7943b5c1117a 149 }
0xf10 11:5b6d98e98127 150
0xf10 13:0f26a3fc1f32 151 uint8_t macAddress[6] = {0x00};
0xf10 13:0f26a3fc1f32 152 BLEProtocol::AddressType_t pubAddr = BLEProtocol::AddressType::PUBLIC;
0xf10 13:0f26a3fc1f32 153 ble.gap().getAddress(&pubAddr, macAddress);
0xf10 13:0f26a3fc1f32 154
0xf10 13:0f26a3fc1f32 155 /* change device MAC address */
0xf10 13:0f26a3fc1f32 156 //const uint8_t address1[] = {0xe7,0xAA,0xAA,0xAA,0xAA,0xAA};
0xf10 13:0f26a3fc1f32 157 //ble.gap().setAddress(pubAddr, address1);
andresag 10:7943b5c1117a 158
andresag 10:7943b5c1117a 159 ble.gap().onDisconnection(disconnectionCallback);
andresag 10:7943b5c1117a 160
andresag 10:7943b5c1117a 161 /* setup advertising */
andresag 10:7943b5c1117a 162 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
andresag 10:7943b5c1117a 163 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
0xf10 13:0f26a3fc1f32 164
0xf10 15:9f9f5d82743d 165 ble.gap().setAdvertisingInterval(MIN_ADVERT_INTERVAL);
0xf10 16:7a9fde930f8a 166 updateManufacturerData();
0xf10 15:9f9f5d82743d 167 error = ble.gap().startAdvertising();
0xf10 15:9f9f5d82743d 168 if (error != BLE_ERROR_NONE) onBleInitError(ble, error);
0xf10 13:0f26a3fc1f32 169
0xf10 13:0f26a3fc1f32 170 // Print Interval and MAC Address
0xf10 15:9f9f5d82743d 171 uint16_t minInterval = ble.gap().getMinAdvertisingInterval();
0xf10 15:9f9f5d82743d 172 printf("MinAdvertisingInterval = %i\n\r", minInterval);
0xf10 13:0f26a3fc1f32 173 printf("MAC Address = %02X:%02X:%02X:%02X:%02X:%02X\n\r", macAddress[5], macAddress[4], macAddress[3], macAddress[2], macAddress[1], macAddress[0]);
andresag 10:7943b5c1117a 174
andresag 10:7943b5c1117a 175 }
andresag 10:7943b5c1117a 176
rgrover1 0:28f095301cb2 177 int main(void)
rgrover1 0:28f095301cb2 178 {
rgrover1 0:28f095301cb2 179 Ticker ticker;
0xf10 14:09f208b24460 180
0xf10 16:7a9fde930f8a 181 // Turn off all LED's
0xf10 15:9f9f5d82743d 182 led1 = !0; led2 = !0; led3 = !0;
0xf10 14:09f208b24460 183
0xf10 16:7a9fde930f8a 184 // Put all GPIO's in PullUp mode, so we do not need pullup resistors.
0xf10 16:7a9fde930f8a 185 button0.mode(PullUp);
0xf10 16:7a9fde930f8a 186 button1.mode(PullUp);
0xf10 16:7a9fde930f8a 187 button2.mode(PullUp);
0xf10 16:7a9fde930f8a 188 button3.mode(PullUp);
0xf10 16:7a9fde930f8a 189 button4.mode(PullUp);
0xf10 16:7a9fde930f8a 190 button5.mode(PullUp);
0xf10 16:7a9fde930f8a 191
0xf10 16:7a9fde930f8a 192 // Setup handler for all buttons
0xf10 14:09f208b24460 193 button0.fall(button0PressedCallback);
0xf10 14:09f208b24460 194 button0.rise(button0ReleasedCallback);
0xf10 14:09f208b24460 195 button1.fall(button1PressedCallback);
0xf10 14:09f208b24460 196 button1.rise(button1ReleasedCallback);
0xf10 14:09f208b24460 197 button2.fall(button2PressedCallback);
0xf10 14:09f208b24460 198 button2.rise(button2ReleasedCallback);
0xf10 14:09f208b24460 199 button3.fall(button3PressedCallback);
0xf10 14:09f208b24460 200 button3.rise(button3ReleasedCallback);
0xf10 14:09f208b24460 201 button4.fall(button4PressedCallback);
0xf10 14:09f208b24460 202 button4.rise(button4ReleasedCallback);
0xf10 14:09f208b24460 203 button5.fall(button5PressedCallback);
0xf10 14:09f208b24460 204 button5.rise(button5ReleasedCallback);
0xf10 16:7a9fde930f8a 205
0xf10 16:7a9fde930f8a 206 // This will make our green led blink
0xf10 16:7a9fde930f8a 207 ticker.attach(periodicCallback, 1);
rgrover1 0:28f095301cb2 208
andresag 10:7943b5c1117a 209 BLE &ble = BLE::Instance();
andresag 10:7943b5c1117a 210 ble.init(bleInitComplete);
andresag 10:7943b5c1117a 211
0xf10 15:9f9f5d82743d 212 /* SpinWait for initialization to complete. This is necessary because the BLE object is used in the main loop below. */
andresag 10:7943b5c1117a 213 while (ble.hasInitialized() == false) { /* spin loop */ }
andresag 10:7943b5c1117a 214
0xf10 15:9f9f5d82743d 215 uint8_t cnt = 0;
rgrover1 0:28f095301cb2 216 while (true) {
0xf10 16:7a9fde930f8a 217
0xf10 16:7a9fde930f8a 218 // we only care about situations where a button was pressed
andresag 10:7943b5c1117a 219 if (buttonState != IDLE) {
0xf10 16:7a9fde930f8a 220 if(buttonState == PRESSED) led1=!1;
0xf10 16:7a9fde930f8a 221 if(buttonState == RELEASED) led1=!0;
0xf10 16:7a9fde930f8a 222
0xf10 16:7a9fde930f8a 223 updateManufacturerData();
0xf10 15:9f9f5d82743d 224 cnt = 0;
rgrover1 9:0f6951db24f1 225 buttonState = IDLE;
rgrover1 9:0f6951db24f1 226 }
rgrover1 9:0f6951db24f1 227
0xf10 16:7a9fde930f8a 228 // stop advertising after 3 cycles
0xf10 15:9f9f5d82743d 229 if(cnt < 1){
0xf10 15:9f9f5d82743d 230 ble.gap().startAdvertising();
0xf10 15:9f9f5d82743d 231 led3 = !1;
0xf10 17:33d38b30e640 232 }else if(cnt == 1){
0xf10 17:33d38b30e640 233 updateManufacturerData();
0xf10 17:33d38b30e640 234 }else if(cnt > 3){
0xf10 15:9f9f5d82743d 235 ble.gap().stopAdvertising();
0xf10 15:9f9f5d82743d 236 led3 = !0;
0xf10 15:9f9f5d82743d 237 }else{
0xf10 16:7a9fde930f8a 238 if(!gpioSet()) cnt++;
0xf10 15:9f9f5d82743d 239 }
0xf10 15:9f9f5d82743d 240
rgrover1 0:28f095301cb2 241 ble.waitForEvent();
0xf10 15:9f9f5d82743d 242 //printf("cnt=%i\n\r",cnt);
rgrover1 0:28f095301cb2 243 }
rgrover1 0:28f095301cb2 244 }