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:
Tue Oct 23 02:37:10 2018 +0000
Revision:
14:c62c3a92aba7
Parent:
13:e136665cf993
Super lazy linker fix to mbed issue 8344.  Not tested, but "it should work"

Who changed what in which revision?

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