Sample NordicSemicondictor nRF52 beacon discovery for CO657 (University of Kent, UK); builds on mbed-os, derived from LEDBeacon sample code (on github). Writes out beacons recently seen to serial port and/or LCD (#ifdef job) on the MBED application shield.
main.cpp@0:f4e27396137e, 2016-10-27 (annotated)
- Committer:
- co657_frmb
- Date:
- Thu Oct 27 16:53:49 2016 +0000
- Revision:
- 0:f4e27396137e
- Child:
- 1:7986f9873e20
First cut of code, uses MBED application shield plugged into nRF52
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
co657_frmb | 0:f4e27396137e | 1 | /* |
co657_frmb | 0:f4e27396137e | 2 | * main.cpp -- test program to _simply_ detect iBeacons (and anything else advertising in a similar way) |
co657_frmb | 0:f4e27396137e | 3 | * Fred Barnes, October 2016 |
co657_frmb | 0:f4e27396137e | 4 | */ |
co657_frmb | 0:f4e27396137e | 5 | |
co657_frmb | 0:f4e27396137e | 6 | /* NOTE: based heavily on mbed-os-example-ble's BLE_LEDBlinker example (trimmed down) */ |
co657_frmb | 0:f4e27396137e | 7 | |
co657_frmb | 0:f4e27396137e | 8 | /* Further note: this is a hack in places */ |
co657_frmb | 0:f4e27396137e | 9 | |
co657_frmb | 0:f4e27396137e | 10 | #include "mbed.h" |
co657_frmb | 0:f4e27396137e | 11 | #include "ble/BLE.h" |
co657_frmb | 0:f4e27396137e | 12 | #include "ble/Gap.h" |
co657_frmb | 0:f4e27396137e | 13 | #include "C12832.h" |
co657_frmb | 0:f4e27396137e | 14 | |
co657_frmb | 0:f4e27396137e | 15 | /* output choice */ |
co657_frmb | 0:f4e27396137e | 16 | #undef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 17 | #define LCD_OUTPUT |
co657_frmb | 0:f4e27396137e | 18 | |
co657_frmb | 0:f4e27396137e | 19 | static DigitalOut led1 (LED1); |
co657_frmb | 0:f4e27396137e | 20 | static DigitalOut led2 (LED2); |
co657_frmb | 0:f4e27396137e | 21 | static DigitalOut led3 (LED3); |
co657_frmb | 0:f4e27396137e | 22 | static DigitalOut led4 (LED4); |
co657_frmb | 0:f4e27396137e | 23 | |
co657_frmb | 0:f4e27396137e | 24 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 25 | static Serial host (USBTX, USBRX); |
co657_frmb | 0:f4e27396137e | 26 | #endif |
co657_frmb | 0:f4e27396137e | 27 | |
co657_frmb | 0:f4e27396137e | 28 | #ifdef LCD_OUTPUT |
co657_frmb | 0:f4e27396137e | 29 | static C12832 shld_lcd (D11, D13, D12, D7, D10); /* LCD on the shield (128x32) */ |
co657_frmb | 0:f4e27396137e | 30 | #endif |
co657_frmb | 0:f4e27396137e | 31 | |
co657_frmb | 0:f4e27396137e | 32 | |
co657_frmb | 0:f4e27396137e | 33 | |
co657_frmb | 0:f4e27396137e | 34 | #define HLEN_MAX (128) |
co657_frmb | 0:f4e27396137e | 35 | |
co657_frmb | 0:f4e27396137e | 36 | typedef struct beacon_log { |
co657_frmb | 0:f4e27396137e | 37 | uint8_t age; /* approx seconds (0xff == dead/gone) */ |
co657_frmb | 0:f4e27396137e | 38 | uint16_t addr_hi; /* two high order bytes */ |
co657_frmb | 0:f4e27396137e | 39 | uint32_t addr_lo; /* four low order bytes */ |
co657_frmb | 0:f4e27396137e | 40 | int8_t rssi; /* RSSI (-ve) */ |
co657_frmb | 0:f4e27396137e | 41 | uint8_t type; /* crudely cast */ |
co657_frmb | 0:f4e27396137e | 42 | } beacon_log_t; |
co657_frmb | 0:f4e27396137e | 43 | |
co657_frmb | 0:f4e27396137e | 44 | #define MAX_BEACONS (32) |
co657_frmb | 0:f4e27396137e | 45 | |
co657_frmb | 0:f4e27396137e | 46 | static beacon_log_t blog[MAX_BEACONS]; |
co657_frmb | 0:f4e27396137e | 47 | |
co657_frmb | 0:f4e27396137e | 48 | void bubble_blog (int idx) |
co657_frmb | 0:f4e27396137e | 49 | { |
co657_frmb | 0:f4e27396137e | 50 | beacon_log_t tmp; |
co657_frmb | 0:f4e27396137e | 51 | |
co657_frmb | 0:f4e27396137e | 52 | /* crude bubble-sort for single insert/update */ |
co657_frmb | 0:f4e27396137e | 53 | if (idx <= 0) { |
co657_frmb | 0:f4e27396137e | 54 | return; |
co657_frmb | 0:f4e27396137e | 55 | } |
co657_frmb | 0:f4e27396137e | 56 | memcpy (&tmp, &blog[idx], sizeof (beacon_log_t)); |
co657_frmb | 0:f4e27396137e | 57 | while ((idx > 0) && (blog[idx-1].age > tmp.age)) { |
co657_frmb | 0:f4e27396137e | 58 | memcpy (&blog[idx], &blog[idx-1], sizeof (beacon_log_t)); |
co657_frmb | 0:f4e27396137e | 59 | idx--; |
co657_frmb | 0:f4e27396137e | 60 | } |
co657_frmb | 0:f4e27396137e | 61 | memcpy (&blog[idx], &tmp, sizeof (beacon_log_t)); |
co657_frmb | 0:f4e27396137e | 62 | |
co657_frmb | 0:f4e27396137e | 63 | return; |
co657_frmb | 0:f4e27396137e | 64 | } |
co657_frmb | 0:f4e27396137e | 65 | |
co657_frmb | 0:f4e27396137e | 66 | void age_blog (void) |
co657_frmb | 0:f4e27396137e | 67 | { |
co657_frmb | 0:f4e27396137e | 68 | int i; |
co657_frmb | 0:f4e27396137e | 69 | |
co657_frmb | 0:f4e27396137e | 70 | for (i=0; i<MAX_BEACONS; i++) { |
co657_frmb | 0:f4e27396137e | 71 | if (blog[i].age == 0xff) { |
co657_frmb | 0:f4e27396137e | 72 | break; |
co657_frmb | 0:f4e27396137e | 73 | } |
co657_frmb | 0:f4e27396137e | 74 | blog[i].age++; |
co657_frmb | 0:f4e27396137e | 75 | } |
co657_frmb | 0:f4e27396137e | 76 | return; |
co657_frmb | 0:f4e27396137e | 77 | } |
co657_frmb | 0:f4e27396137e | 78 | |
co657_frmb | 0:f4e27396137e | 79 | #ifdef LCD_OUTPUT |
co657_frmb | 0:f4e27396137e | 80 | void draw_blog (void) |
co657_frmb | 0:f4e27396137e | 81 | { |
co657_frmb | 0:f4e27396137e | 82 | shld_lcd.cls (); |
co657_frmb | 0:f4e27396137e | 83 | for (int i=0; (i<3) && (blog[i].age != 0xff); i++) { |
co657_frmb | 0:f4e27396137e | 84 | shld_lcd.locate (0, (i * 10)); |
co657_frmb | 0:f4e27396137e | 85 | shld_lcd.printf ("%4.4X%8.8X", blog[i].addr_hi, blog[i].addr_lo); |
co657_frmb | 0:f4e27396137e | 86 | shld_lcd.locate (72, (i * 10)); |
co657_frmb | 0:f4e27396137e | 87 | shld_lcd.printf ("%d", blog[i].rssi); |
co657_frmb | 0:f4e27396137e | 88 | shld_lcd.locate (96, (i * 10)); |
co657_frmb | 0:f4e27396137e | 89 | shld_lcd.printf ("%u", blog[i].type); |
co657_frmb | 0:f4e27396137e | 90 | shld_lcd.locate (108, (i * 10)); |
co657_frmb | 0:f4e27396137e | 91 | shld_lcd.printf ("%u", blog[i].age); |
co657_frmb | 0:f4e27396137e | 92 | } |
co657_frmb | 0:f4e27396137e | 93 | shld_lcd.copy_to_lcd (); |
co657_frmb | 0:f4e27396137e | 94 | return; |
co657_frmb | 0:f4e27396137e | 95 | } |
co657_frmb | 0:f4e27396137e | 96 | #endif |
co657_frmb | 0:f4e27396137e | 97 | |
co657_frmb | 0:f4e27396137e | 98 | void scan_advert_got (const Gap::AdvertisementCallbackParams_t *params) |
co657_frmb | 0:f4e27396137e | 99 | { |
co657_frmb | 0:f4e27396137e | 100 | int i, last; |
co657_frmb | 0:f4e27396137e | 101 | uint32_t a_lo; |
co657_frmb | 0:f4e27396137e | 102 | uint16_t a_hi; |
co657_frmb | 0:f4e27396137e | 103 | int newb = 0; |
co657_frmb | 0:f4e27396137e | 104 | |
co657_frmb | 0:f4e27396137e | 105 | a_hi = ((uint16_t)params->peerAddr[5] << 8) | (uint16_t)params->peerAddr[4]; |
co657_frmb | 0:f4e27396137e | 106 | a_lo = ((uint32_t)params->peerAddr[3] << 24) | ((uint32_t)params->peerAddr[2] << 16) | ((uint32_t)params->peerAddr[1] << 8) | (uint32_t)params->peerAddr[0]; |
co657_frmb | 0:f4e27396137e | 107 | |
co657_frmb | 0:f4e27396137e | 108 | /* scribble the data into the log */ |
co657_frmb | 0:f4e27396137e | 109 | for (i=0, last=-1; i<MAX_BEACONS; i++) { |
co657_frmb | 0:f4e27396137e | 110 | /* see if we match */ |
co657_frmb | 0:f4e27396137e | 111 | if (blog[i].age == 0xff) { |
co657_frmb | 0:f4e27396137e | 112 | last = i; |
co657_frmb | 0:f4e27396137e | 113 | break; |
co657_frmb | 0:f4e27396137e | 114 | } else if ((blog[i].addr_hi == a_hi) && (blog[i].addr_lo == a_lo)) { |
co657_frmb | 0:f4e27396137e | 115 | /* this one! */ |
co657_frmb | 0:f4e27396137e | 116 | break; |
co657_frmb | 0:f4e27396137e | 117 | } |
co657_frmb | 0:f4e27396137e | 118 | } |
co657_frmb | 0:f4e27396137e | 119 | if (last >= 0) { |
co657_frmb | 0:f4e27396137e | 120 | /* new(ish) beacon */ |
co657_frmb | 0:f4e27396137e | 121 | i = last; |
co657_frmb | 0:f4e27396137e | 122 | newb = 1; |
co657_frmb | 0:f4e27396137e | 123 | } else if ((i == MAX_BEACONS) && (last < 0)) { |
co657_frmb | 0:f4e27396137e | 124 | /* ran out of room searching for slot, use last */ |
co657_frmb | 0:f4e27396137e | 125 | i = MAX_BEACONS - 1; |
co657_frmb | 0:f4e27396137e | 126 | newb = 1; |
co657_frmb | 0:f4e27396137e | 127 | } /* else found it somewhere, just reset age */ |
co657_frmb | 0:f4e27396137e | 128 | |
co657_frmb | 0:f4e27396137e | 129 | if (newb) { |
co657_frmb | 0:f4e27396137e | 130 | blog[i].addr_hi = a_hi; |
co657_frmb | 0:f4e27396137e | 131 | blog[i].addr_lo = a_lo; |
co657_frmb | 0:f4e27396137e | 132 | blog[i].type = (uint8_t)params->type; |
co657_frmb | 0:f4e27396137e | 133 | } |
co657_frmb | 0:f4e27396137e | 134 | blog[i].rssi = (int8_t)params->rssi; |
co657_frmb | 0:f4e27396137e | 135 | blog[i].age = 0; |
co657_frmb | 0:f4e27396137e | 136 | bubble_blog (i); |
co657_frmb | 0:f4e27396137e | 137 | |
co657_frmb | 0:f4e27396137e | 138 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 139 | host.printf ("ADV:"); |
co657_frmb | 0:f4e27396137e | 140 | for (i=Gap::ADDR_LEN - 1; i>=0; i--) { // backwards |
co657_frmb | 0:f4e27396137e | 141 | host.printf ("%2.2x", params->peerAddr[i]); |
co657_frmb | 0:f4e27396137e | 142 | } |
co657_frmb | 0:f4e27396137e | 143 | host.printf (":%d:%u:%d:", params->rssi, (unsigned int)params->type, params->advertisingDataLen); |
co657_frmb | 0:f4e27396137e | 144 | for (i=0; (i<params->advertisingDataLen) && (hlen < (HLEN_MAX-4)); i++) { |
co657_frmb | 0:f4e27396137e | 145 | uint8_t ch = (uint8_t)params->advertisingData[i]; |
co657_frmb | 0:f4e27396137e | 146 | |
co657_frmb | 0:f4e27396137e | 147 | host.printf ("%2.2x", ch); |
co657_frmb | 0:f4e27396137e | 148 | } |
co657_frmb | 0:f4e27396137e | 149 | |
co657_frmb | 0:f4e27396137e | 150 | host.printf ("\r\n"); |
co657_frmb | 0:f4e27396137e | 151 | #endif |
co657_frmb | 0:f4e27396137e | 152 | #ifdef LCD_OUTPUT |
co657_frmb | 0:f4e27396137e | 153 | draw_blog (); |
co657_frmb | 0:f4e27396137e | 154 | #endif |
co657_frmb | 0:f4e27396137e | 155 | |
co657_frmb | 0:f4e27396137e | 156 | return; |
co657_frmb | 0:f4e27396137e | 157 | } |
co657_frmb | 0:f4e27396137e | 158 | |
co657_frmb | 0:f4e27396137e | 159 | #define SCAN_INTERVAL (20) |
co657_frmb | 0:f4e27396137e | 160 | #define SCAN_WINDOW (20) |
co657_frmb | 0:f4e27396137e | 161 | |
co657_frmb | 0:f4e27396137e | 162 | |
co657_frmb | 0:f4e27396137e | 163 | void ble_init_done (BLE::InitializationCompleteCallbackContext *params) |
co657_frmb | 0:f4e27396137e | 164 | { |
co657_frmb | 0:f4e27396137e | 165 | BLE &ble = params->ble; |
co657_frmb | 0:f4e27396137e | 166 | ble_error_t err = params->error; |
co657_frmb | 0:f4e27396137e | 167 | |
co657_frmb | 0:f4e27396137e | 168 | if (err != BLE_ERROR_NONE) { |
co657_frmb | 0:f4e27396137e | 169 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 170 | host.printf ("ERR:Failed to initialise BLE, error code %d\r\n", (int)err); |
co657_frmb | 0:f4e27396137e | 171 | #endif |
co657_frmb | 0:f4e27396137e | 172 | return; |
co657_frmb | 0:f4e27396137e | 173 | } |
co657_frmb | 0:f4e27396137e | 174 | |
co657_frmb | 0:f4e27396137e | 175 | if (ble.getInstanceID () != BLE::DEFAULT_INSTANCE) { |
co657_frmb | 0:f4e27396137e | 176 | // erm.. |
co657_frmb | 0:f4e27396137e | 177 | return; |
co657_frmb | 0:f4e27396137e | 178 | } |
co657_frmb | 0:f4e27396137e | 179 | |
co657_frmb | 0:f4e27396137e | 180 | // setup for scanning |
co657_frmb | 0:f4e27396137e | 181 | err = ble.gap().setScanInterval (SCAN_INTERVAL); |
co657_frmb | 0:f4e27396137e | 182 | if (err != BLE_ERROR_NONE) { |
co657_frmb | 0:f4e27396137e | 183 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 184 | host.printf ("ERR:Failed to set scanning interval (%d), code %d\r\n", SCAN_INTERVAL, (int)err); |
co657_frmb | 0:f4e27396137e | 185 | #endif |
co657_frmb | 0:f4e27396137e | 186 | return; |
co657_frmb | 0:f4e27396137e | 187 | } |
co657_frmb | 0:f4e27396137e | 188 | |
co657_frmb | 0:f4e27396137e | 189 | err = ble.gap().setScanWindow (SCAN_WINDOW); |
co657_frmb | 0:f4e27396137e | 190 | if (err != BLE_ERROR_NONE) { |
co657_frmb | 0:f4e27396137e | 191 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 192 | host.printf ("ERR:Failed to set scanning window (%d), code %d\r\n", SCAN_WINDOW, (int)err); |
co657_frmb | 0:f4e27396137e | 193 | #endif |
co657_frmb | 0:f4e27396137e | 194 | return; |
co657_frmb | 0:f4e27396137e | 195 | } |
co657_frmb | 0:f4e27396137e | 196 | |
co657_frmb | 0:f4e27396137e | 197 | err = ble.gap().setScanTimeout (0); |
co657_frmb | 0:f4e27396137e | 198 | if (err != BLE_ERROR_NONE) { |
co657_frmb | 0:f4e27396137e | 199 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 200 | host.printf ("ERR:Failed to set scan timeout (0), code %d\r\n", (int)err); |
co657_frmb | 0:f4e27396137e | 201 | #endif |
co657_frmb | 0:f4e27396137e | 202 | return; |
co657_frmb | 0:f4e27396137e | 203 | } |
co657_frmb | 0:f4e27396137e | 204 | |
co657_frmb | 0:f4e27396137e | 205 | err = ble.gap().setActiveScanning (false); |
co657_frmb | 0:f4e27396137e | 206 | if (err != BLE_ERROR_NONE) { |
co657_frmb | 0:f4e27396137e | 207 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 208 | host.printf ("ERR:Failed to set active scan (false), code %d\r\n", (int)err); |
co657_frmb | 0:f4e27396137e | 209 | #endif |
co657_frmb | 0:f4e27396137e | 210 | return; |
co657_frmb | 0:f4e27396137e | 211 | } |
co657_frmb | 0:f4e27396137e | 212 | |
co657_frmb | 0:f4e27396137e | 213 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 214 | host.printf ("MSG:Scan parameters set, off we go..\r\n"); |
co657_frmb | 0:f4e27396137e | 215 | #endif |
co657_frmb | 0:f4e27396137e | 216 | // Thread::wait (500); |
co657_frmb | 0:f4e27396137e | 217 | |
co657_frmb | 0:f4e27396137e | 218 | err = ble.gap().startScan (scan_advert_got); |
co657_frmb | 0:f4e27396137e | 219 | if (err != BLE_ERROR_NONE) { |
co657_frmb | 0:f4e27396137e | 220 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 221 | host.printf ("ERR:Failed to start scanning (code %d)\r\n", (int)err); |
co657_frmb | 0:f4e27396137e | 222 | #endif |
co657_frmb | 0:f4e27396137e | 223 | return; |
co657_frmb | 0:f4e27396137e | 224 | } |
co657_frmb | 0:f4e27396137e | 225 | |
co657_frmb | 0:f4e27396137e | 226 | return; |
co657_frmb | 0:f4e27396137e | 227 | } |
co657_frmb | 0:f4e27396137e | 228 | |
co657_frmb | 0:f4e27396137e | 229 | |
co657_frmb | 0:f4e27396137e | 230 | // main() runs in its own thread in the OS |
co657_frmb | 0:f4e27396137e | 231 | // (note the calls to Thread::wait below for delays) |
co657_frmb | 0:f4e27396137e | 232 | int main() |
co657_frmb | 0:f4e27396137e | 233 | { |
co657_frmb | 0:f4e27396137e | 234 | BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); |
co657_frmb | 0:f4e27396137e | 235 | uint8_t lw = 0x01; |
co657_frmb | 0:f4e27396137e | 236 | int acnt = 0; |
co657_frmb | 0:f4e27396137e | 237 | |
co657_frmb | 0:f4e27396137e | 238 | #ifdef SERIAL_OUTPUT |
co657_frmb | 0:f4e27396137e | 239 | host.baud (38400); |
co657_frmb | 0:f4e27396137e | 240 | #endif |
co657_frmb | 0:f4e27396137e | 241 | |
co657_frmb | 0:f4e27396137e | 242 | led1 = 1; |
co657_frmb | 0:f4e27396137e | 243 | led2 = 0; |
co657_frmb | 0:f4e27396137e | 244 | led3 = 0; |
co657_frmb | 0:f4e27396137e | 245 | led4 = 0; |
co657_frmb | 0:f4e27396137e | 246 | |
co657_frmb | 0:f4e27396137e | 247 | for (int i=0; i<MAX_BEACONS; i++) { |
co657_frmb | 0:f4e27396137e | 248 | memset (&blog[i], 0x00, sizeof (beacon_log_t)); |
co657_frmb | 0:f4e27396137e | 249 | |
co657_frmb | 0:f4e27396137e | 250 | blog[i].age = 0xff; |
co657_frmb | 0:f4e27396137e | 251 | } |
co657_frmb | 0:f4e27396137e | 252 | |
co657_frmb | 0:f4e27396137e | 253 | /* Note: most of the real initialisation is done inside "ble_init_done" */ |
co657_frmb | 0:f4e27396137e | 254 | ble.init (ble_init_done); |
co657_frmb | 0:f4e27396137e | 255 | |
co657_frmb | 0:f4e27396137e | 256 | #ifdef LCD_OUTPUT |
co657_frmb | 0:f4e27396137e | 257 | shld_lcd.set_auto_up (0); |
co657_frmb | 0:f4e27396137e | 258 | shld_lcd.cls (); |
co657_frmb | 0:f4e27396137e | 259 | shld_lcd.locate (1, 1); |
co657_frmb | 0:f4e27396137e | 260 | shld_lcd.printf ("Hello, CO657!"); |
co657_frmb | 0:f4e27396137e | 261 | shld_lcd.copy_to_lcd (); |
co657_frmb | 0:f4e27396137e | 262 | Thread::wait (500); |
co657_frmb | 0:f4e27396137e | 263 | #endif |
co657_frmb | 0:f4e27396137e | 264 | |
co657_frmb | 0:f4e27396137e | 265 | // GROT |
co657_frmb | 0:f4e27396137e | 266 | for (;;) { |
co657_frmb | 0:f4e27396137e | 267 | led1 = (lw & 0x01) ? 0 : 1; |
co657_frmb | 0:f4e27396137e | 268 | led2 = (lw & 0x02) ? 0 : 1; |
co657_frmb | 0:f4e27396137e | 269 | led4 = (lw & 0x04) ? 0 : 1; |
co657_frmb | 0:f4e27396137e | 270 | led3 = (lw & 0x08) ? 0 : 1; |
co657_frmb | 0:f4e27396137e | 271 | |
co657_frmb | 0:f4e27396137e | 272 | lw <<= 1; |
co657_frmb | 0:f4e27396137e | 273 | if (lw == 0x10) { |
co657_frmb | 0:f4e27396137e | 274 | lw = 0x01; |
co657_frmb | 0:f4e27396137e | 275 | } |
co657_frmb | 0:f4e27396137e | 276 | acnt++; |
co657_frmb | 0:f4e27396137e | 277 | if (acnt == 10) { |
co657_frmb | 0:f4e27396137e | 278 | acnt = 0; |
co657_frmb | 0:f4e27396137e | 279 | age_blog (); |
co657_frmb | 0:f4e27396137e | 280 | #ifdef LCD_OUTPUT |
co657_frmb | 0:f4e27396137e | 281 | draw_blog (); |
co657_frmb | 0:f4e27396137e | 282 | #endif |
co657_frmb | 0:f4e27396137e | 283 | } |
co657_frmb | 0:f4e27396137e | 284 | |
co657_frmb | 0:f4e27396137e | 285 | ble.processEvents (); |
co657_frmb | 0:f4e27396137e | 286 | |
co657_frmb | 0:f4e27396137e | 287 | Thread::wait (100); |
co657_frmb | 0:f4e27396137e | 288 | } |
co657_frmb | 0:f4e27396137e | 289 | |
co657_frmb | 0:f4e27396137e | 290 | } |
co657_frmb | 0:f4e27396137e | 291 |