Did I feed the dog? How much dog food is left?

Dependencies:   BLE_API VL6180 mbed nRF51822

Fork of BLE_Sensor by Eric Tsai

Revision:
12:1049290dd610
Parent:
11:4f925834167d
--- a/main.cpp	Sat Jul 29 22:01:45 2017 +0000
+++ b/main.cpp	Thu May 03 02:56:54 2018 +0000
@@ -1,80 +1,142 @@
-/* 
-Eric Tsai
+/*  
+ * 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: started with the basic BLE Temperature Beacon code from mbed Bluetooth Low Energy team
+ * https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_TemperatureBeacon/file/0a8bbb6dea16/main.cpp
+ *
+ * Dog food sensor (feed activity and level)
+ * keywords:  todo, tochange
+*/
 
-7/29/2017:  added clock algorithm to corresond with gateway spoof checking
- 
- */
 
-//required to call the ecb functions
 extern "C"
 {
-   #include "nrf_ecb.h"
+   #include "nrf_ecb.h"  //required to call the ecb functions for encryption
 }
  
 #include "mbed.h"
 #include "toolchain.h"
 #include "ble/BLE.h"
-#include "TMP_nrf51/TMP_nrf51.h"
-
-//comment out when done with debug uart, else eats batteries
-#define MyDebugEnb 0
-
-//Pin "P0.4" on nRF51822 = mbed "p4".
-//InterruptIn is pulled-up.  GND the pin to activate.
+//#include "TMP_nrf51/TMP_nrf51.h"
+//#include "TMP102.h"
+#include "VL6180.h" //https://developer.mbed.org/users/sburg/code/VL6180/
+//https://developer.mbed.org/users/sburg/notebook/vl6180-time-of-flight-range-finder/
 
-// waveshare board ******
-//InterruptIn button1(p10);
-//InterruptIn button2(p11);
+/*******************************************************************************************
+ * START tochange: items that may need customization depending on sensors, hardware, and desired behavior
+*******************************************************************************************/
+const uint16_t Periodic_Update_Seconds = 900; //number of seconds between periodic I/O status re-transmits 900s =15 min.
+#define MyDebugEnb 0  //enables serial output for debug, consumes ~1mA when idle
+uint8_t magnet_near=0;  //this I/O, specifically for reed switch sensor
+//TMP102 tempI2C(p0, p1, 0x90);
+//VL6180 rf(p12, p15); //I2C purple board sda=p12, scl=p15
+VL6180 rf(p9, p11); //I2C purple board sda=p12, scl=p15
+//DigitalOut pinHandShake(p0);  //shutdown pin
+//VL6180 rf(p12, p15); //I2C sda=P0 and scl=p1
+/* hardware interrupt pins, selected based on hardware
+ *Syntax:  Pin "P0.4" on nRF51822 documentation is mbed "p4".
+ * InterruptIn is pulled-up.  GND the pin to activate.
+*/
 
-// purple board ******
-//InterruptIn button1(p23);
-//InterruptIn button2(p24);
-
-// universal
-InterruptIn button1(p0);
-InterruptIn button2(p1);
+//tilt switch on "button1", should be open (not shorted) in rest state
+InterruptIn button1(p0);    //nRF51822 P0.0
+//InterruptIn button2(p1);    //nRF51822 P0.1
 
 
+/******************************************************************************************
+ * END tochange
+*******************************************************************************************/
 
-//Serial device(p9, p11);  // tx, rx, purple board and Rigado
+
 #if MyDebugEnb
-// if you see ~1mA consumption during sleep, that's because uart is enabled.
+// if you see ~1mA consumption during sleep, that's because MyDebugEnb==1, it's enabled.
 Serial device(p9, p11);  //nRF51822 uart :  TX=p9.  RX=p11
 #endif
 
+static Ticker Tic_Stop_Adv;   //used to stop advertising after X seconds
+static Ticker Tic_Debounce; //debounce I/O
+static Ticker Tic_Periodic; //transmit sensor data on a periodic basis outside I/O events
 
-static Timer myTimer;  //timed advertising
-static Ticker tic_adv;   //stop adv
-static Ticker tic_debounce; //debounce I/O
-static Ticker tic_periodic; //regular updates
-static Ticker tic_clock_reset; //resets clock
-const uint16_t Periodicity = 180;   //clock periodicity used for spoof checking, should be 1800 seconds for 30minutes
-//static TMP_nrf51  tempSensor;
-static bool flag_update_io = false;
-static bool flag_periodic_call = false;
-static bool flag_detach_adv_tic = false;
-static bool flag_set_debounce_tic = false;  //not used
+const uint16_t Periodicity = 1800;   //birthday periodicity used for spoof checking, must match gateway. Should be 1800 seconds for 30minutes
+static Timer Tmr_From_Birthday;  //holds number of seconds since birthday, for spoof detection
+static Ticker Tic_Birthday; //resets Tmr_From_Birthday every Periodicity seconds, for spoof detection
+
 
-//static DigitalOut alivenessLED(LED1, 1);
-float mySensor = 2.0f;
+static bool Flag_Update_IO = false;  //flag to indicate event is hardware interrupt
+static bool Flag_Periodic_Call = false;  //flag to indicate event is periodic callback
+static bool Flag_Detach_Adv_Tic = false;  //flag to stop advertising
+
+/* Optional: Device Name, add for human read-ability */
+const static char     DEVICE_NAME[] = "LOL";
+
+//dog food sensor
+uint16_t button1_released_counter = 0;
 
 
-/* Optional: Device Name, add for human read-ability */
-const static char     DEVICE_NAME[] = "CUU";
+//Advertisement Data
+//note:  AdvData[] holds bytes [5] to byte [30] of entire advertising data.  The user content part after ADV flag and header
+static uint8_t AdvData[] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};  //26 Bytes manufacturer specific data
+char buffer[10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //hold I/O reading json
+char bat_volt_char[6] = {0, 0, 0, 0, 0, 0}; //hold json for battery reading
+uint8_t Adv_First_Section[10];  //holds the first several bytes with a pattern indicating this sensor is "one of ours" 
+uint8_t mac_reverse[6] = {0x0,0x0,0x0,0x0,0x0,0x0};  //mac address for this module
+char sensor_char[8] = {0, 0, 0, 0, 0, 0}; //hold json for temperature
 
-/* You have up to 26 bytes of advertising data to use. */
-/*
-Advertisement
+/*****  Advertisement structure is 31 Bytes  ****************
+
+https://docs.mbed.com/docs/ble-intros/en/latest/Advanced/CustomGAP/
 
-*/
-//full with nullls
-static uint8_t AdvData[] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};   /* Example of hex data */
-char buffer[10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //battery analog reading
-char bat_volt_char[6] = {0, 0, 0, 0, 0, 0};
-uint8_t Adv_First_Section[10];
-uint8_t mac_reverse[6] = {0x0,0x0,0x0,0x0,0x0,0x0};
-uint8_t magnet_near=0;
+Full Advertisement:
+First 5 bytes are set by stack according to flag and header parameters.
+Last 26 bytes are user data
+-- tabbed --
+Byte 0  |   AD1 Length  |       0x02    |   AD1 is 2 bytes long
+Byte 1  |   AD1 Type    |       0x01    |   AD1 Data interpreted as flag
+Byte 2  |   AD1 Data 0  |       0x06    |   AD1 Data flag mean "00000110"
+Byte 3  |   AD2 Length  |       0x1B    |   AD2 is 27 bytes (0x1B) long (rest of this data)
+Byte 4  |   AD2 Type    |       0xFF    |   0xFF mean Manufacturer Specific Data
+Byte 5  |   AD2 Data 0  |   ADV_Data[0] |   "our device" flag, MAC[3]
+Byte 6  |   AD2 Data 1  |   ADV_Data[1] |   "out device" flag, MAC[2]
+Byte 7  |   AD2 Data 2  |   ADV_Data[2] |   "out device" flag, MAC[1]
+Byte 8  |   AD2 Data 3  |   ADV_Data[3] |   "out device" flag, MAC[0]
+Byte 9  |   AD2 Data 4  |   ADV_Data[4] |   battery voltage json MSB, ie 3 in 3.14
+Byte 10 |   AD2 Data 5  |   ADV_Data[5] |   battery voltage json
+Byte 11 |   AD2 Data 6  |   ADV_Data[6] |   battery voltage json
+Byte 12 |   AD2 Data 7  |   ADV_Data[7] |   battery voltage json LSB, ie 4 in 3.14
+Byte 13 |   AD2 Data 8  |   ADV_Data[8] |   reserved
+Byte 14 |   AD2 Data 9  |   ADV_Data[9] |   reserved
+Byte 15 |   AD2 Data 10 |   ADV_Data[10] Encrypted  |   spoof - clock high byte, range 0 to 1800 seconds
+Byte 16 |   AD2 Data 11 |   ADV_Data[11] Encrypted  |   spoof - clock low byte
+Byte 17 |   AD2 Data 12 |   ADV_Data[12] Encrypted  |   Xmit_Cnt - increments per transmit event, 0-255
+Byte 18 |   AD2 Data 13 |   ADV_Data[13] Encrypted  |   JSON[0]
+Byte 19 |   AD2 Data 14 |   ADV_Data[14] Encrypted  |   JSON[1]
+Byte 20 |   AD2 Data 15 |   ADV_Data[15] Encrypted  |   JSON[2]
+Byte 21 |   AD2 Data 16 |   ADV_Data[16] Encrypted  |   JSON[3]
+Byte 22 |   AD2 Data 17 |   ADV_Data[17] Encrypted  |   JSON[4]
+Byte 23 |   AD2 Data 18 |   ADV_Data[18] Encrypted  |   JSON[5]
+Byte 24 |   AD2 Data 19 |   ADV_Data[19] Encrypted  |   JSON[6]
+Byte 25 |   AD2 Data 20 |   ADV_Data[20] Encrypted  |   JSON[7]
+Byte 26 |   AD2 Data 21 |   ADV_Data[21] Encrypted  |   JSON[8]
+Byte 27 |   AD2 Data 22 |   ADV_Data[22] Encrypted  |   JSON[9]
+Byte 28 |   AD2 Data 23 |   ADV_Data[23] Encrypted  |   JSON[10]
+Byte 29 |   AD2 Data 24 |   ADV_Data[24] Encrypted  |   JSON[11]
+Byte 30 |   AD2 Data 25 |   ADV_Data[25] Encrypted  |   JSON[12]
 
+***************************************************/
 
 
 static uint8_t key[16] = {0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4};
@@ -86,7 +148,6 @@
 static uint8_t des_buf[16] = {0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4,0x1,0x2,0x3,0x4};
 
 uint8_t Xmit_Cnt = 1;
-//const static uint8_t AdvData[] = {"ChangeThisData"};         /* Example of character data */
 
 
 
@@ -105,55 +166,50 @@
     //app ID is 16 bit, (0xFEFE)
     uint16_t    applicationSpecificId; /* An ID used to identify temperature value in the manufacture specific AD data field */
     
-    //float = 32-bit.  
-    //tsai: change this to uint32_t!!!
-    TMP_nrf51::TempSensorValue_t tmpSensorValue;        /* this is a float (32-bit), user data */
+    //TMP_nrf51::TempSensorValue_t tmpSensorValue;        /* this is a float (32-bit), user data */
 } PACKED;
 
 
 
 void debounce_Callback(void)
 {
-    tic_debounce.detach();
-    flag_set_debounce_tic = false;      //not used
-    flag_update_io = true;  //start advertising
+    //Tic_Debounce.detach();
+    button1.mode(PullUp);   //tilt switch should be opened (not shorted) in rest state
+    wait_ms(1);
+    uint8_t button1_state = button1.read();
+    if ( button1_state == 1)    //open circuit, top is in rest position
+    {
+        button1_released_counter++;
+    }
+    else
+    {
+        button1_released_counter = 0;
+    }
+    if (button1_released_counter >= 3)
+    {
+        Flag_Update_IO = true;  //start advertising
+        Tic_Debounce.detach();
+        button1_released_counter = 0;
+        //Period = false;
+    }
+    
     /* Note that the buttonPressedCallback() executes in interrupt context, so it is safer to access
      * BLE device API from the main thread. */
-    //buttonState = PRESSED;
+
 }
 
-//----- button rising ---
+/*
+//ISR for I/O interrupt
 void buttonPressedCallback(void)
 {
-
-
-    //flag_update_io = true;
-    
-    tic_debounce.attach(debounce_Callback, 1); //ok to attach multiple times, first one wins
-    
-
-    //buttonState = PRESSED;
-    
-    /*
-    if (flag_set_debounce_tic == false)
-    {
-        flag_set_debounce_tic = true;
-        
-    }
-    */
+    Tic_Debounce.attach(debounce_Callback, 1); //ok to attach multiple times, recent one wins
 }
-
-//----- button falling ---
+*/
+//ISR for I/O interrupt
 void buttonReleasedCallback(void)
 {
     
-
-    //flag_update_io = true;
-    
-    tic_debounce.attach(debounce_Callback, 1);
-    
-    
-  
+    Tic_Debounce.attach(debounce_Callback, 3);  
 }
 
 
@@ -162,42 +218,49 @@
     //stops advertising after X seconds
     /* Note that the Callback() executes in interrupt context, so it is safer to do
      * heavy-weight sensor polling from the main thread (where we should be able to block safely, if needed). */
-    
-    //tic_adv.detach();
-    
-    flag_detach_adv_tic = true;
-    //ble.gap().stopAdvertising();
-    
+    Flag_Detach_Adv_Tic = true;
+
+}
 
+/* ****************************************
+ * Decides what actions need to be performed on periodic basis
+*******************************************/
+void periodic_Callback(void)
+{
+    Flag_Update_IO = true;
+    Flag_Periodic_Call = true;
+}
+
+/* ****************************************
+ * Decides what actions need to be performed on periodic basis
+*******************************************/
+void read_IO_Callback(void)
+{
+    Flag_Update_IO = true;
+    Flag_Periodic_Call = false;
 }
 
 
-
-
-
-void periodic_Callback(void)
-{
-    flag_update_io = true;
-    flag_periodic_call = true;
-}
-
+/* ****************************************
+ * No RTC available, tickers only have a 35 minute range.
+ * So periodicity for spoof avoidance is set to 30 minutes
+*******************************************/
 void clock_reset_Callback(void)
 {
 #if MyDebugEnb
     device.printf("===== reset timer =====");
     device.printf("\r\n");
 #endif
-    myTimer.reset();
+    Tmr_From_Birthday.reset();
 };
 
+
 void setupApplicationData(ApplicationData_t &appData)
 {
     // two byte ID:  0xFEFE
     static const uint16_t APP_SPECIFIC_ID_TEST = 0xFEFE;        //2 byte application ID
 
     appData.applicationSpecificId = APP_SPECIFIC_ID_TEST;
-    //appData.tmpSensorValue        = tempSensor.get();
-    appData.tmpSensorValue        = mySensor;
 }
 
 
@@ -210,6 +273,8 @@
     /* Initialization error handling should go here */
 }
 
+
+
 /**
  * Callback triggered when the ble initialization process has finished
  */
@@ -237,23 +302,18 @@
     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
     
 
-
     //from GAP example
     /* Sacrifice 2B of 31B to AdvType overhead, rest goes to AdvData array you define */
     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, AdvData, sizeof(AdvData));
 
     /* Setup advertising parameters:  not connectable */
     ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
-    ble.gap().setAdvertisingInterval(300);  //one advertisment every 300ms.  Self tickers, so you don't have to worry.
+    ble.gap().setAdvertisingInterval(200);  //one advertisment every 300ms.  Self tickers, so you don't have to worry.
 
+}
 
 
-    //don't start advertising on init.  Only advertise on pin interrupt.
-    //ble.gap().startAdvertising();
-}
-
 //not needed anymore
-//https://developer.mbed.org/users/MarceloSalazar/notebook/measuring-battery-voltage-with-nordic-nrf51x/
 void my_analogin_init(void)
 {
     
@@ -267,7 +327,13 @@
     NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Enabled;
 }
 
-uint16_t my_analogin_read_u16(void)
+
+/* ****************************************
+ * Read battery voltage using bandgap reference
+ * shunt Vdd to ADC, thanks to Marcelo Salazar's notes here:
+ * https://developer.mbed.org/users/MarceloSalazar/notebook/measuring-battery-voltage-with-nordic-nrf51x/
+*******************************************/
+uint16_t read_bat_volt(void)
 {
     //10 bit resolution, route Vdd as analog input, set ADC ref to VBG band gap
     //disable analog pin select "PSEL" because we're using Vdd as analog input
@@ -288,7 +354,7 @@
     
     //while loop doesn't actually loop until reading comlete, use a wait.
     while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {};
-    wait_ms(2);
+    wait_ms(1);
 
     //save off RESULT before disabling.
     //uint16_t myresult = (uint16_t)NRF_ADC->RESULT;
@@ -299,9 +365,16 @@
     
     return (uint16_t)NRF_ADC->RESULT; // 10 bit
     //return myresult;
-}
+}  //end read_bat_volt
+
+
 
-uint16_t my_analog_pin_read(void)
+/* ****************************************
+ * Read battery voltage using bandgap reference
+ * shunt analog pin to ADC, from API here
+ * https://developer.mbed.org/users/mbed_official/code/mbed-src/file/cb4253f91ada/targets/hal/TARGET_NORDIC/TARGET_NRF51822/analogin_api.c
+*******************************************/
+uint16_t read_ADC_pin(void)
 {
 
     //10 bit resolution, route PSEL pin as 1/3 input sel,
@@ -324,7 +397,7 @@
     
     //while loop doesn't actually loop until reading comlete, use a wait.
     while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {};
-    wait_ms(2);
+    wait_ms(1);     //needed because busy while loop doesn't run.
 
     //save off RESULT before disabling.
     //uint16_t myresult = (uint16_t)NRF_ADC->RESULT;
@@ -335,10 +408,14 @@
     
     return (uint16_t)NRF_ADC->RESULT; // 10 bit
     //return myresult;
-}
+}  //end read_ADC_pin
 
 
-//hash_first_section(Adv_First_Section, mac_reverse, bat_reading);
+/* ****************************************
+ * Pattern scheme indicating "one of ours"
+ * generate first part of ADV data so that observer can recognize it as "one of ours".
+ * use specific schema to decide how we're recognizing our sensor ADV
+*******************************************/
 void hash_first_section(uint8_t * dest, const uint8_t * mac_addr, const char * bat_volt_str)
 {
     dest[0] = mac_addr[3];
@@ -351,46 +428,40 @@
     dest[7] = bat_volt_str[3];
     dest[8] = 0x10;
     dest[9] = 0x11;
-#if MyDebugEnb
-    
-    device.printf("hash array: ");
-    for (int i=0; i<10; i++)
-    {
-        device.printf("%x ", dest[i]);
-    }
-    device.printf("\r\n");
-#endif
+    #if MyDebugEnb
+        
+        device.printf("hash array: ");
+        for (int i=0; i<10; i++)
+        {
+            device.printf("%x ", dest[i]);
+        }
+        device.printf("\r\n");
+    #endif
 }
 
 
-uint16_t clock_remainder = 0;
-
+/* ****************************************
+ * 
+ * Main Loop
+ * 
+*******************************************/
 int main(void)
 {
 
-#if MyDebugEnb
-    device.baud(9600);
-    device.printf("started sensor node 36 ");
-    device.printf("\r\n");
-#endif
+    #if MyDebugEnb
+        device.baud(9600);
+        device.printf("started sensor node 36 ");
+        device.printf("\r\n");
+    #endif
 
-    
-    
-    //Timer myTimer;  //moved to global
-    myTimer.start();
-
+    //pinHandShake = 0;
+    //pinHandShake.mode(PullNone); //Expecting gateway to set pin high for flow control
+    Tmr_From_Birthday.start();      //tracks # sec since birthday
 
-    button1.fall(buttonPressedCallback);
-    button1.rise(buttonReleasedCallback);
-    button1.mode(PullNone);
-    button1.fall(NULL);
-    button1.rise(NULL); 
 
     BLE &ble = BLE::Instance();
     ble.init(bleInitComplete);
     
-    //debug uart
-    //device.baud(115200);
     float bat_reading;  //hold battery voltage reading (Vbg/Vcc)
     
     my_analogin_init();//routes band-gap to analog input
@@ -400,59 +471,60 @@
     while (ble.hasInitialized() == false) { /* spin loop */ }
     
     //every X seconds, sends period update, up to 1800 (30 minutes)
-    tic_periodic.attach(periodic_Callback, 1600);
-    tic_clock_reset.attach(clock_reset_Callback, Periodicity);
-    
-    //how to generate random number using die tempearature
-    uint32_t myTempRand;
-    uint32_t * p_temp;
-    //get temperature for random number
-    //SVCALL(SD_TEMP_GET, myTempRand, sd_temp_get(p_temp));
-    //sd_temp_get(& myTempRand);
+    Tic_Periodic.attach(periodic_Callback, Periodic_Update_Seconds);  //send updated I/O every x seconds
+    Tic_Birthday.attach(clock_reset_Callback, Periodicity);  //clock algorithm periodicity
 
 
-    ble.getAddress(0,mac_reverse);  //NOTE:  last byte of MAC (as shown on phone app) is at mac[0], not mac[6];
-#if MyDebugEnb
-    device.printf("mac = ");
-    for (int i=0; i<6; i++) //prints out MAC address in reverse order; opps.
-    {
-        device.printf("%x:", mac_reverse[i]);
-    }
-    device.printf("\r\n");
-#endif
-    while (true) {
-        //seconds counts to 35 minutes:  mySeconds=2142, then 63392 which should be 2450 but isn't.
-        //00001000,01011110   -> 11110111,10100000
-        uint16_t mySeconds =(uint16_t)(myTimer.read_ms()/1000); //problem:  mySeconds is only 2 byte
-        //xmit_cnt++;
-        //if (mySeconds > 1800)
-        //{
-        //    myTimer.reset();
-            //clock_remainder = mySeconds - 1800;
-        //}
-        //mySeconds = mySeconds + clock_remainder;  l3kjl3
+    ble.getAddress(0,mac_reverse);  //last byte of MAC (as shown on phone app) is at mac[0], not mac[6];
+    #if MyDebugEnb
+        device.printf("mac = ");
+        for (int i=0; i<6; i++) //prints out MAC address in reverse order; opps.
+        {
+            device.printf("%x:", mac_reverse[i]);
+        }
+        device.printf("\r\n");
+    #endif
+    
+    button1.rise(NULL);     //disable interrupt on rise
+    
+    while (true) 
+    {  //Main Loop
+
+        uint16_t seconds_Old =(uint16_t)(Tmr_From_Birthday.read_ms()/1000); // 0-1800 seconds (30 minutes)
+
+        #if MyDebugEnb
+            device.printf("current time in seconds: %d \r\n", seconds_Old);
+        #endif
+
         
-        //reading the ADV value, only goes up to 0-255;
-        //reading the uart:  current time in seconds: -1782, goes negative.
-        //need to be able to count 1800 seconds since that's the length of timer.
+        button1.mode(PullUp);   //tilt switch should be opened (not shorted) in rest state
+        //0 = activity
+        //1 = no activity
         
-#if MyDebugEnb
-        device.printf("current time in seconds: %d \r\n", mySeconds);
-#endif
-        //**** set which pin should be interrupt, set pullups ***
+        uint8_t button1_state = button1.read();
+        if ( button1_state == 0)    //pin grounded, there's activity, set sleep for 3 seconds
+        {
+            Tic_Periodic.attach(periodic_Callback, Periodic_Update_Seconds);    //reset periodic
+            button1.fall(NULL);     //disable interrupt
+            button1.mode(PullNone); //float pin to save battery
+            
+            //Tic_Periodic.attach(read_IO_Callback, 3);   //wait 3 seconds before reading pins again
+            //Flag_Update_IO = false;
+        }
+        else    //pin open, no activity
+        {
+            button1.fall(buttonReleasedCallback);     //enable interrupt
+            button1.mode(PullUp); //pull up on pin to get interrupt
+            
+        }
+        
+        /* comment out button interrupts
+        
         
         //set both pins to pull-up, so they're not floating when we read state
         button1.mode(PullUp);
         button2.mode(PullUp);
         
-        //wait_ms(300);   //contact settle
-        
-
-        //AdvData[12] is automatically CR?  why?
-        
-        //0x33 0x2E 0x33 0x32 0x13
-        //   3    .    3    2   CR
-        
         //expect either button1 or button2 is grounded, b/c using SPDT reed switch
         //the "common" pin on the reed switch should be on GND
         uint8_t button1_state = button1.read();
@@ -460,12 +532,10 @@
         
         
         //let's just update the pins on every wake.  Insurance against const drain.
-        //if state == 0, pin is grounded.  Unset interrupt and float pin
-        //set the other input
+        //if state == 0, pin is grounded.  Unset interrupt and float pin, set the other pin for ISR
         if ( (button1_state == 0) && (button2_state == 1) )
         {
             magnet_near = 1;
-            //AdvData[4] = 0x11;  //dont' set ADV data directly.  Using json now, need spacing
             //button1.disable_irq() //don't know if disables IRQ on port or pin
             button1.fall(NULL);     //disable interrupt
             button1.rise(NULL);     //disable interrupt
@@ -475,14 +545,13 @@
             button2.fall(buttonReleasedCallback);     //enable interrupt
             button2.rise(buttonReleasedCallback);     //enable interrupt
             button2.mode(PullUp); //pull up on pin to get interrupt
-#if MyDebugEnb
-        device.printf("=== button 1!  %d seconds=== \r\n", mySeconds);
-#endif
-        }
+            #if MyDebugEnb
+            device.printf("=== button 1!  %d seconds=== \r\n", seconds_Old);
+            #endif
+        }  //end if button2
         else if ( (button1_state == 1) && (button2_state == 0) )       //assume other pin is open circuit
         {
             magnet_near = 0;
-            //AdvData[4] = 0x22;    //dont' set ADV data directly.  Using json now, need spacing
             //button1.disable_irq() //don't know if disables IRQ on port or pin
             button1.fall(buttonReleasedCallback);     //enable interrupt
             button1.rise(buttonReleasedCallback);     //enable interrupt
@@ -492,10 +561,10 @@
             button2.fall(NULL);     //disable interrupt
             button2.rise(NULL);     //disable interrupt
             button2.mode(PullNone); //float pin to save battery
-#if MyDebugEnb
-        device.printf("=== button 2! === %d seconds\r\n", mySeconds);
-#endif
-        }    
+            #if MyDebugEnb
+            device.printf("=== button 2! === %d seconds\r\n", seconds_Old);
+            #endif
+        }  //end if button1
         else    //odd state, shouldn't happen, suck battery and pullup both pins
         {
             magnet_near = 2;
@@ -509,238 +578,219 @@
             button2.fall(buttonReleasedCallback);     //disable interrupt
             button2.rise(buttonReleasedCallback);     //disable interrupt
             button2.mode(PullUp); //float pin to save battery
-#if MyDebugEnb
-        device.printf("no buttons!! %d seconds\r\n", mySeconds);
-#endif
-        }         
+            #if MyDebugEnb
+            device.printf("no buttons!! %d seconds\r\n", seconds_Old);
+            #endif
+        }  //end odd state
         
         
-        if (flag_update_io) {
+        **** end comment out button interrupts */
+        
+        
+        if (Flag_Update_IO) {
+            
+            //pinHandShake = 1; //enable distance sensor
+            //wait_ms(500);   //let sensor run
             /* Do blocking calls or whatever hardware-specific action is
              * necessary to poll the sensor. */
 
+            //call attach again on periodic update to reset ticker
+            //next periodic updates happens Perioidc_Update_Seconds after I/O events
+            Tic_Periodic.attach(periodic_Callback, Periodic_Update_Seconds);   
             Xmit_Cnt++; //increment transmit counter when updating I/O
-
-
-            //read battery voltage
-            //analog reading consumes 940uA if not disabled
             
             
-            bat_reading = (float)my_analogin_read_u16();    
-            
+            //read and convert battery voltage
+            bat_reading = (float)read_bat_volt();    
             bat_reading = (bat_reading * 3.6) / 1024.0;
-#if MyDebugEnb
+            #if MyDebugEnb
             device.printf("bat reading: %f \r\n", bat_reading);
-#endif
-
-            //memset(&buffer[0], 0, sizeof(buffer));      //clear out buffer
-            //sprintf (buffer, "%f.2", bat_reading);    //don't know what i'm doing
-            //sprintf (buffer, "%.2f", bat_reading);
-            //AdvData[8] = buffer[0]; //"3"=0x33
-            //AdvData[9] = buffer[1]; //"."=0x2E
-            //AdvData[10] = buffer[2];//"3"=0x33
-            //AdvData[11] = buffer[3];//"2"=0x32
+            #endif
+            //write battery voltage
+            uint8_t total_chars;
+            memset(&bat_volt_char[0], 0, sizeof(bat_volt_char));      //clear out buffer
+            //convert battery voltage float value to string reprsentation to 2 decimal places, and save the size of string.
+            total_chars = sprintf (bat_volt_char, "%.2f", bat_reading);
             
-            //try this
-            //https://developer.mbed.org/users/mbed_official/code/mbed-src/file/cb4253f91ada/targets/hal/TARGET_NORDIC/TARGET_NRF51822/analogin_api.c
+            
+            //read and convert analog voltage.  Comment out this section if note needed, saves some battery
             NRF_ADC->TASKS_STOP = 1;
             float analogreading;
-            analogreading = (float)my_analog_pin_read();
+            analogreading = (float)read_ADC_pin();
             analogreading = (analogreading * 3.6) / 1024.0;
             #if MyDebugEnb
             device.printf("separate analog reading: %.02f \r\n", analogreading);
             #endif
             
-            //disable ADC
+            //disable ADC to save power
             NRF_ADC->TASKS_STOP = 1;
             NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled;    //disable to shutdown ADC & lower bat consumption
 
-
+            //read distance using VL6180 
+            float sensor_reading = rf;
+            uint8_t total_chars_sensor;
+            memset(&sensor_char[0], 0, sizeof(sensor_char));      //clear out buffer
+            total_chars_sensor = sprintf (sensor_char, "%.2f", sensor_reading);
+            
+            //pinHandShake = 0; //enable distance sensor
 
-            //***********************************
-            //form JSON string in ADV_DATA
-            //1)  volts starts at AdvData[8]
-            
+            #if MyDebugEnb
+            device.printf("char buff: %c%c%c%c \r\n", bat_volt_char[0], bat_volt_char[1], bat_volt_char[2], bat_volt_char[3]);
+            device.printf("num chars: %d \r\n", total_chars);
+            #endif
 
 
-            //write battery voltage
-            uint8_t total_chars;
-            memset(&bat_volt_char[0], 0, sizeof(bat_volt_char));      //clear out buffer
-            total_chars = sprintf (bat_volt_char, "%.2f", bat_reading);    //returns total number of characters
-
-#if MyDebugEnb
-            device.printf("char buff: %c%c%c%c \r\n", bat_volt_char[0], bat_volt_char[1], bat_volt_char[2], bat_volt_char[3]);
-            device.printf("num chars: %d \r\n", total_chars);
-#endif
+            //Generate "First Section" for ADV_Data so gateway will recognize our advertisement pattern
+            hash_first_section(Adv_First_Section, mac_reverse, bat_volt_char);
 
 
-
-            //memset(&Adv_First_Section[0], 0, sizeof(Adv_First_Section));  //not needed to reset
-            hash_first_section(Adv_First_Section, mac_reverse, bat_volt_char);
-            
-
-            
-            //------------------------------------------------------------------
-            //start writing out ADVData array
-            //------------------------------------------------------------------
-
+            /* ****************************************
+             * start writing out ADVData array
+             * todo: this is easy to write but hard to read.  Maybe make it easy to read and hard to write?
+             ******************************************/
             memset(&AdvData[0], 0, sizeof(AdvData));
             uint8_t JSON_loc=0; //AdvData[0]
 
-            AdvData[0] = Adv_First_Section[0];          //AdvData[0] = manf ID 01
-            JSON_loc++; //1
-            AdvData[1] = Adv_First_Section[1];          //AdvData[1] = manf ID 02
-            JSON_loc++; //2
-            AdvData[2] = Adv_First_Section[2];          //AdvData[2] = reserved
-            JSON_loc++; //3...
-            AdvData[3] = Adv_First_Section[3];          //AdvData[3] = reserved
-            JSON_loc++;
-            AdvData[4] = Adv_First_Section[4];          //AdvData[4] = voltage 01
+            AdvData[0] = Adv_First_Section[0];          //"our device" flag, MAC[3]
+            JSON_loc++; //JSON_loc == 1
+            AdvData[1] = Adv_First_Section[1];          //"out device" flag, MAC[2]...
+            JSON_loc++; //JSON_loc == 2
+            AdvData[2] = Adv_First_Section[2];
+            JSON_loc++; //JSON_loc == 3
+            AdvData[3] = Adv_First_Section[3];
+            JSON_loc++;  //JSON_loc == 4
+            AdvData[4] = Adv_First_Section[4];
+            JSON_loc++;  //JSON_loc == 5
+            AdvData[5] = Adv_First_Section[5];
+            JSON_loc++;  //JSON_loc == 6
+            AdvData[6] = Adv_First_Section[6];
             JSON_loc++;
-            AdvData[5] = Adv_First_Section[5];          //AdvData[5] = voltage 02
-            JSON_loc++;
-            AdvData[6] = Adv_First_Section[6];          //AdvData[6] = voltage 03
+            AdvData[7] = Adv_First_Section[7];
             JSON_loc++;
-            AdvData[7] = Adv_First_Section[7];          //AdvData[7] = voltage 04
+            AdvData[8] = Adv_First_Section[8];
             JSON_loc++;
-            AdvData[8] = Adv_First_Section[8];          //AdvData[8] = reserved
-            JSON_loc++;
-            AdvData[9] = Adv_First_Section[9];          //AdvData[9] = reserved
+            AdvData[9] = Adv_First_Section[9];
             JSON_loc++;
 
-#if MyDebugEnb
-    
-            device.printf("ADV first 10 array: ");
-            for (int i=0; i<10; i++)
-            {
-                device.printf("%x ", AdvData[i]);
-            }
-            device.printf("\r\n");
-#endif
+            #if MyDebugEnb
+                device.printf("ADV first 10 array: ");
+                for (int i=0; i<10; i++)
+                {
+                    device.printf("%x ", AdvData[i]);
+                }
+                device.printf("\r\n");
+            #endif
 
 
             JSON_loc = 10;
-            //start of encrypted data
-            //AdvData[10]
-            AdvData[10] = mySeconds & 0xFF;           //reserved for timer
+            //Start of encrypted user data
+            
+            //[10] and [11] hold 2 bytes for how many seconds since birthday, little endian
+            AdvData[10] = seconds_Old & 0xFF;
             JSON_loc++;
-            AdvData[11] = (mySeconds >> 8) & 0xFF;           //reserved for timer
+            AdvData[11] = (seconds_Old >> 8) & 0xFF;
             JSON_loc++;
+            
             AdvData[12] = Xmit_Cnt;
             JSON_loc++;
+            
             //start of jason data
-            JSON_loc = 13;
-            AdvData[JSON_loc] = 0x22;       //" start mag   pos=13
+            //"mag":
+            JSON_loc = 13;  //hardcode should be 13
+            AdvData[JSON_loc] = 0x22;       //ADV_Data[13] = "
             JSON_loc++; //14
             
-            AdvData[JSON_loc] = 0x6d;       //m,    pos=14
+            AdvData[JSON_loc] = 'd';       //ADV_Data[14] = d
             JSON_loc++; //15
             
-            AdvData[JSON_loc] = 0x61;       //a,    pos=15
+            AdvData[JSON_loc] = 'i';       //ADV_Data[15] = i
             JSON_loc++; //16
             
-            AdvData[JSON_loc] = 0x67;       //g,    pos=16
+            AdvData[JSON_loc] = 's';       //ADV_Data[16] = s
             JSON_loc++; //17
             
-            if (flag_periodic_call)
+            //for periodic calls, we want to add an extra mqtt level "p", using "/p"
+            //to delineate between MQTT publishes from real world I/O interrupts vs timer interrupts
+            if (Flag_Periodic_Call)
             {
-                //AdvData[JSON_loc] = 0x2f;       // "/"
-                //JSON_loc++;
-                AdvData[JSON_loc] = 0x2f;       // "/"  pos=17
-                JSON_loc++;//pos=18
-                AdvData[JSON_loc] = 0x70;       // "p"  poes=18
-                JSON_loc++;//pos=19
-            }//end if period call
+                AdvData[JSON_loc] = 0x2f;       // ADV_Data[17] = /
+                JSON_loc++;  //18
+                AdvData[JSON_loc] = 0x70;       // ADV_Data[18] =p
+                JSON_loc++;  //19
+            }
             
-            AdvData[JSON_loc] = 0x22;       //"     pos = 17 or 19
+            AdvData[JSON_loc] = 0x22;       //ADV_Data[17 or 19] = "   
             JSON_loc++; //20
 
-            AdvData[JSON_loc] = 0x3a;       //:     pos = 18 or 20
-            JSON_loc++; //22
+            AdvData[JSON_loc] = 0x3a;       //ADV_Data[18 or 20] = :
+            JSON_loc++; //21
             
-            //prep magnet location (1 or 0) for char[]
+            //convert magnet variable to string, for magnet sensor, this is easy
+            //since we only have 1 or 0, but this also works for analog values
+            /*
             memset(&buffer[0], 0, sizeof(buffer));      //clear out buffer
-            //magnet_near is an integer
             total_chars = sprintf (buffer, "%d", magnet_near);    //returns total number of characters, which is 1 character.
             for (int i=0; i < total_chars; i++)
             {
                 AdvData[JSON_loc] = buffer[i];
                 JSON_loc++; //23
             } //JSON_loc left at location of next character
+            */
             
-            //MUST null terminate for JSON to read correctly, else get intermittent JSON parse errors at gateway
-            //happens when string is shorter than last string, get trash left overs
-            //not really needed after clearning AdvData at start.
+            //memset(&buffer[0], 0, sizeof(buffer));      //clear out buffer
+            for (int i=0; i < total_chars_sensor; i++)
+            {
+                AdvData[JSON_loc] = sensor_char[i];
+                JSON_loc++;
+            } //JSON_loc left at location of next character
             
-            
-            //AdvData[JSON_loc] = 0x0;    //null terminate here
+                        
+            //AdvData[JSON_loc] = 0x0;    //since AdvData was cleared to start with, we don't need to null term
 
             ApplicationData_t appData;
             setupApplicationData(appData);
             
-            
+            /*********************
+             * start encrypting last 16 bytes of ADV_Data
+            *********************/
             for (int i=0; i<16; i++)
             {
                 src_buf[i] = AdvData[i+10]; //start of encrypted section is at AdvData[10]
             }
-
-            //nrf_ecb_set_key(key_buf);
             nrf_ecb_init();
             nrf_ecb_set_key(key_buf);
             bool successful_ecb = nrf_ecb_crypt(des_buf, src_buf);
-#if MyDebugEnb
-            device.printf("success ecb = %d \r\n", successful_ecb);
-            device.printf("src_buf: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \r\n", src_buf[0], src_buf[1], src_buf[2], src_buf[3], src_buf[4], src_buf[5], src_buf[6], src_buf[7], src_buf[8], src_buf[9], src_buf[10], src_buf[11], src_buf[12], src_buf[13], src_buf[14], src_buf[15]);
-            device.printf("des_buf: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \r\n", des_buf[0], des_buf[1], des_buf[2], des_buf[3], des_buf[4], des_buf[5], des_buf[6], des_buf[7], des_buf[8], des_buf[9], des_buf[10], des_buf[11], des_buf[12], des_buf[13], des_buf[14], des_buf[15]);
-#endif
-            for (int i=0; i<16; i++)
+            #if MyDebugEnb
+                device.printf("success ecb = %d \r\n", successful_ecb);
+                device.printf("src_buf: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \r\n", src_buf[0], src_buf[1], src_buf[2], src_buf[3], src_buf[4], src_buf[5], src_buf[6], src_buf[7], src_buf[8], src_buf[9], src_buf[10], src_buf[11], src_buf[12], src_buf[13], src_buf[14], src_buf[15]);
+                device.printf("des_buf: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \r\n", des_buf[0], des_buf[1], des_buf[2], des_buf[3], des_buf[4], des_buf[5], des_buf[6], des_buf[7], des_buf[8], des_buf[9], des_buf[10], des_buf[11], des_buf[12], des_buf[13], des_buf[14], des_buf[15]);
+            #endif
+            for (int i=0; i<16; i++)  //replace last 16 bytes with encrypted 16 bytes
             {
                 AdvData[i+10] = des_buf[i];
             }
             
+            //set payload for advertisement to our custom manufactured data.  First 5 bytes is BLE standard, last 26 bytes is our array
             //ble.gap().updateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *) &appData, sizeof(ApplicationData_t));
             ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, AdvData, sizeof(AdvData));
             
-            flag_update_io = false;
-            flag_periodic_call = false;
+            Flag_Update_IO = false;
+            Flag_Periodic_Call = false;
             
-            //GAP::AddressType_t *myType;
-            //GAP::Address_t myAddress
-            //ble_error_t getAddress(Gap::AddressType_t *typeP, Gap::Address_t address)
-            //ble.gap().getAddress(myType, myAddress);
-            //ble.gap().getAddress(Gap::AddressType_t *typeP, Gap::Address_t address);
-
-            
-
             ble.gap().startAdvertising();
-            tic_adv.attach(stop_adv_Callback, 2); /* trigger turn off advertisement after X seconds */
-
+            Tic_Stop_Adv.attach(stop_adv_Callback, 4); /* trigger turn off advertisement after X seconds */
         
-        }//end flag_update_io
+        }//end Flag_Update_IO
         
         
-        /*
-        if (flag_set_debounce_tic == true)
-        {
-            tic_debounce.attach();
-            //flag_set_debounce_tic = false;
-            
-        }
-        */
-        
-        //if (trigger_Detach_ADV_Tick == false)
-        //{  
-        //}
-        if (flag_detach_adv_tic == true)    //Stop Advertising
+        if (Flag_Detach_Adv_Tic == true)    //ticker callback flag to stop advertising
         {
             ble.gap().stopAdvertising();    //may be safer to execute BLE operations in main
-            tic_adv.detach();
-            flag_detach_adv_tic = false;
+            Tic_Stop_Adv.detach();
+            Flag_Detach_Adv_Tic = false;
         }
-        //device.printf("Input Voltage: %f\n\r",bat_reading);
+
         
-        ble.waitForEvent(); //sleeps until interrupt
-        
-
+        ble.waitForEvent(); //sleeps until interrupt form ticker or I/O
     }//end forever while
 }//end main