BLE ADV Gateway, converts advertisement to proper JSON serial output

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:0486f885b1b1
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 }