2018-10-22: This is a temporary repository to fix issue mbed OS issue 8344. I'm reverting to an earlier mbed revision that isn't messed up. Expect mbed to fix the linker issue in the next release and I'll remove this repository. I havne't tested the code at this revision - sorry!

Dependencies:   BLE_API mbed mbedtls nRF51822

Committer:
electronichamsters
Date:
Sun Aug 27 05:48:02 2017 +0000
Revision:
13:e136665cf993
Parent:
12:30c6e83f0fe5
Child:
14:c62c3a92aba7
added serial flow control

Who changed what in which revision?

UserRevisionLine numberNew contents of line
electronichamsters 11:d5edb6e3edab 1 /*
electronichamsters 13:e136665cf993 2 * Copyright (c) Eric Tsai 2017
electronichamsters 13:e136665cf993 3 *
electronichamsters 13:e136665cf993 4 * Licensed under the Apache License, Version 2.0 (the "License");
electronichamsters 13:e136665cf993 5 * you may not use this file except in compliance with the License.
electronichamsters 13:e136665cf993 6 * You may obtain a copy of the License at
electronichamsters 13:e136665cf993 7 *
electronichamsters 13:e136665cf993 8 * http://www.apache.org/licenses/LICENSE-2.0
electronichamsters 13:e136665cf993 9 *
electronichamsters 13:e136665cf993 10 * Unless required by applicable law or agreed to in writing, software
electronichamsters 13:e136665cf993 11 * distributed under the License is distributed on an "AS IS" BASIS,
electronichamsters 13:e136665cf993 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
electronichamsters 13:e136665cf993 13 * See the License for the specific language governing permissions and
electronichamsters 13:e136665cf993 14 * limitations under the License.
electronichamsters 13:e136665cf993 15 *
electronichamsters 13:e136665cf993 16 *
electronichamsters 13:e136665cf993 17 * Credit: I started with the basic BLE_Observer code from mbed Bluetooth Low Energy team
electronichamsters 13:e136665cf993 18 * https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_Observer/file/88f50499af9a/main.cpp
electronichamsters 13:e136665cf993 19 *
electronichamsters 13:e136665cf993 20 *
electronichamsters 13:e136665cf993 21 *
electronichamsters 13:e136665cf993 22 * This BLE advertisement observer looks for specific advertisements from intended bacons
electronichamsters 13:e136665cf993 23 * and outputs beacon data as json over serial. Compiled and tested for nRF51822 on mbed.
electronichamsters 11:d5edb6e3edab 24 */
electronichamsters 8:46c5e0bfab05 25
electronichamsters 13:e136665cf993 26 #include "mbed.h" //revision 148
electronichamsters 9:1ea51b2048a8 27 #include "ble/BLE.h"
electronichamsters 13:e136665cf993 28 #include "mbedtls/aes.h" //derived from the standard mbedtls. Modified for smaller build. See project.
electronichamsters 13:e136665cf993 29
electronichamsters 13:e136665cf993 30
electronichamsters 13:e136665cf993 31 #define MyDebugEnb 0 //change to 1 for debug out of the same serial as intended output
electronichamsters 8:46c5e0bfab05 32
electronichamsters 8:46c5e0bfab05 33
electronichamsters 9:1ea51b2048a8 34 Ticker ticker;
electronichamsters 8:46c5e0bfab05 35
electronichamsters 13:e136665cf993 36 //clock periodicity used for spoof checking, should be 1800 seconds for 30minutes
electronichamsters 13:e136665cf993 37 //make sure matches periodicity of beacons for correct operation
electronichamsters 13:e136665cf993 38 const uint16_t Periodicity = 1800;
electronichamsters 11:d5edb6e3edab 39
electronichamsters 13:e136665cf993 40 //aes
electronichamsters 9:1ea51b2048a8 41 uint8_t src_buf[16] = {0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4};
electronichamsters 9:1ea51b2048a8 42 uint8_t des_buf[16] = {0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4};
electronichamsters 9:1ea51b2048a8 43 mbedtls_aes_context aes;
electronichamsters 13:e136665cf993 44 unsigned char iv[16] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x1, 0x2}; //16-byte aes key
electronichamsters 13:e136665cf993 45
electronichamsters 9:1ea51b2048a8 46
electronichamsters 13:e136665cf993 47 Serial device(p9, p11); //nRF51822 uart: TX=p9. RX=p11
electronichamsters 13:e136665cf993 48 DigitalIn pinHandShake(p0); //handshake uart to prevent output before bridge MCU is ready. Flow control.
electronichamsters 9:1ea51b2048a8 49
electronichamsters 11:d5edb6e3edab 50 //data structures for tracking wake time of BLE end nodes, for to prevent spoofing
electronichamsters 11:d5edb6e3edab 51 struct MAC_Birth_Record
electronichamsters 11:d5edb6e3edab 52 {
electronichamsters 11:d5edb6e3edab 53 uint8_t MAC_Addr[6]; //mac[0] is low order byte in mac address
electronichamsters 11:d5edb6e3edab 54 uint16_t MAC_Time; //The time of birth for this end node
electronichamsters 11:d5edb6e3edab 55 uint16_t Attempt_MAC_Time;
electronichamsters 11:d5edb6e3edab 56 uint8_t Attempt_Cnt;
electronichamsters 11:d5edb6e3edab 57 uint8_t Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 58 };
electronichamsters 13:e136665cf993 59 const uint8_t sizeOfSpoof = 50; //translates to the number of unique BLE modules this gateway should receive
electronichamsters 11:d5edb6e3edab 60 MAC_Birth_Record Spoof_Check[sizeOfSpoof]; //array tracking end node birth times
electronichamsters 11:d5edb6e3edab 61 uint8_t Spoof_Ray_Tail = 0; //array index for next record
electronichamsters 11:d5edb6e3edab 62 uint8_t Received_MAC_Addr[6]; //mac[0] is low order byte in mac address
electronichamsters 13:e136665cf993 63 uint16_t Received_MAC_Time; //global var to hold MAC for processing the current ADV
electronichamsters 13:e136665cf993 64 static Timer Gateway_Time; //global for the # seconds within each "Periodicity" cycle, each 30 minute chunk.
electronichamsters 13:e136665cf993 65 static uint16_t Expected_MAC_Time; //holds Gateway Time Zone value for Beacon's birth time indicated by ADV
electronichamsters 13:e136665cf993 66 uint8_t Received_Xmit_Cnt; //global var to hold xmit count for processing the current ADV
electronichamsters 13:e136665cf993 67 const uint8_t Allowance = 5; //number of seconds allowed for MAC Birthtime mismatch
electronichamsters 11:d5edb6e3edab 68
electronichamsters 13:e136665cf993 69 // possible return values for Is_Not_Spoofed()
electronichamsters 13:e136665cf993 70 const uint8_t ADVisUnknown = 0; //Unaccounted for advertisement type, should never happen
electronichamsters 13:e136665cf993 71 const uint8_t ADVisNew = 1; //first time seeing this MAC address
electronichamsters 13:e136665cf993 72 const uint8_t ADVisDuplicate = 2; //packet is one of the duplicate advertisement
electronichamsters 13:e136665cf993 73 const uint8_t ADVisSpoof = 3; //birth times do not match
electronichamsters 11:d5edb6e3edab 74
electronichamsters 13:e136665cf993 75 uint8_t MAC_gateway[6] = {0x0,0x0,0x0,0x0,0x0,0x0}; //mac address of this gateway BLE module
electronichamsters 11:d5edb6e3edab 76
electronichamsters 11:d5edb6e3edab 77 //********************
electronichamsters 13:e136665cf993 78 // Checks if Beacon's transmitted MAC birth time matches and gateway's recorded MAC birth time.
electronichamsters 13:e136665cf993 79 // Takes into account 30-minute clock, takes care of edge cases for wrap around
electronichamsters 11:d5edb6e3edab 80 // returns:
electronichamsters 11:d5edb6e3edab 81 // TRUE: if sensor's reported time lines up to gateway's recorded time
electronichamsters 13:e136665cf993 82 //********************
electronichamsters 11:d5edb6e3edab 83 bool Is_Birth_Time_Correct (uint16_t gateway_mac_time, uint16_t sensor_mac_time, uint8_t margin)
electronichamsters 11:d5edb6e3edab 84 {
electronichamsters 11:d5edb6e3edab 85 bool return_val = 0;
electronichamsters 11:d5edb6e3edab 86 uint16_t current_time = (uint16_t)(Gateway_Time.read_ms()/1000);
electronichamsters 11:d5edb6e3edab 87 int16_t gateway_time_zone = current_time - sensor_mac_time;
electronichamsters 11:d5edb6e3edab 88
electronichamsters 13:e136665cf993 89 if (current_time >= sensor_mac_time) //simple time translation
electronichamsters 11:d5edb6e3edab 90 {
electronichamsters 11:d5edb6e3edab 91 Expected_MAC_Time = current_time - sensor_mac_time;
electronichamsters 11:d5edb6e3edab 92 }
electronichamsters 13:e136665cf993 93 else //wrap around time given periodicity
electronichamsters 11:d5edb6e3edab 94 {
electronichamsters 11:d5edb6e3edab 95 Expected_MAC_Time = (Periodicity - sensor_mac_time + current_time);
electronichamsters 11:d5edb6e3edab 96 }
electronichamsters 11:d5edb6e3edab 97
electronichamsters 13:e136665cf993 98 //todo: perhaps return true if count is 0 to avoid 3-transmits needed to confirm devices that were reset? Meh.
electronichamsters 13:e136665cf993 99 if (1)
electronichamsters 11:d5edb6e3edab 100 {
electronichamsters 13:e136665cf993 101 //We can't be too stringent that beacon MAC time precisely matches recorded time, because we're advertising
electronichamsters 13:e136665cf993 102 // the same data over several seconds. Not bothering to update the MAC time of each ADV within same event.
electronichamsters 13:e136665cf993 103 // Pick margin time (in seconds) based on how many seconds the beacon is advertising, to give this alloweance
electronichamsters 13:e136665cf993 104 // For example, you want to be more certain that beacon seen by gateway, and you increase the number of seconds
electronichamsters 13:e136665cf993 105 // you advertise for from 2 to 4 seconds. Then Margin has to be likewise increased to 4 seconds.
electronichamsters 13:e136665cf993 106 // Increasing probably that Beacon is seen results in slightly compromised spoof-detection.
electronichamsters 11:d5edb6e3edab 107 if ( (gateway_mac_time < (Expected_MAC_Time + margin)) && (gateway_mac_time > (Expected_MAC_Time - margin)) )
electronichamsters 11:d5edb6e3edab 108 {
electronichamsters 11:d5edb6e3edab 109 return_val = 1;
electronichamsters 11:d5edb6e3edab 110 }
electronichamsters 11:d5edb6e3edab 111 else
electronichamsters 11:d5edb6e3edab 112 {
electronichamsters 11:d5edb6e3edab 113 return_val = 0;
electronichamsters 11:d5edb6e3edab 114
electronichamsters 11:d5edb6e3edab 115 }
electronichamsters 11:d5edb6e3edab 116 }
electronichamsters 13:e136665cf993 117
electronichamsters 11:d5edb6e3edab 118 return return_val;
electronichamsters 11:d5edb6e3edab 119 }//end Is_Birth_Time_Correct
electronichamsters 11:d5edb6e3edab 120
electronichamsters 11:d5edb6e3edab 121
electronichamsters 11:d5edb6e3edab 122
electronichamsters 13:e136665cf993 123 /* ****************************************
electronichamsters 13:e136665cf993 124 iterates Beacon adv against all mac birth records to detect spoofing, repeats, and
electronichamsters 11:d5edb6e3edab 125 add device to birth records if new
electronichamsters 13:e136665cf993 126
electronichamsters 11:d5edb6e3edab 127 returns
electronichamsters 13:e136665cf993 128 ADVisNew = 1 First time seeing this MAC address
electronichamsters 13:e136665cf993 129 ADVisDuplicate = 2 Subsequent advertisements for same event
electronichamsters 13:e136665cf993 130 ADVisSpoof = 3 MAC times do not match
electronichamsters 13:e136665cf993 131 ADVisUnknown = 0 Shouldn't encounter this, debug
electronichamsters 13:e136665cf993 132 *******************************************/
electronichamsters 11:d5edb6e3edab 133 uint8_t Is_Not_Spoofed ()
electronichamsters 8:46c5e0bfab05 134 {
electronichamsters 11:d5edb6e3edab 135 uint8_t return_val = ADVisUnknown;
electronichamsters 13:e136665cf993 136
electronichamsters 11:d5edb6e3edab 137 //iterate through all of birth records looking for one that matches MAC address
electronichamsters 11:d5edb6e3edab 138 for (int i=0; i<sizeOfSpoof; i++)
electronichamsters 11:d5edb6e3edab 139 {
electronichamsters 11:d5edb6e3edab 140 //Search for matching MAC address
electronichamsters 11:d5edb6e3edab 141 if (Spoof_Check[i].MAC_Addr[0] == Received_MAC_Addr[0] &&
electronichamsters 11:d5edb6e3edab 142 Spoof_Check[i].MAC_Addr[1] == Received_MAC_Addr[1] &&
electronichamsters 11:d5edb6e3edab 143 Spoof_Check[i].MAC_Addr[2] == Received_MAC_Addr[2] &&
electronichamsters 11:d5edb6e3edab 144 Spoof_Check[i].MAC_Addr[3] == Received_MAC_Addr[3] &&
electronichamsters 11:d5edb6e3edab 145 Spoof_Check[i].MAC_Addr[4] == Received_MAC_Addr[4] &&
electronichamsters 11:d5edb6e3edab 146 Spoof_Check[i].MAC_Addr[5] == Received_MAC_Addr[5])
electronichamsters 11:d5edb6e3edab 147 {
electronichamsters 11:d5edb6e3edab 148 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 149 device.printf("found MAC address in array\r\n");
electronichamsters 11:d5edb6e3edab 150 device.printf(" Index = %d \r\n", i);
electronichamsters 11:d5edb6e3edab 151 device.printf(" MAC = %02x:%02x:%02x:%02x:%02x:%02x \r\n", Received_MAC_Addr[5],Received_MAC_Addr[4],Received_MAC_Addr[3],Received_MAC_Addr[2],Received_MAC_Addr[1],Received_MAC_Addr[0]);
electronichamsters 11:d5edb6e3edab 152 device.printf(" Received MAC Time = %d \r\n", Received_MAC_Time);
electronichamsters 11:d5edb6e3edab 153 device.printf(" Gateway time = %d \r\n", (uint16_t)(Gateway_Time.read_ms()/1000));
electronichamsters 11:d5edb6e3edab 154 device.printf(" Array.MAC_Time = %d \r\n", Spoof_Check[i].MAC_Time);
electronichamsters 11:d5edb6e3edab 155 device.printf(" Array.Attempt_MAC_Time = %d \r\n", Spoof_Check[i].Attempt_MAC_Time);
electronichamsters 11:d5edb6e3edab 156 device.printf(" Array.Attempt_Cnt = %d \r\n", Spoof_Check[i].Attempt_Cnt);
electronichamsters 11:d5edb6e3edab 157 device.printf(" Array.Xmit_Cnt = %d \r\n", Spoof_Check[i].Xmit_Cnt);
electronichamsters 11:d5edb6e3edab 158 device.printf(" expected time = %d \r\n", ((uint16_t)(Gateway_Time.read_ms()/1000)) - Received_MAC_Time);
electronichamsters 11:d5edb6e3edab 159 #endif
electronichamsters 11:d5edb6e3edab 160
electronichamsters 11:d5edb6e3edab 161 if
electronichamsters 11:d5edb6e3edab 162 (
electronichamsters 13:e136665cf993 163 //check primary MAC time
electronichamsters 13:e136665cf993 164 //adjust margin=5 as needed to accomodate Beacon advertisement interval time
electronichamsters 13:e136665cf993 165 // if advertising for 3 seconds, then make margin 4. 4->5, etc...
electronichamsters 13:e136665cf993 166 Is_Birth_Time_Correct(Spoof_Check[i].MAC_Time, Received_MAC_Time, Allowance)
electronichamsters 11:d5edb6e3edab 167 )
electronichamsters 11:d5edb6e3edab 168 {
electronichamsters 13:e136665cf993 169 if (Spoof_Check[i].Xmit_Cnt != Received_Xmit_Cnt) //check if this is duplicate
electronichamsters 11:d5edb6e3edab 170 {
electronichamsters 11:d5edb6e3edab 171 return_val = ADVisNew; //MAC Time checks out and not duplicate
electronichamsters 11:d5edb6e3edab 172 Spoof_Check[i].MAC_Time = Expected_MAC_Time; //update birth time for this device.
electronichamsters 11:d5edb6e3edab 173 Spoof_Check[i].Xmit_Cnt = Received_Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 174 //i = sizeOfSpoof; //exit for loop, we've found the MAC address. But can't do it this way.
electronichamsters 11:d5edb6e3edab 175 //ToDo: hey, what happens if the array holds entries w/ same MAC? Is that possible?
electronichamsters 11:d5edb6e3edab 176 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 177 device.printf("Pirmary MAC Time as expected...expected=%d...Spoof_mac_tmr=%d \r\n", Expected_MAC_Time, Spoof_Check[i].MAC_Time);
electronichamsters 11:d5edb6e3edab 178 #endif
electronichamsters 11:d5edb6e3edab 179 }
electronichamsters 11:d5edb6e3edab 180 else
electronichamsters 11:d5edb6e3edab 181 {
electronichamsters 11:d5edb6e3edab 182 return_val = ADVisDuplicate; //MAC Time checks out and is duplicate
electronichamsters 11:d5edb6e3edab 183 }
electronichamsters 11:d5edb6e3edab 184 }//if primary MAC_time match
electronichamsters 11:d5edb6e3edab 185 else
electronichamsters 11:d5edb6e3edab 186 {
electronichamsters 13:e136665cf993 187
electronichamsters 11:d5edb6e3edab 188 // check secondary Mac_Time
electronichamsters 13:e136665cf993 189 // allows for device to become registered if secondary matches multiple times
electronichamsters 11:d5edb6e3edab 190 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 191 device.printf(" MAC Time No Match!!...expected=%d...Spoof_mac_tmr=%d \r\n", Expected_MAC_Time, Spoof_Check[i].MAC_Time);
electronichamsters 11:d5edb6e3edab 192 #endif
electronichamsters 11:d5edb6e3edab 193
electronichamsters 11:d5edb6e3edab 194 //increment count if matches secondary
electronichamsters 13:e136665cf993 195 if (Is_Birth_Time_Correct(Spoof_Check[i].Attempt_MAC_Time, Received_MAC_Time, Allowance))
electronichamsters 11:d5edb6e3edab 196 {
electronichamsters 13:e136665cf993 197 if (Spoof_Check[i].Xmit_Cnt != Received_Xmit_Cnt) //not a duplicate ADV
electronichamsters 11:d5edb6e3edab 198 {
electronichamsters 11:d5edb6e3edab 199 Spoof_Check[i].Attempt_Cnt++;
electronichamsters 11:d5edb6e3edab 200 Spoof_Check[i].Xmit_Cnt = Received_Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 201 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 202 device.printf(" Match on secondary, Attempt_Cnt= %d, Attempt_MAC_Time = %d, Expected_MAC_Time=%d \r\n", Spoof_Check[i].Attempt_Cnt, Spoof_Check[i].Attempt_MAC_Time, Expected_MAC_Time);
electronichamsters 11:d5edb6e3edab 203 #endif
electronichamsters 11:d5edb6e3edab 204 //this takes care of usecase where a module is reset after it's already been seen by gateway
electronichamsters 11:d5edb6e3edab 205 //after 3 consecutive correlated MAC_Time attempts we assume is our long lost friend and not a spoof.
electronichamsters 11:d5edb6e3edab 206 if (Spoof_Check[i].Attempt_Cnt >= 3)
electronichamsters 11:d5edb6e3edab 207 {
electronichamsters 11:d5edb6e3edab 208 return_val = ADVisNew;
electronichamsters 11:d5edb6e3edab 209
electronichamsters 11:d5edb6e3edab 210 //promote this MAC_Time to primary and start accepting data @ this MAC_Time
electronichamsters 11:d5edb6e3edab 211 Spoof_Check[i].MAC_Time = Expected_MAC_Time;
electronichamsters 11:d5edb6e3edab 212 Spoof_Check[i].Xmit_Cnt = Received_Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 213 Spoof_Check[i].Attempt_Cnt = 0;
electronichamsters 11:d5edb6e3edab 214 }
electronichamsters 11:d5edb6e3edab 215 else //Received_MAC_Time matches Attempt, but not enough times to be considered as valid.
electronichamsters 11:d5edb6e3edab 216 {
electronichamsters 11:d5edb6e3edab 217 return_val = ADVisSpoof;
electronichamsters 11:d5edb6e3edab 218 }
electronichamsters 11:d5edb6e3edab 219 }//is not duplicate, and transmit count matches
electronichamsters 11:d5edb6e3edab 220 else
electronichamsters 11:d5edb6e3edab 221 {
electronichamsters 11:d5edb6e3edab 222 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 223 device.printf(" is Duplicate , but matches Attempt_MAC_Time matches\r\n");
electronichamsters 11:d5edb6e3edab 224 #endif
electronichamsters 11:d5edb6e3edab 225 return_val = ADVisDuplicate;
electronichamsters 11:d5edb6e3edab 226 }
electronichamsters 11:d5edb6e3edab 227 } //Recevied MAC_Time matches secondary MAC_Time
electronichamsters 11:d5edb6e3edab 228 else
electronichamsters 11:d5edb6e3edab 229 {
electronichamsters 11:d5edb6e3edab 230 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 231 device.printf(" No Match on secondary either, ===setting return_val = Spoof ===\r\n");
electronichamsters 11:d5edb6e3edab 232 #endif
electronichamsters 11:d5edb6e3edab 233 return_val = ADVisSpoof; //it should still be zero, so this is just for clarification
electronichamsters 11:d5edb6e3edab 234 //at this point: MAC matches, MAC_Time doesn't match primary nor secondary.
electronichamsters 11:d5edb6e3edab 235 Spoof_Check[i].Attempt_Cnt = 0; //reset secondary count
electronichamsters 11:d5edb6e3edab 236 }
electronichamsters 11:d5edb6e3edab 237 //update second backup regardless whether it matches exptected_mac_time matches secondary or not.
electronichamsters 11:d5edb6e3edab 238 Spoof_Check[i].Attempt_MAC_Time = Expected_MAC_Time;
electronichamsters 11:d5edb6e3edab 239 Spoof_Check[i].Xmit_Cnt = Received_Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 240 }//if Primary MAC_Time doesn't match
electronichamsters 11:d5edb6e3edab 241
electronichamsters 11:d5edb6e3edab 242 break; //return_val tells us if this is a valid or not. Don't need to search through remainder of array
electronichamsters 11:d5edb6e3edab 243 }//if matching MAC address
electronichamsters 11:d5edb6e3edab 244 else //MAC doesn't match
electronichamsters 11:d5edb6e3edab 245 {
electronichamsters 11:d5edb6e3edab 246 //MAC doesn't match and we've searched through entire record
electronichamsters 13:e136665cf993 247 //let's add this MAC as new, and initialze records to match this sensor
electronichamsters 11:d5edb6e3edab 248 if (i >= (sizeOfSpoof - 1)) //we've searched through entire array and didn't find this MAC
electronichamsters 11:d5edb6e3edab 249 {
electronichamsters 11:d5edb6e3edab 250 //we've searched through the entire array and didn't find this MAC address
electronichamsters 11:d5edb6e3edab 251 //add this MAC to array, and report this as valid MAC_Time
electronichamsters 11:d5edb6e3edab 252 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 253 device.printf("MAC not found, creating new at %d \r\n", Spoof_Ray_Tail);
electronichamsters 11:d5edb6e3edab 254 device.printf(" sizeOfSpoof=%d ... and i=%d \r\n", sizeOfSpoof, i);
electronichamsters 11:d5edb6e3edab 255 #endif
electronichamsters 11:d5edb6e3edab 256
electronichamsters 11:d5edb6e3edab 257 return_val = ADVisNew;
electronichamsters 11:d5edb6e3edab 258
electronichamsters 13:e136665cf993 259 //create new entry for newly seen MAC @ tail of FIFO
electronichamsters 11:d5edb6e3edab 260 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[0] = Received_MAC_Addr[0];
electronichamsters 11:d5edb6e3edab 261 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[1] = Received_MAC_Addr[1];
electronichamsters 11:d5edb6e3edab 262 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[2] = Received_MAC_Addr[2];
electronichamsters 11:d5edb6e3edab 263 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[3] = Received_MAC_Addr[3];
electronichamsters 11:d5edb6e3edab 264 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[4] = Received_MAC_Addr[4];
electronichamsters 11:d5edb6e3edab 265 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[5] = Received_MAC_Addr[5];
electronichamsters 11:d5edb6e3edab 266 Spoof_Check[Spoof_Ray_Tail].Xmit_Cnt = Received_Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 267
electronichamsters 13:e136665cf993 268 //call this just to calculate Expected_MAC_Time...kinda ugly to do this. todo: don't do this
electronichamsters 13:e136665cf993 269 Is_Birth_Time_Correct (0, Received_MAC_Time, Allowance);
electronichamsters 11:d5edb6e3edab 270 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 271 device.printf("Expected_MAC_Time should be %d \r\n", Expected_MAC_Time);
electronichamsters 11:d5edb6e3edab 272 #endif
electronichamsters 11:d5edb6e3edab 273 Spoof_Check[Spoof_Ray_Tail].MAC_Time = Expected_MAC_Time; //wrong!!!
electronichamsters 11:d5edb6e3edab 274 Spoof_Check[Spoof_Ray_Tail].Xmit_Cnt = Received_Xmit_Cnt;
electronichamsters 11:d5edb6e3edab 275 Spoof_Check[Spoof_Ray_Tail].Attempt_Cnt = 0;
electronichamsters 11:d5edb6e3edab 276
electronichamsters 11:d5edb6e3edab 277 //increment tail pointer to next position or wrap around
electronichamsters 11:d5edb6e3edab 278 if (Spoof_Ray_Tail >= (sizeOfSpoof-1) ) //FIFO at end of array, return to beginning
electronichamsters 11:d5edb6e3edab 279 {
electronichamsters 11:d5edb6e3edab 280 Spoof_Ray_Tail = 0;
electronichamsters 11:d5edb6e3edab 281 }
electronichamsters 11:d5edb6e3edab 282 else
electronichamsters 11:d5edb6e3edab 283 {
electronichamsters 11:d5edb6e3edab 284 Spoof_Ray_Tail++;
electronichamsters 11:d5edb6e3edab 285 }
electronichamsters 11:d5edb6e3edab 286
electronichamsters 11:d5edb6e3edab 287 }//end if loop at end of array
electronichamsters 11:d5edb6e3edab 288 }//end else not maching MAC
electronichamsters 11:d5edb6e3edab 289 }//loop through Spoof_Check array
electronichamsters 11:d5edb6e3edab 290
electronichamsters 13:e136665cf993 291
electronichamsters 11:d5edb6e3edab 292 return return_val;
electronichamsters 11:d5edb6e3edab 293 }//end Is_Not_Spoofed()
electronichamsters 11:d5edb6e3edab 294
electronichamsters 11:d5edb6e3edab 295
electronichamsters 13:e136665cf993 296 void periodicCallback(void) //every Periodicity seconds, reset clock
electronichamsters 11:d5edb6e3edab 297 {
electronichamsters 11:d5edb6e3edab 298 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 299 device.printf("===== reset timer ===== \r\n");
electronichamsters 11:d5edb6e3edab 300 #endif
electronichamsters 11:d5edb6e3edab 301 Gateway_Time.reset();
electronichamsters 11:d5edb6e3edab 302 }
electronichamsters 11:d5edb6e3edab 303
electronichamsters 11:d5edb6e3edab 304
electronichamsters 13:e136665cf993 305
electronichamsters 13:e136665cf993 306 //Scheme for recognizing our beacons and ignoring all other beacons
electronichamsters 13:e136665cf993 307 //idea: could use something like Pearson hash on parts of MAC address to make less obvious
electronichamsters 11:d5edb6e3edab 308 bool is_ours(const uint8_t * adv_data, const uint8_t * adv_address)
electronichamsters 11:d5edb6e3edab 309 {
electronichamsters 11:d5edb6e3edab 310 if ((adv_data[5] == adv_address[3]) && (adv_data[6] == adv_address[2]))
electronichamsters 11:d5edb6e3edab 311 return 1;
electronichamsters 11:d5edb6e3edab 312 else
electronichamsters 11:d5edb6e3edab 313 return 0;
electronichamsters 8:46c5e0bfab05 314 }
electronichamsters 8:46c5e0bfab05 315
electronichamsters 13:e136665cf993 316
electronichamsters 13:e136665cf993 317 // callback when BLE stack scans and finds a BLE ADV packet
electronichamsters 13:e136665cf993 318 // Parse ADV and determine if it's one of ours, output data to serial if it is.
electronichamsters 9:1ea51b2048a8 319 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
electronichamsters 8:46c5e0bfab05 320
electronichamsters 9:1ea51b2048a8 321 if ( (params->advertisingDataLen) >= 8)
electronichamsters 9:1ea51b2048a8 322 {
electronichamsters 11:d5edb6e3edab 323 if (is_ours(params->advertisingData, params->peerAddr))
electronichamsters 9:1ea51b2048a8 324 {
electronichamsters 11:d5edb6e3edab 325 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 326 device.printf("----------- ADV CAll Back -----------------\r\n ");
electronichamsters 11:d5edb6e3edab 327 #endif
electronichamsters 13:e136665cf993 328
electronichamsters 11:d5edb6e3edab 329 //**************
electronichamsters 11:d5edb6e3edab 330 // Decrypt data
electronichamsters 11:d5edb6e3edab 331 //**************
electronichamsters 11:d5edb6e3edab 332 //prep array for deciphering the encrypted portion of advertisement
electronichamsters 11:d5edb6e3edab 333 for (int i = 0; i<16; i++)
electronichamsters 11:d5edb6e3edab 334 {
electronichamsters 11:d5edb6e3edab 335 src_buf[i]=params->advertisingData[i+15];
electronichamsters 11:d5edb6e3edab 336 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 337 //device.printf("%x ", src_buf[i]);
electronichamsters 11:d5edb6e3edab 338 #endif
electronichamsters 11:d5edb6e3edab 339 }
electronichamsters 13:e136665cf993 340 mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_DECRYPT, src_buf, des_buf ); //execution time not an issue
electronichamsters 11:d5edb6e3edab 341 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 342 //device.printf("decoded first 16 bytes \r\n");
electronichamsters 11:d5edb6e3edab 343 for (int i = 0; i<16; i++)
electronichamsters 11:d5edb6e3edab 344 {
electronichamsters 11:d5edb6e3edab 345 //device.printf("%02x", params->advertisingData[index]);
electronichamsters 11:d5edb6e3edab 346 if (i < 2)
electronichamsters 11:d5edb6e3edab 347 {
electronichamsters 11:d5edb6e3edab 348 //device.printf("%x ", des_buf[i]);
electronichamsters 11:d5edb6e3edab 349 }
electronichamsters 11:d5edb6e3edab 350 else
electronichamsters 11:d5edb6e3edab 351 {
electronichamsters 11:d5edb6e3edab 352 //device.printf("%c ", des_buf[i]);
electronichamsters 11:d5edb6e3edab 353 }
electronichamsters 11:d5edb6e3edab 354 }
electronichamsters 11:d5edb6e3edab 355 //device.printf("done----- \r\n");
electronichamsters 11:d5edb6e3edab 356 #endif
electronichamsters 13:e136665cf993 357
electronichamsters 13:e136665cf993 358 //save MAC address to global
electronichamsters 11:d5edb6e3edab 359 Received_MAC_Addr[0] = params->peerAddr[0];
electronichamsters 11:d5edb6e3edab 360 Received_MAC_Addr[1] = params->peerAddr[1];
electronichamsters 11:d5edb6e3edab 361 Received_MAC_Addr[2] = params->peerAddr[2];
electronichamsters 11:d5edb6e3edab 362 Received_MAC_Addr[3] = params->peerAddr[3];
electronichamsters 11:d5edb6e3edab 363 Received_MAC_Addr[4] = params->peerAddr[4];
electronichamsters 11:d5edb6e3edab 364 Received_MAC_Addr[5] = params->peerAddr[5];
electronichamsters 11:d5edb6e3edab 365
electronichamsters 13:e136665cf993 366 Received_MAC_Time = des_buf[0] | (des_buf[1] << 8); //it's a 2 byte uint little endian
electronichamsters 11:d5edb6e3edab 367 Received_Xmit_Cnt = des_buf[2];
electronichamsters 11:d5edb6e3edab 368
electronichamsters 11:d5edb6e3edab 369
electronichamsters 11:d5edb6e3edab 370
electronichamsters 9:1ea51b2048a8 371
electronichamsters 13:e136665cf993 372 // punch out the data over serial as json
electronichamsters 11:d5edb6e3edab 373 //---------------------------------------
electronichamsters 11:d5edb6e3edab 374 // 1. MAC and RSSI
electronichamsters 11:d5edb6e3edab 375 // "mac":xxxxxxxx,rssi:xx,
electronichamsters 11:d5edb6e3edab 376 //---------------------------------------
electronichamsters 11:d5edb6e3edab 377 uint8_t ADV_Result = Is_Not_Spoofed();
electronichamsters 11:d5edb6e3edab 378 #if MyDebugEnb
electronichamsters 11:d5edb6e3edab 379 device.printf("--------ADV_Result = %d", ADV_Result);
electronichamsters 11:d5edb6e3edab 380 #endif
electronichamsters 11:d5edb6e3edab 381
electronichamsters 13:e136665cf993 382 //decide wether or not duplicate ADV packets should be output as well.
electronichamsters 13:e136665cf993 383 //if ((ADV_Result == ADVisNew) || (ADV_Result==ADVisDuplicate)) //output both first and duplicates
electronichamsters 13:e136665cf993 384 if (ADV_Result == ADVisNew) //only output first received ADV
electronichamsters 9:1ea51b2048a8 385 {
electronichamsters 11:d5edb6e3edab 386 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"rssi\":%d,",
electronichamsters 11:d5edb6e3edab 387 params->peerAddr[5],
electronichamsters 11:d5edb6e3edab 388 params->peerAddr[4],
electronichamsters 11:d5edb6e3edab 389 params->peerAddr[3],
electronichamsters 11:d5edb6e3edab 390 params->peerAddr[2],
electronichamsters 11:d5edb6e3edab 391 params->peerAddr[1],
electronichamsters 11:d5edb6e3edab 392 params->peerAddr[0],
electronichamsters 11:d5edb6e3edab 393 params->rssi
electronichamsters 11:d5edb6e3edab 394 );
electronichamsters 11:d5edb6e3edab 395
electronichamsters 11:d5edb6e3edab 396 //---------------------------------------
electronichamsters 13:e136665cf993 397 // 2. Volt is always X.XX, per Beacon code
electronichamsters 11:d5edb6e3edab 398 // "volt":3.03,
electronichamsters 11:d5edb6e3edab 399 //---------------------------------------
electronichamsters 11:d5edb6e3edab 400 device.printf("\"volt\":%c%c%c%c,",
electronichamsters 11:d5edb6e3edab 401 params->advertisingData[9],
electronichamsters 11:d5edb6e3edab 402 params->advertisingData[10],
electronichamsters 11:d5edb6e3edab 403 params->advertisingData[11],
electronichamsters 11:d5edb6e3edab 404 params->advertisingData[12]);
electronichamsters 11:d5edb6e3edab 405
electronichamsters 11:d5edb6e3edab 406
electronichamsters 11:d5edb6e3edab 407 //---------------------------------------
electronichamsters 13:e136665cf993 408 // 3. Beacon time (# seconds since birth, clocked around Periodicity) 0-1800 seconds
electronichamsters 13:e136665cf993 409 // "tmr":xxxx,
electronichamsters 11:d5edb6e3edab 410 //---------------------------------------
electronichamsters 11:d5edb6e3edab 411
electronichamsters 13:e136665cf993 412 device.printf("\"tmr\":%d,", Received_MAC_Time);
electronichamsters 13:e136665cf993 413
electronichamsters 13:e136665cf993 414 //---------------------------------------
electronichamsters 13:e136665cf993 415 // 4. Xmit Counter 0-255, incremented by Beacon with each new unique ADV event.
electronichamsters 13:e136665cf993 416 // "tmr":xxxx,
electronichamsters 13:e136665cf993 417 //---------------------------------------
electronichamsters 11:d5edb6e3edab 418 device.printf("\"xmit_cnt\":%d,", Received_Xmit_Cnt);
electronichamsters 11:d5edb6e3edab 419
electronichamsters 11:d5edb6e3edab 420 //---------------------------------------
electronichamsters 13:e136665cf993 421 // 5. rest of sensor payload as json
electronichamsters 11:d5edb6e3edab 422 // "tmr":xxx,
electronichamsters 11:d5edb6e3edab 423 //---------------------------------------
electronichamsters 13:e136665cf993 424 for (int i = 3; i<16; i++)
electronichamsters 9:1ea51b2048a8 425 {
electronichamsters 11:d5edb6e3edab 426 device.printf("%c", des_buf[i]); //print as character
electronichamsters 13:e136665cf993 427 //Note that sensor JSON payload most likely is not exactly 16 bytes long, so there's likely /0 in middle
electronichamsters 13:e136665cf993 428 // of this. But JSON library on gateway handles this gracefully.
electronichamsters 9:1ea51b2048a8 429 }
electronichamsters 11:d5edb6e3edab 430
electronichamsters 13:e136665cf993 431 device.printf("}");
electronichamsters 13:e136665cf993 432 device.printf("\r\n"); //gateway looking for cariage return to indicate end
electronichamsters 13:e136665cf993 433 wait_ms(60); //needed to give gateway time to assert flow control handshake pin
electronichamsters 13:e136665cf993 434 while (pinHandShake.read() == 1) //normally pulled down, so loop when gateway processing;
electronichamsters 9:1ea51b2048a8 435 {
electronichamsters 13:e136665cf993 436 //uart flow control
electronichamsters 13:e136665cf993 437 //blocking until gateway has processed ADV data from uart
electronichamsters 11:d5edb6e3edab 438 }
electronichamsters 9:1ea51b2048a8 439 }
electronichamsters 13:e136665cf993 440
electronichamsters 13:e136665cf993 441 if (ADV_Result == ADVisSpoof) //If detected spoofed sensor data
electronichamsters 11:d5edb6e3edab 442 {
electronichamsters 11:d5edb6e3edab 443 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"spoof\": %d}\r\n",
electronichamsters 11:d5edb6e3edab 444 params->peerAddr[5],
electronichamsters 11:d5edb6e3edab 445 params->peerAddr[4],
electronichamsters 11:d5edb6e3edab 446 params->peerAddr[3],
electronichamsters 11:d5edb6e3edab 447 params->peerAddr[2],
electronichamsters 11:d5edb6e3edab 448 params->peerAddr[1],
electronichamsters 11:d5edb6e3edab 449 params->peerAddr[0],
electronichamsters 11:d5edb6e3edab 450 ADV_Result);
electronichamsters 11:d5edb6e3edab 451 }
electronichamsters 13:e136665cf993 452
electronichamsters 13:e136665cf993 453 if (ADV_Result == ADVisUnknown) //catch all, should never occur
electronichamsters 11:d5edb6e3edab 454 {
electronichamsters 11:d5edb6e3edab 455 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"unknown\": %d}\r\n",
electronichamsters 11:d5edb6e3edab 456 params->peerAddr[5],
electronichamsters 11:d5edb6e3edab 457 params->peerAddr[4],
electronichamsters 11:d5edb6e3edab 458 params->peerAddr[3],
electronichamsters 11:d5edb6e3edab 459 params->peerAddr[2],
electronichamsters 11:d5edb6e3edab 460 params->peerAddr[1],
electronichamsters 11:d5edb6e3edab 461 params->peerAddr[0],
electronichamsters 11:d5edb6e3edab 462 ADV_Result);
electronichamsters 11:d5edb6e3edab 463 }
electronichamsters 9:1ea51b2048a8 464 }//end if it's our adv
electronichamsters 9:1ea51b2048a8 465 }//end if advertisingDataLen
electronichamsters 11:d5edb6e3edab 466 }//end advertisementCallback
electronichamsters 8:46c5e0bfab05 467
electronichamsters 8:46c5e0bfab05 468
electronichamsters 8:46c5e0bfab05 469
andresag 7:0a8bbb6dea16 470 /**
electronichamsters 9:1ea51b2048a8 471 * This function is called when the ble initialization process has failed
andresag 7:0a8bbb6dea16 472 */
andresag 7:0a8bbb6dea16 473 void onBleInitError(BLE &ble, ble_error_t error)
andresag 7:0a8bbb6dea16 474 {
andresag 7:0a8bbb6dea16 475 /* Initialization error handling should go here */
electronichamsters 9:1ea51b2048a8 476 device.printf("periodic callback ");
electronichamsters 9:1ea51b2048a8 477 device.printf("\r\n");
andresag 7:0a8bbb6dea16 478 }
andresag 7:0a8bbb6dea16 479
andresag 7:0a8bbb6dea16 480 /**
andresag 7:0a8bbb6dea16 481 * Callback triggered when the ble initialization process has finished
andresag 7:0a8bbb6dea16 482 */
andresag 7:0a8bbb6dea16 483 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
sunsmile2015 2:b935358da5ba 484 {
andresag 7:0a8bbb6dea16 485 BLE& ble = params->ble;
andresag 7:0a8bbb6dea16 486 ble_error_t error = params->error;
andresag 7:0a8bbb6dea16 487
andresag 7:0a8bbb6dea16 488 if (error != BLE_ERROR_NONE) {
andresag 7:0a8bbb6dea16 489 /* In case of error, forward the error handling to onBleInitError */
andresag 7:0a8bbb6dea16 490 onBleInitError(ble, error);
andresag 7:0a8bbb6dea16 491 return;
andresag 7:0a8bbb6dea16 492 }
andresag 7:0a8bbb6dea16 493
andresag 7:0a8bbb6dea16 494 /* Ensure that it is the default instance of BLE */
andresag 7:0a8bbb6dea16 495 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
andresag 7:0a8bbb6dea16 496 return;
andresag 7:0a8bbb6dea16 497 }
electronichamsters 9:1ea51b2048a8 498
electronichamsters 13:e136665cf993 499 //note: defaults to scanning 3 channels.
electronichamsters 13:e136665cf993 500 // Window and Interval in ms. Duty cycle = (interval / window); 200ms/500ms = 40%; Max is 10000
electronichamsters 13:e136665cf993 501 // |---window---| |---window---| |---window---|
electronichamsters 13:e136665cf993 502 // |---------- interval @ ch1 -----| |------- interval @ ch2--------||-----interval @ ch3-------|
electronichamsters 13:e136665cf993 503 // set window equal to interval for full duty cycle scanning
electronichamsters 13:e136665cf993 504 // set interval to hit all 3 channels of beacon advertising over advertising time duration
electronichamsters 13:e136665cf993 505 ble.gap().setScanParams(500 /* scan interval */, 500 /* scan window */);
electronichamsters 9:1ea51b2048a8 506 ble.gap().startScan(advertisementCallback);
sunsmile2015 4:e5fa4c8838db 507 }
sunsmile2015 4:e5fa4c8838db 508
sunsmile2015 2:b935358da5ba 509 int main(void)
sunsmile2015 2:b935358da5ba 510 {
electronichamsters 13:e136665cf993 511 pinHandShake.mode(PullDown); //Expecting gateway to set pin high for flow control
electronichamsters 13:e136665cf993 512
electronichamsters 13:e136665cf993 513 //intialize spoof checking data structure
electronichamsters 11:d5edb6e3edab 514 for (int i=0; i<sizeOfSpoof; i++)
electronichamsters 11:d5edb6e3edab 515 {
electronichamsters 11:d5edb6e3edab 516 Spoof_Check[i].MAC_Addr[0]= 0;
electronichamsters 11:d5edb6e3edab 517 Spoof_Check[i].MAC_Addr[1]= 0;
electronichamsters 11:d5edb6e3edab 518 Spoof_Check[i].MAC_Addr[2]= 0;
electronichamsters 11:d5edb6e3edab 519 Spoof_Check[i].MAC_Time = 0;
electronichamsters 11:d5edb6e3edab 520 Spoof_Check[i].Attempt_MAC_Time = 0;
electronichamsters 11:d5edb6e3edab 521 Spoof_Check[i].Attempt_Cnt = 0;
electronichamsters 11:d5edb6e3edab 522 Spoof_Check[i].Attempt_Cnt = 0;
electronichamsters 11:d5edb6e3edab 523 Spoof_Check[i].Xmit_Cnt = 0;
electronichamsters 11:d5edb6e3edab 524 }
electronichamsters 13:e136665cf993 525
electronichamsters 13:e136665cf993 526 //maintains periodicity for spoof checking scheme
electronichamsters 11:d5edb6e3edab 527 Gateway_Time.start();
electronichamsters 11:d5edb6e3edab 528 ticker.attach(periodicCallback, Periodicity);
electronichamsters 8:46c5e0bfab05 529
electronichamsters 13:e136665cf993 530 device.baud(9600); //p0.9 tx, p0.11 rx. Use p0.9 to gateway
electronichamsters 13:e136665cf993 531
electronichamsters 13:e136665cf993 532 mbedtls_aes_setkey_dec( &aes, iv, 128 ); //set AES key for decrypt
sunsmile2015 0:3dc6e424dba0 533
andresag 7:0a8bbb6dea16 534 BLE &ble = BLE::Instance();
andresag 7:0a8bbb6dea16 535 ble.init(bleInitComplete);
electronichamsters 13:e136665cf993 536
electronichamsters 13:e136665cf993 537 ble.getAddress(0,MAC_gateway); //get this gateway module's ble MAC
electronichamsters 13:e136665cf993 538 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"gatewaystart\":\"now\"},",
electronichamsters 13:e136665cf993 539 MAC_gateway[5],
electronichamsters 13:e136665cf993 540 MAC_gateway[4],
electronichamsters 13:e136665cf993 541 MAC_gateway[3],
electronichamsters 13:e136665cf993 542 MAC_gateway[2],
electronichamsters 13:e136665cf993 543 MAC_gateway[1],
electronichamsters 13:e136665cf993 544 MAC_gateway[0]
electronichamsters 13:e136665cf993 545 );
electronichamsters 13:e136665cf993 546 device.printf("\r\n");
electronichamsters 13:e136665cf993 547
electronichamsters 13:e136665cf993 548 while (true)
electronichamsters 13:e136665cf993 549 {
electronichamsters 13:e136665cf993 550 ble.waitForEvent(); //idle here until callback
electronichamsters 9:1ea51b2048a8 551 }
electronichamsters 9:1ea51b2048a8 552 }