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

Files at this revision

API Documentation at this revision

Comitter:
electronichamsters
Date:
Sun Aug 27 05:48:02 2017 +0000
Parent:
12:30c6e83f0fe5
Child:
14:c62c3a92aba7
Commit message:
added serial flow control

Changed in this revision

BLE_API.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
nRF51822.lib Show annotated file Show diff for this revision Revisions of this file
--- a/BLE_API.lib	Sat Jul 29 22:03:27 2017 +0000
+++ b/BLE_API.lib	Sun Aug 27 05:48:02 2017 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#bfc5b9b6ecf5
+http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#65474dc93927
--- a/main.cpp	Sat Jul 29 22:03:27 2017 +0000
+++ b/main.cpp	Sun Aug 27 05:48:02 2017 +0000
@@ -1,37 +1,51 @@
 /*  
- Eric Tsai
- 
- 7/29/2017:  Added spoof checking using clock algorithm.  
- Changes:
- 1)  Modify "Periodicity" to match sensors
- 
-
+ * Copyright (c) Eric Tsai 2017
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Credit:  I started with the basic BLE_Observer code from mbed Bluetooth Low Energy team
+ * https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_Observer/file/88f50499af9a/main.cpp
+ *
+ *
+ *
+ * This BLE advertisement observer looks for specific advertisements from intended bacons
+ * and outputs beacon data as json over serial.  Compiled and tested for nRF51822 on mbed.
 */
 
-#include "mbed.h"
+#include "mbed.h"   //revision 148
 #include "ble/BLE.h"
-#include "mbedtls/aes.h"
+#include "mbedtls/aes.h"    //derived from the standard mbedtls.  Modified for smaller build.  See project.
+
+
+#define MyDebugEnb 0    //change to 1 for debug out of the same serial as intended output
 
 
-//comment out when done with debug uart, else eats batteries
-#define MyDebugEnb 0
-
-
-
-//DigitalOut led1(LED1, 1);
 Ticker     ticker;
 
-const uint16_t Periodicity = 180;   //clock periodicity used for spoof checking, should be 1800 seconds for 30minutes
+//clock periodicity used for spoof checking, should be 1800 seconds for 30minutes
+//make sure matches periodicity of beacons for correct operation
+const uint16_t Periodicity = 1800;   
 
-//aes stuff
+//aes
 uint8_t src_buf[16] = {0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4};
 uint8_t des_buf[16] = {0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4};
 mbedtls_aes_context aes;
-unsigned char iv[16] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x1, 0x2};       //16-byte key
-size_t input_len = 16;
-size_t output_len = 0;
+unsigned char iv[16] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x1, 0x2};       //16-byte aes key
+
 
-Serial device(p9, p11);  //nRF51822 uart :  TX=p9.  RX=p11
+Serial device(p9, p11);  //nRF51822 uart:  TX=p9.  RX=p11
+DigitalIn pinHandShake(p0);  //handshake uart to prevent output before bridge MCU is ready.  Flow control.
 
 //data structures for tracking wake time of BLE end nodes, for to prevent spoofing
 struct MAC_Birth_Record
@@ -42,44 +56,54 @@
     uint8_t Attempt_Cnt;
     uint8_t Xmit_Cnt;
 };
-const uint8_t sizeOfSpoof = 50;
+const uint8_t sizeOfSpoof = 50; //translates to the number of unique BLE modules this gateway should receive
 MAC_Birth_Record Spoof_Check[sizeOfSpoof];   //array tracking end node birth times
 uint8_t Spoof_Ray_Tail = 0;         //array index for next record
 uint8_t Received_MAC_Addr[6]; //mac[0] is low order byte in mac address
-uint16_t Received_MAC_Time;
-static Timer Gateway_Time;
-static uint16_t Expected_MAC_Time;
-uint8_t Received_Xmit_Cnt;
+uint16_t Received_MAC_Time;     //global var to hold MAC for processing the current ADV
+static Timer Gateway_Time;  //global for the # seconds within each "Periodicity" cycle, each 30 minute chunk.
+static uint16_t Expected_MAC_Time;  //holds Gateway Time Zone value for  Beacon's birth time indicated by ADV
+uint8_t Received_Xmit_Cnt;  //global var to hold xmit count for processing the current ADV
+const uint8_t Allowance = 5;  //number of seconds allowed for MAC Birthtime mismatch
 
+// possible return values for Is_Not_Spoofed()
+const uint8_t ADVisUnknown = 0;     //Unaccounted for advertisement type, should never happen
+const uint8_t ADVisNew = 1;             //first time seeing this MAC address
+const uint8_t ADVisDuplicate = 2;       //packet is one of the duplicate advertisement
+const uint8_t ADVisSpoof = 3;           //birth times do not match
 
-const uint8_t ADVisUnknown = 0;
-const uint8_t ADVisNew = 1;
-const uint8_t ADVisDuplicate = 2;
-const uint8_t ADVisSpoof = 3;
+uint8_t MAC_gateway[6] = {0x0,0x0,0x0,0x0,0x0,0x0};  //mac address of this gateway BLE module
 
 //********************
-// Takes into account 30-minute clock, wrap arounds and edge cases
+// Checks if Beacon's transmitted MAC birth time matches and gateway's recorded MAC birth time.
+// Takes into account 30-minute clock, takes care of edge cases for wrap around
 // returns:
 //      TRUE:  if sensor's reported time lines up to gateway's recorded time
-//  Expected_MAC_Time
-//*******************
+//********************
 bool Is_Birth_Time_Correct (uint16_t gateway_mac_time, uint16_t sensor_mac_time, uint8_t margin)
 {
     bool return_val = 0;
     uint16_t current_time = (uint16_t)(Gateway_Time.read_ms()/1000);
     int16_t gateway_time_zone = current_time - sensor_mac_time;
     
-    if (current_time >= sensor_mac_time)
+    if (current_time >= sensor_mac_time)        //simple time translation
     {
         Expected_MAC_Time = current_time - sensor_mac_time;
     }
-    else
+    else        //wrap around time given periodicity
     {
         Expected_MAC_Time = (Periodicity - sensor_mac_time + current_time);
     }
     
-    if (1)  //check for count==0 situations
+    //todo:  perhaps return true if count is 0 to avoid 3-transmits needed to confirm devices that were reset?  Meh.
+    if (1) 
     {
+        //We can't be too stringent that beacon MAC time precisely matches recorded time, because we're advertising 
+        // the same data over several seconds.  Not bothering to update the MAC time of each ADV within same event.
+        // Pick margin time (in seconds) based on how many seconds the beacon is advertising, to give this alloweance
+        // For example, you want to be more certain that beacon seen by gateway, and you increase the number of seconds
+        // you advertise for from 2 to 4 seconds.  Then Margin has to be likewise increased to 4 seconds.
+        // Increasing probably that Beacon is seen results in slightly compromised spoof-detection.
         if ( (gateway_mac_time < (Expected_MAC_Time + margin)) && (gateway_mac_time > (Expected_MAC_Time - margin)) )
         {
             return_val = 1;
@@ -90,57 +114,26 @@
             
         }  
     }
-    
-    /*
-    //if positive, not a wrap around edge case
-    //todo:  take into account low count, indicates reset?
-    if ((gateway_time_zone >= 0) && (1))
-    {
-        Expected_MAC_Time = gateway_time_zone;
-        if ( (gateway_mac_time < (Expected_MAC_Time + margin)) && (gateway_mac_time > (Expected_MAC_Time - margin)) )
-        {
-            return_val = 1;  //valid birth time
-        }
-        
-    }
-    else    //wrap around edge case, gateway_time_zone is negative
-    {
-        gateway_time_zone = (Periodicity - sensor_mac_time + current_time);
-        Expected_MAC_Time = gateway_time_zone;                  //todo:  2 declarations??
-        //if ( (Periodicity-gateway_mac_time)+current_time == sensor_mac_time) //wrong, need bands
-        if ( (gateway_mac_time < (Expected_MAC_Time + margin)) && (gateway_mac_time > (Expected_MAC_Time - margin)) )
-        {
-            return_val = 1;
-        }
-        else
-        {
-            return_val = 0;
-            
-        }
-        
-    }
-    */
+
     return return_val;
-    
 }//end Is_Birth_Time_Correct
 
 
 
-/* **************************************
-check adv against birth records to detect spoofing
+/* ****************************************
+iterates Beacon adv against all mac birth records to detect spoofing, repeats, and
 add device to birth records if new
+
 returns
-    TRUE:   if device reported birth time matches real birth time
-            if device is first encountered
-            if X consecutive birth time matches
-    FALSE:  if device reported birth time does not match
-    
-ToDo:  add attempts
-ToDo:  wrap around of gateway clock not accounted for.  Like if Gateway_Time.read_ms() - Received_MAC_Time < 0
-*/
+    ADVisNew = 1                First time seeing this MAC address
+    ADVisDuplicate = 2         Subsequent advertisements for same event
+    ADVisSpoof = 3              MAC times do not match
+    ADVisUnknown = 0        Shouldn't encounter this, debug
+*******************************************/
 uint8_t Is_Not_Spoofed ()
 {
     uint8_t return_val = ADVisUnknown;
+    
     //iterate through all of birth records looking for one that matches MAC address
     for (int i=0; i<sizeOfSpoof; i++)
     {
@@ -152,9 +145,6 @@
             Spoof_Check[i].MAC_Addr[4] == Received_MAC_Addr[4] &&
             Spoof_Check[i].MAC_Addr[5] == Received_MAC_Addr[5])
         {
-            
-            
-            
             #if MyDebugEnb
             device.printf("found MAC address in array\r\n");
             device.printf("   Index = %d \r\n", i);
@@ -168,25 +158,15 @@
             device.printf("   expected time =  %d \r\n", ((uint16_t)(Gateway_Time.read_ms()/1000)) - Received_MAC_Time);
             #endif
             
-            //calcuate the time of birth of this bluetooth module @ gateway time zone relative to received MAC_Time.
-            //int16_t expected_mac_time = ((uint16_t)(Gateway_Time.read_ms()/1000)) - Received_MAC_Time;
-            //uint16_t expected_mac_time = 0;
-            
-            
-            //todo:  this needs to be a POSITIVE VALUE, calculated by Is_MAC_Time_Correct();
-            
-            
-            // ToDo:  there's a bug here.  Need to use count to figure out when it's a first-powered on device.  Can't use time?
-            
-            //*****
-            // check primary Mac_Time
-            //****
             if 
             (
-                Is_Birth_Time_Correct(Spoof_Check[i].MAC_Time, Received_MAC_Time, 3)
+                //check primary MAC time
+                //adjust margin=5 as needed to accomodate Beacon advertisement interval time
+                // if advertising for 3 seconds, then make margin 4.  4->5, etc...
+                Is_Birth_Time_Correct(Spoof_Check[i].MAC_Time, Received_MAC_Time, Allowance)
             )
             {
-                if (Spoof_Check[i].Xmit_Cnt != Received_Xmit_Cnt)
+                if (Spoof_Check[i].Xmit_Cnt != Received_Xmit_Cnt)   //check if this is duplicate
                 {
                     return_val = ADVisNew; //MAC Time checks out and not duplicate
                     Spoof_Check[i].MAC_Time = Expected_MAC_Time;    //update birth time for this device.
@@ -204,22 +184,18 @@
             }//if primary MAC_time match
             else
             {
-                //*****
+                
                 // check secondary Mac_Time
-                //****
+                // allows for device to become registered if secondary matches multiple times
                 #if MyDebugEnb
                 device.printf("    MAC Time No Match!!...expected=%d...Spoof_mac_tmr=%d \r\n", Expected_MAC_Time, Spoof_Check[i].MAC_Time);
-                
                 #endif 
                 
                 //increment count if matches secondary
-                //if ( (Spoof_Check[i].Attempt_MAC_Time < (expected_mac_time + 5)) && (Spoof_Check[i].Attempt_MAC_Time > (expected_mac_time - 5)) )
-                if (Is_Birth_Time_Correct(Spoof_Check[i].Attempt_MAC_Time, Received_MAC_Time, 3))
+                if (Is_Birth_Time_Correct(Spoof_Check[i].Attempt_MAC_Time, Received_MAC_Time, Allowance))
                 {
-                    if (Spoof_Check[i].Xmit_Cnt != Received_Xmit_Cnt)
+                    if (Spoof_Check[i].Xmit_Cnt != Received_Xmit_Cnt)   //not a duplicate ADV
                     {
-
-                        //Spoof_Check[i].Attempt_MAC_Time = expected_mac_time;
                         Spoof_Check[i].Attempt_Cnt++;
                         Spoof_Check[i].Xmit_Cnt = Received_Xmit_Cnt;
                         #if MyDebugEnb
@@ -239,10 +215,7 @@
                         else    //Received_MAC_Time matches Attempt, but not enough times to be considered as valid.
                         {
                             return_val = ADVisSpoof;
-                            
                         }
-                        
-                        
                     }//is not duplicate, and transmit count matches
                     else
                     {
@@ -260,7 +233,6 @@
                     return_val = ADVisSpoof;  //it should still be zero, so this is just for clarification
                     //at this point:  MAC matches, MAC_Time doesn't match primary nor secondary.
                     Spoof_Check[i].Attempt_Cnt = 0;  //reset secondary count
-
                 }
                 //update second backup regardless whether it matches exptected_mac_time matches secondary or not.
                 Spoof_Check[i].Attempt_MAC_Time = Expected_MAC_Time;
@@ -272,7 +244,7 @@
         else //MAC doesn't match
         {
             //MAC doesn't match and we've searched through entire record
-            //let's add this MAC as new, an initialze records to match this sensor
+            //let's add this MAC as new, and initialze records to match this sensor
             if (i >= (sizeOfSpoof - 1))   //we've searched through entire array and didn't find this MAC
             {
                 //we've searched through the entire array and didn't find this MAC address
@@ -284,8 +256,7 @@
                 
                 return_val = ADVisNew;
 
-                //create new entry for newly seen MAC @ tail
-                // why refigure??  Spoof_Check[Spoof_Ray_Tail].MAC_Time = ((uint16_t)(Gateway_Time.read_ms()/1000)) - Received_MAC_Time;
+                //create new entry for newly seen MAC @ tail of FIFO
                 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[0] = Received_MAC_Addr[0];
                 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[1] = Received_MAC_Addr[1];
                 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[2] = Received_MAC_Addr[2];
@@ -294,18 +265,16 @@
                 Spoof_Check[Spoof_Ray_Tail].MAC_Addr[5] = Received_MAC_Addr[5];
                 Spoof_Check[Spoof_Ray_Tail].Xmit_Cnt = Received_Xmit_Cnt;
 
-                //calculate Expected_MAC_Time
-                Is_Birth_Time_Correct (0, Received_MAC_Time, 3);
+                //call this just to calculate Expected_MAC_Time...kinda ugly to do this.  todo:  don't do this
+                Is_Birth_Time_Correct (0, Received_MAC_Time, Allowance);
                 #if MyDebugEnb
                 device.printf("Expected_MAC_Time should be %d \r\n", Expected_MAC_Time);
-
                 #endif
                 Spoof_Check[Spoof_Ray_Tail].MAC_Time = Expected_MAC_Time;    //wrong!!!
                 Spoof_Check[Spoof_Ray_Tail].Xmit_Cnt = Received_Xmit_Cnt;
                 Spoof_Check[Spoof_Ray_Tail].Attempt_Cnt = 0;
                 
                 //increment tail pointer to next position or wrap around
-                //todo:  might not be using the last index position of this array, not sure.  Doesn't matter IDK.
                 if (Spoof_Ray_Tail >= (sizeOfSpoof-1) ) //FIFO at end of array, return to beginning
                 {
                     Spoof_Ray_Tail = 0;
@@ -317,73 +286,50 @@
                 
             }//end if loop at end of array
         }//end else not maching MAC
-        
     }//loop through Spoof_Check array
 
-    
+ 
     return return_val;
 }//end Is_Not_Spoofed()
 
 
-
-
-void periodicCallback(void) //every 1800 seconds = 30 minutes, max for ticker.
+void periodicCallback(void) //every Periodicity seconds, reset clock
 {
 #if MyDebugEnb
     device.printf("===== reset timer ===== \r\n");
 #endif
-    //led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
-    //device.printf("periodic 5...");
-    //device.printf("\r\n");
     Gateway_Time.reset();
 }
 
 
-//with the current beacon, I see 3 valid advertisements per wake period with ambient other beacons.  sometimes 4.
-//even with 2 phones broadcasting at 10Hz, still see 3 adv's.
+
+//Scheme for recognizing our beacons and ignoring all other beacons
+//idea:  could use something like Pearson hash on parts of MAC address to make less obvious
 bool is_ours(const uint8_t * adv_data, const uint8_t * adv_address)
 {
-    //if ((adv_data[5] == adv_address[3]) && (adv_data[6] == adv_address[2]) && (adv_data[7] == adv_address[1]) && (adv_data[8] == adv_address[0]))
     if ((adv_data[5] == adv_address[3]) && (adv_data[6] == adv_address[2]))
         return 1;
     else
         return 0;
 }
 
+
+// callback when BLE stack scans and finds a BLE ADV packet
+// Parse ADV and determine if it's one of ours, output data to serial if it is.
 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
 
-
-    //BLE MAC Address (6 bytes):
-    //      params->peerAddr[5]
-    //      params->peerAddr[4]
-    //      ...
-    //      params->peerAddr[0]
-    //RSSI = params->rssi
-    //Payload
-    //  params->advertisingData[#<advertisingDataLen]
-    
-
-    
-    //              [<---MY DATA-->]
-    //0x02      0x01    0x06    0x06    0xff    D   E   C   ?  ?
-    //0         1       2       3       4       5   6   7   8   9
-
     if ( (params->advertisingDataLen) >= 8)
     {
-        //if one of "ours", these UUID fields will be this value.  Arbitrary " 
-        
-        //if ( (params->advertisingData[5] == 0x44) && (params->advertisingData[6] == 0x45) && (params->advertisingData[7]==0x43) )
-        //if (is_ours(params->advertisingData[5],params->advertisingData[6],params->advertisingData[7], params->advertisingData[8], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0] ))
         if (is_ours(params->advertisingData, params->peerAddr))
         {
             #if MyDebugEnb
             device.printf("----------- ADV CAll Back -----------------\r\n  ");
             #endif 
+            
             //**************
             // Decrypt data
             //**************
             //prep array for deciphering the encrypted portion of advertisement
-            //device.printf("\r\n copy adv length:  %d \r\n", params->advertisingDataLen);  //always 31
             for (int i = 0; i<16; i++)
             {
                 src_buf[i]=params->advertisingData[i+15];
@@ -391,16 +337,8 @@
                 //device.printf("%x ", src_buf[i]);
                 #endif
             }
+            mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_DECRYPT, src_buf, des_buf );   //execution time not an issue
             #if MyDebugEnb
-            //device.printf("...\r\n  ");
-            #endif 
-
-            
-            mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_DECRYPT, src_buf, des_buf );   //execution time not an issue
-            
-            
-            #if MyDebugEnb
-            
             //device.printf("decoded first 16 bytes \r\n");
             for (int i = 0; i<16; i++)
             {
@@ -416,7 +354,8 @@
             }
             //device.printf("done----- \r\n");
             #endif
-            //save MAC address
+            
+            //save MAC address to global
             Received_MAC_Addr[0] = params->peerAddr[0];
             Received_MAC_Addr[1] = params->peerAddr[1];
             Received_MAC_Addr[2] = params->peerAddr[2];
@@ -424,31 +363,13 @@
             Received_MAC_Addr[4] = params->peerAddr[4];
             Received_MAC_Addr[5] = params->peerAddr[5];
             
-            uint16_t beacon_timer = des_buf[0] | (des_buf[1] << 8);  //it's a 2 byte uint little endian
-            Received_MAC_Time = beacon_timer;
+            Received_MAC_Time = des_buf[0] | (des_buf[1] << 8);  //it's a 2 byte uint little endian
             Received_Xmit_Cnt = des_buf[2];
             
             
             
-            /*
-            BLE Received from MAC C2F154BB0AF9
-            volt:3.11,mag:1
             
-            uart-transmit:
-            mac:C2F154BB0AF9,rssi:##,volt:3.11,mag:1
-            
-            /ble/C2F154BB0AF9/rssi
-            /ble/C2F154BB0AF9/1st_token
-            /ble/c2F153
-            
-            */
-            /*
-            device.printf("Adv peerAddr: [%02x%02x%02x%02x%02x%02x] rssi %d, ScanResp: %u, AdvType: %u\r\n",
-              params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
-              params->rssi, params->isScanResponse, params->type);
-            */
-            
-            // punch out the data as json
+            // punch out the data over serial as json 
             //---------------------------------------
             // 1.  MAC and RSSI
             // "mac":xxxxxxxx,rssi:xx,
@@ -458,8 +379,9 @@
             device.printf("--------ADV_Result = %d", ADV_Result);
             #endif
 
-
-            if (ADV_Result == ADVisNew)
+            //decide wether or not duplicate ADV packets should be output as well.
+            //if ((ADV_Result == ADVisNew) || (ADV_Result==ADVisDuplicate))  //output both first and duplicates
+            if (ADV_Result == ADVisNew)  //only output first received ADV
             {
                 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"rssi\":%d,",
                     params->peerAddr[5], 
@@ -470,10 +392,9 @@
                     params->peerAddr[0],
                     params->rssi
                     );
-                //mac:"c2f154bb0af9"
     
                 //---------------------------------------
-                // 2.  Volt
+                // 2.  Volt is always X.XX, per Beacon code
                 // "volt":3.03,
                 //---------------------------------------
                 device.printf("\"volt\":%c%c%c%c,",
@@ -483,61 +404,41 @@
                     params->advertisingData[12]);
                 
     
-    
-    
                 //---------------------------------------
-                // 3.  clock
-                // "tmr":xxx,
-                //---------------------------------------
-                //print clock
-                //     "tmr":3232,
+                // 3.  Beacon time (# seconds since birth, clocked around Periodicity) 0-1800 seconds
+                // "tmr":xxxx,
                 //---------------------------------------
                 
-                device.printf("\"tmr\":%d,", beacon_timer);
-                //device.printf("\"tmr\":%d,", des_buf[0]);
+                device.printf("\"tmr\":%d,", Received_MAC_Time);
+                
+                //---------------------------------------
+                // 4.  Xmit Counter 0-255, incremented by Beacon with each new unique ADV event.
+                // "tmr":xxxx,
+                //---------------------------------------                
                 device.printf("\"xmit_cnt\":%d,", Received_Xmit_Cnt);
                 
                 //---------------------------------------
-                // 4.  rest of payload as json
+                // 5.  rest of sensor payload as json
                 // "tmr":xxx,
                 //---------------------------------------
-                for (int i = 3; i< 16; i++)
+                for (int i = 3; i<16; i++)
                 {
-                    //device.printf("%02x", params->advertisingData[index]);
                     device.printf("%c", des_buf[i]);    //print as character
+                    //Note that sensor JSON payload most likely is not exactly 16 bytes long, so there's likely /0 in middle
+                    // of this.  But JSON library on gateway handles this gracefully.
                 }
     
-    
-    
-                /*
-                for (unsigned index = 8; index < params->advertisingDataLen; index++)
+                device.printf("}");
+                device.printf("\r\n");  //gateway looking for cariage return to indicate end
+                wait_ms(60);  //needed to give gateway time to assert flow control handshake pin
+                while (pinHandShake.read() == 1)    //normally pulled down, so loop when gateway processing;
                 {
-                    //device.printf("%02x", params->advertisingData[index]);
-                    device.printf("%c", params->advertisingData[index]);
+                    //uart flow control
+                    //blocking until gateway has processed ADV data from uart
                 }
-                */
-                
-                device.printf("}");
-                device.printf("\r\n");
-                
-                /*
-                mac:c2f154bb0af9,rssi:-55,volt:3.05,mag:1
-                mac:c2f154bb0af9,rssi:-67,volt:3.05,mag:1
-                mac:c2f154bb0af9,rssi:-60,volt:3.07,mag:0
-                */
             }
-            if (ADV_Result == ADVisDuplicate)
-            {
-                device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"duplicate\": %d}\r\n",
-                    params->peerAddr[5], 
-                    params->peerAddr[4], 
-                    params->peerAddr[3], 
-                    params->peerAddr[2], 
-                    params->peerAddr[1], 
-                    params->peerAddr[0],
-                    ADV_Result);
-            }
-            if (ADV_Result == ADVisSpoof)
+
+            if (ADV_Result == ADVisSpoof)  //If detected spoofed sensor data
             {
                 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"spoof\": %d}\r\n",
                     params->peerAddr[5], 
@@ -548,7 +449,8 @@
                     params->peerAddr[0],
                     ADV_Result);
             }
-            if (ADV_Result == ADVisUnknown)
+            
+            if (ADV_Result == ADVisUnknown)  //catch all, should never occur
             {
                 device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"unknown\": %d}\r\n",
                     params->peerAddr[5], 
@@ -561,7 +463,6 @@
             }
         }//end if it's our adv
     }//end if advertisingDataLen
-
 }//end advertisementCallback
 
 
@@ -595,13 +496,21 @@
         return;
     }
  
-    // in ms.  Duty cycle = (interval / window);  200ms/500ms = 40%
-    ble.gap().setScanParams(500 /* scan interval */, 200 /* scan window */);
+    //note:  defaults to scanning 3 channels.
+    // Window and Interval in ms.  Duty cycle = (interval / window);  200ms/500ms = 40%;  Max is 10000
+    //  |---window---|                          |---window---|                       |---window---|
+    //  |---------- interval @ ch1 -----| |------- interval @ ch2--------||-----interval @ ch3-------|
+    //  set window equal to interval for full duty cycle scanning
+    //  set interval to hit all 3 channels of beacon advertising over advertising time duration
+    ble.gap().setScanParams(500 /* scan interval */, 500 /* scan window */);
     ble.gap().startScan(advertisementCallback);
 }
 
 int main(void)
 {
+    pinHandShake.mode(PullDown); //Expecting gateway to set pin high for flow control
+    
+    //intialize spoof checking data structure
     for (int i=0; i<sizeOfSpoof; i++)
     {
         Spoof_Check[i].MAC_Addr[0]= 0;
@@ -613,21 +522,31 @@
         Spoof_Check[i].Attempt_Cnt = 0;
         Spoof_Check[i].Xmit_Cnt = 0;
     }
-    
+        
+    //maintains periodicity for spoof checking scheme
     Gateway_Time.start();
-    device.baud(9600);
-    device.printf("started main 06 hashed observer... ");
-    device.printf("\r\n");
     ticker.attach(periodicCallback, Periodicity);
     
-    //mbedtls_aes_init(&aes);
-    mbedtls_aes_setkey_dec( &aes, iv, 128 );
-    //mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_DECRYPT, input, output );
+    device.baud(9600);  //p0.9 tx, p0.11 rx.  Use p0.9 to gateway
+
+    mbedtls_aes_setkey_dec( &aes, iv, 128 );  //set AES key for decrypt
 
     BLE &ble = BLE::Instance();
     ble.init(bleInitComplete);
-
-    while (true) {
-        ble.waitForEvent();
+    
+    ble.getAddress(0,MAC_gateway);  //get this gateway module's ble MAC
+    device.printf("{\"mac\":\"%02x%02x%02x%02x%02x%02x\",\"gatewaystart\":\"now\"},",
+        MAC_gateway[5], 
+        MAC_gateway[4], 
+        MAC_gateway[3], 
+        MAC_gateway[2], 
+        MAC_gateway[1], 
+        MAC_gateway[0]
+        );
+    device.printf("\r\n");
+    
+    while (true) 
+    {
+        ble.waitForEvent();  //idle here until callback
     }
 }
--- a/mbed.bld	Sat Jul 29 22:03:27 2017 +0000
+++ b/mbed.bld	Sun Aug 27 05:48:02 2017 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/4336505e4b1c
\ No newline at end of file
+https://mbed.org/users/mbed_official/code/mbed/builds/e2bfab296f20
\ No newline at end of file
--- a/nRF51822.lib	Sat Jul 29 22:03:27 2017 +0000
+++ b/nRF51822.lib	Sun Aug 27 05:48:02 2017 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#3cc0718d98d0
+http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#c90ae1400bf2