BLE ADV Gateway, converts advertisement to proper JSON serial output

Dependencies:   BLE_API mbed mbedtls nRF51822

Revision:
13:e136665cf993
Parent:
12:30c6e83f0fe5
Child:
14:0486f885b1b1
diff -r 30c6e83f0fe5 -r e136665cf993 main.cpp
--- 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
     }
 }