Mobile Life IoT project using the AT&T IoT Starter Kit Software and files for my device to monitor the status or our Airstream travel trailer RV. A full description of the project is at Hackster.IO here as part of the Realtime AT&T IoT Starter Kit Challenge: https://www.hackster.io/Anubus/mobile-life-iot-9c10be

Dependencies:   FXOS8700CQ MODSERIAL mbed

Files at this revision

API Documentation at this revision

Comitter:
Anubus
Date:
Sun Apr 02 12:28:21 2017 +0000
Commit message:
public version commit

Changed in this revision

FXOS8700CQ.lib Show annotated file Show diff for this revision Revisions of this file
HTS221.h Show annotated file Show diff for this revision Revisions of this file
MODSERIAL.lib Show annotated file Show diff for this revision Revisions of this file
cell_modem.cpp Show annotated file Show diff for this revision Revisions of this file
cell_modem.h Show annotated file Show diff for this revision Revisions of this file
config_me.h Show annotated file Show diff for this revision Revisions of this file
hardware.h Show annotated file Show diff for this revision Revisions of this file
hts221_driver.cpp Show annotated file Show diff for this revision Revisions of this file
itm_output.cpp Show annotated file Show diff for this revision Revisions of this file
itm_output.h 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
sensors.cpp Show annotated file Show diff for this revision Revisions of this file
sensors.h Show annotated file Show diff for this revision Revisions of this file
wnc_control.cpp Show annotated file Show diff for this revision Revisions of this file
wnc_control.h Show annotated file Show diff for this revision Revisions of this file
xadow_gps.cpp Show annotated file Show diff for this revision Revisions of this file
xadow_gps.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r bd276b1f1249 FXOS8700CQ.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FXOS8700CQ.lib	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/Anubus/code/FXOS8700CQ/#fb4cef1399b8
diff -r 000000000000 -r bd276b1f1249 HTS221.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTS221.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,108 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef HTS221_H_
+#define HTS221_H_
+
+class HTS221 {
+public:
+    HTS221(void);
+    int begin(void);
+    int activate(void);
+    int deactivate(void);
+
+    int bduActivate(void);
+    int bduDeactivate(void);
+
+    int readHumidity(void);
+    double readTemperature(void);
+private:
+    int storeCalibration(void);
+    unsigned char _h0_rH, _h1_rH;
+    unsigned int  _T0_degC, _T1_degC;
+    unsigned int  _H0_T0, _H1_T0;
+    unsigned int  _T0_OUT, _T1_OUT;
+    double _temperature;
+    int _humidity;
+    unsigned char _address;
+
+    unsigned char readRegister(unsigned char slaveAddress, unsigned char regToRead);
+    int writeRegister(unsigned char slaveAddress, unsigned char regToWrite, unsigned char dataToWrite);
+};
+
+#define HTS221_ADDRESS     0xBF
+
+//Define a few of the registers that we will be accessing on the HTS221
+#define WHO_AM_I           0x0F
+#define WHO_AM_I_RETURN    0xBC //This read-only register contains the device identifier, set to BCh
+
+#define AVERAGE_REG        0x10 // To configure humidity/temperature average.
+#define AVERAGE_DEFAULT    0x1B
+
+/*
+ * [7] PD: power down control
+ * (0: power-down mode; 1: active mode)
+ *
+ * [6:3] Reserved
+ *
+ * [2] BDU: block data update
+ * (0: continuous update; 1: output registers not updated until MSB and LSB reading)
+The BDU bit is used to inhibit the output register update between the reading of the upper
+and lower register parts. In default mode (BDU = ?0?), the lower and upper register parts are
+updated continuously. If it is not certain whether the read will be faster than output data rate,
+it is recommended to set the BDU bit to ?1?. In this way, after the reading of the lower (upper)
+register part, the content of that output register is not updated until the upper (lower) part is
+read also.
+ *
+ * [1:0] ODR1, ODR0: output data rate selection (see table 17)
+ */
+#define CTRL_REG1          0x20
+#define POWER_UP           0x80
+#define BDU_SET            0x4
+#define ODR0_SET           0x1   // setting sensor reading period 1Hz
+
+#define CTRL_REG2          0x21
+#define CTRL_REG3          0x22
+#define REG_DEFAULT        0x00
+
+#define STATUS_REG         0x27
+#define TEMPERATURE_READY  0x1
+#define HUMIDITY_READY     0x2
+
+#define HUMIDITY_L_REG     0x28
+#define HUMIDITY_H_REG     0x29
+#define TEMP_L_REG         0x2A
+#define TEMP_H_REG         0x2B
+/*
+ * calibration registry should be read for temperature and humidity calculation.
+ * Before the first calculation of temperature and humidity,
+ * the master reads out the calibration coefficients.
+ * will do at init phase
+ */
+#define CALIB_START        0x30
+#define CALIB_END          0x3F
+/*
+#define CALIB_T0_DEGC_X8   0x32
+#define CALIB_T1_DEGC_X8   0x33
+#define CALIB_T1_T0_MSB    0x35
+#define CALIB_T0_OUT_L     0x3C
+#define CALIB_T0_OUT_H     0x3D
+#define CALIB_T1_OUT_L     0x3E
+#define CALIB_T1_OUT_H     0x3F
+ */
+ 
+#endif
diff -r 000000000000 -r bd276b1f1249 MODSERIAL.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL.lib	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/stefanrousseau/code/MODSERIAL/#ae4c4f174d1f
diff -r 000000000000 -r bd276b1f1249 cell_modem.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cell_modem.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,350 @@
+/* ===================================================================
+Copyright c 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#include "mbed.h"
+#include <cctype>
+#include <string>
+
+#include "config_me.h"
+#include "wnc_control.h"
+#include "hardware.h"
+
+#define MDM_DBG_OFF                             0
+#define MDM_DBG_AT_CMDS                         (1 << 0)
+int mdm_dbgmask = MDM_DBG_OFF;
+
+#define WNC_WAIT_FOR_AT_CMD_MS 40
+
+DigitalOut  mdm_uart2_rx_boot_mode_sel(PTC17);  // on powerup, 0 = boot mode, 1 = normal boot
+DigitalOut  mdm_power_on(PTB9);                 // 0 = turn modem on, 1 = turn modem off (should be held high for >5 seconds to cycle modem)
+DigitalOut  mdm_wakeup_in(PTC2);                // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield
+
+DigitalOut  mdm_reset(PTC12);                   // active high      
+
+DigitalOut  shield_3v3_1v8_sig_trans_ena(PTC4); // 0 = disabled (all signals high impedence, 1 = translation active
+DigitalOut  mdm_uart1_cts(PTD0);
+
+#define TOUPPER(a) (a) //toupper(a)
+
+const char ok_str[] = "OK";
+const char error_str[] = "ERROR";
+
+#define MDM_OK                                  0
+#define MDM_ERR_TIMEOUT                         -1
+
+#define MAX_AT_RSP_LEN                          255
+
+ssize_t mdm_getline(char *buff, size_t size, int timeout_ms) {
+    int cin = -1;
+    int cin_last;
+    
+    if (NULL == buff || size == 0) {
+        return -1;
+    }
+
+    size_t len = 0;
+    Timer timer;
+    timer.start();
+    while ((len < (size-1)) && (timer.read_ms() < timeout_ms)) {
+        if (mdm.readable()) {
+            cin_last = cin;
+            cin = mdm.getc();
+            if (isprint(cin)) {
+                buff[len++] = (char)cin;
+                continue;
+            } else if (('\r' == cin_last) && ('\n' == cin)) {
+                break;
+            }
+        }
+//        wait_ms(1);
+    }
+    buff[len] = (char)NULL;
+    
+    return len;
+}
+
+int mdm_sendAtCmd(const char *cmd, const char **rsp_list, int timeout_ms) {
+    // Per WNC wait:
+    wait_ms(WNC_WAIT_FOR_AT_CMD_MS);
+
+    if (cmd && strlen(cmd) > 0) {
+        if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
+            PRINTF(MAG "ATCMD: " DEF "--> " GRN "%s" DEF "\n", cmd);
+        }
+        mdm.puts(cmd);
+        mdm.puts("\r\n");
+    }
+
+    if (rsp_list) {
+        Timer   timer;
+        char    rsp[MAX_AT_RSP_LEN+1];
+        int     len;
+        
+        timer.start();
+        while (timer.read_ms() < timeout_ms) {
+            len = mdm_getline(rsp, sizeof(rsp), timeout_ms - timer.read_ms());
+            
+            if (len < 0)
+                return MDM_ERR_TIMEOUT;
+
+            if (len == 0)
+                continue;
+                
+            if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
+                PRINTF(MAG "ATRSP: " DEF "<-- " CYN "%s" DEF "\n", rsp);
+            }
+        
+            if (rsp_list) {
+                int rsp_idx = 0;
+                while (rsp_list[rsp_idx]) {
+                    if (strcasecmp(rsp, rsp_list[rsp_idx]) == 0) {
+                        return rsp_idx;
+                    } else if (strncmp(rsp, "@EXTERR", 7) == 0){
+                        pc.printf("----- We got EXTERR ---\r\n");
+                        return 2;    
+                    } else if (strncmp(rsp, "+CME", 4) == 0){
+                        return 3;    
+                    } 
+                    rsp_idx++;
+                }
+            }
+        }
+        return MDM_ERR_TIMEOUT;
+    }
+    return MDM_OK;
+}
+
+int mdm_init(void) {
+    // Hard reset the modem (doesn't go through
+    // the signal level translator)
+    mdm_reset = 0;
+
+    // disable signal level translator (necessary
+    // for the modem to boot properly).  All signals
+    // except mdm_reset go through the level translator
+    // and have internal pull-up/down in the module. While
+    // the level translator is disabled, these pins will
+    // be in the correct state.  
+    shield_3v3_1v8_sig_trans_ena = 0;
+
+    // While the level translator is disabled and ouptut pins
+    // are tristated, make sure the inputs are in the same state
+    // as the WNC Module pins so that when the level translator is
+    // enabled, there are no differences.
+    mdm_uart2_rx_boot_mode_sel = 1;   // UART2_RX should be high
+    mdm_power_on = 0;                 // powr_on should be low
+    mdm_wakeup_in = 1;                // wake-up should be high
+    mdm_uart1_cts = 0;                // indicate that it is ok to send
+
+   // Now, wait for the WNC Module to perform its initial boot correctly
+    wait(1.0);
+  
+    // The WNC module initializes comms at 115200 8N1 so set it up
+     mdm.baud(115200);
+    
+    //Now, enable the level translator, the input pins should now be the
+    //same as how the M14A module is driving them with internal pull ups/downs.
+    //When enabled, there will be no changes in these 4 pins...
+    shield_3v3_1v8_sig_trans_ena = 1;
+
+    // Now, give the modem 60 seconds to start responding by
+    // sending simple 'AT' commands to modem once per second.
+    Timer timer;
+    timer.start();
+    while (timer.read() < 60) {
+        const char * rsp_lst[] = { ok_str, error_str, NULL };
+        int rc = mdm_sendAtCmd("AT", rsp_lst, 500);
+        if (rc == 0)
+            return true; //timer.read();
+        wait_ms(1000 - (timer.read_ms() % 1000));
+        PRINTF("\r%d",timer.read_ms()/1000);
+    }
+    return false;       
+}
+
+int mdm_sendAtCmdRsp(const char *cmd, const char **rsp_list, int timeout_ms, string * rsp, int * len) {
+    static char cmd_buf[3200];  // Need enough room for the WNC sockreads (over 3000 chars)
+    size_t n = strlen(cmd);
+
+    // Per WNC wait:
+    wait_ms(WNC_WAIT_FOR_AT_CMD_MS);
+
+    if (cmd && n > 0) {
+        if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
+            PRINTF(MAG "ATCMD: " DEF "--> " GRN "%s" DEF "\n", cmd);
+        }
+//        mdm.puts(cmd);
+//        mdm.puts("\r\n");
+        while (n--) {
+            mdm.putc(*cmd++);
+            wait_us(1000);
+        };
+        mdm.putc('\r');
+        wait_us(1000);
+        mdm.putc('\n');
+        wait_us(1000);
+    }
+
+    if (rsp_list) {
+        rsp->erase(); // Clean up from prior cmd response
+        *len = 0;
+        Timer   timer;
+        timer.start();
+        while (timer.read_ms() < timeout_ms) {
+            int lenCmd = mdm_getline(cmd_buf, sizeof(cmd_buf), timeout_ms - timer.read_ms());
+
+            if (lenCmd == 0)
+                continue;
+
+            if (lenCmd < 0)
+                return MDM_ERR_TIMEOUT;
+            else {
+                *len += lenCmd;
+                *rsp += cmd_buf;
+            }
+
+            if (mdm_dbgmask & MDM_DBG_AT_CMDS) {
+                PRINTF(MAG "ATRSP: " DEF "<-- " CYN "%s" DEF "\n", cmd_buf);
+            }
+
+            int rsp_idx = 0;
+            // TODO: Test if @EXTERR:<code>
+            while (rsp_list[rsp_idx]) {
+                if (strcasecmp(cmd_buf, rsp_list[rsp_idx]) == 0) {
+                    return rsp_idx;
+                } else if (strncmp(cmd_buf, "@EXTERR", 7) == 0){
+                    PRINTF("----- We got EXTERR ---\r\n");
+                    return 2;    
+                } else if (strncmp(cmd_buf, "+CME", 4) == 0){
+                    return 3;    
+                } 
+                rsp_idx++;
+            }
+        }
+        return MDM_ERR_TIMEOUT;
+    }
+
+    return MDM_OK;
+}
+
+void reinitialize_mdm(void)
+{
+    // Initialize the modem
+    PRINTF(GRN "Modem RE-initializing..." DEF "\r\n");
+    if (!mdm_init()) {
+        PRINTF(RED "\n\rModem RE-initialization failed!" DEF "\n");
+    }
+    PRINTF("\r\n");
+}
+// These are built on the fly
+string MyServerIpAddress;
+string MySocketData;
+
+//********************************************************************************************************************************************
+//* Process JSON response messages
+//********************************************************************************************************************************************
+bool extract_JSON(char* search_field, char* found_string)
+{
+    char* beginquote;
+    char* endquote;
+    beginquote = strchr(search_field, '{'); //start of JSON
+    endquote = strchr(search_field, '}'); //end of JSON
+    if (beginquote)
+    {
+        uint16_t ifoundlen;
+        if (endquote)
+        {
+            ifoundlen = (uint16_t) (endquote - beginquote) + 1;
+            strncpy(found_string, beginquote, ifoundlen );
+            found_string[ifoundlen] = 0; //null terminate
+            return true;
+        }
+        else
+        {
+            endquote = strchr(search_field, '\0'); //end of string...  sometimes the end bracket is missing
+            ifoundlen = (uint16_t) (endquote - beginquote) + 1;
+            strncpy(found_string, beginquote, ifoundlen );
+            found_string[ifoundlen] = 0; //null terminate
+            return false;
+        }
+    }
+    else
+    {
+        return false;
+    }
+} //extract_JSON
+
+int cell_modem_init() 
+{
+    int i;
+
+    pc.baud(115200);
+     // Initialize the modem
+    PRINTF(GRN "Modem initializing... will take up to 60 seconds" DEF "\r\n");
+    do {
+        i=mdm_init();
+        if (!i) {
+            PRINTF(RED "Modem initialization failed!" DEF "\n");
+        }
+    } while (!i);
+    
+    //Software init
+    software_init_mdm();
+ 
+    // Resolve URL to IP address to connect to
+    resolve_mdm();
+    // Open the socket (connect to the server)
+    sockopen_mdm();
+    return (0);
+}
+
+int cell_modem_Sendreceive(char* tx_string, char* rx_string) 
+{
+    int iStatus = 0; //error by default
+    PRINTF(DEF "\r\n");
+    PRINTF(BLU "Sending to modem : %s" DEF "\r\n", &tx_string[0]); 
+    sockwrite_mdm(&tx_string[0]);
+    if (sockread_mdm(&MySocketData, 1024, 20))
+    {
+        PRINTF(DEF "\r\n");
+        PRINTF(YEL "Read back : %s" DEF "\r\n", MySocketData.c_str());
+        char stringToCharBuf[BUF_SIZE_FOR_N_MAX_SOCKREAD*MAX_WNC_SOCKREAD_PAYLOAD+1]; // WNC can return max of 1500 (per sockread)
+        if ((MySocketData.length() + 1) < sizeof(stringToCharBuf))
+        {
+            strcpy(stringToCharBuf, MySocketData.c_str());
+            if (extract_JSON(stringToCharBuf, &rx_string[0]))
+            {
+                PRINTF(GRN "JSON : %s" DEF "\n", &rx_string[0]);
+                iStatus = 1; //all good
+            }
+        }
+        else
+        {
+            PRINTF(RED "BUFFER not big enough for sock data!" DEF "\r\n");
+        }
+    }
+    else
+    {
+        PRINTF(RED "No response..." DEF "\r\n");
+    }
+    return iStatus;
+}
+
+void display_wnc_firmware_rev(void)
+{
+    display_modem_firmware_version();
+}
\ No newline at end of file
diff -r 000000000000 -r bd276b1f1249 cell_modem.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cell_modem.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,23 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef __CELL_MODEM_H_
+#define __CELL_MODEM_H_
+int cell_modem_init();
+int cell_modem_Sendreceive(char* tx_string, char* rx_string);
+void display_wnc_firmware_rev(void);
+#endif
\ No newline at end of file
diff -r 000000000000 -r bd276b1f1249 config_me.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config_me.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,77 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+=======================================================
+Modified by Robert Bolling
+January 2017 
+for the Mobile Life IoT project
+  - refactored the sensor list defines to fit project
+=======================================================
+
+======================================================================== */
+
+
+#ifndef __CONFIG_ME_H_
+#define __CONFIG_ME_H_
+
+// User must set these for own context:
+
+#define BUF_SIZE_FOR_N_MAX_SOCKREAD (10)
+#define MAX_WNC_SOCKREAD_PAYLOAD (1500)
+
+// This is the server's base URL name.  Example "www.google.com"
+// Note that when you Fork a FLOW, it will typically assign  either
+// "run-east.att.io" or "run-west.att.io", so be sure to check this.
+static const char * MY_SERVER_URL       = "run-east.att.io";
+
+// These are FLOW fields from the Endpoints tab:
+#define FLOW_BASE_URL                   "/your_base_url_goes_here/in/flow"
+#define FLOW_INPUT_NAME                 "/status"
+
+// Unless you want to use a different protocol, this field should be left as is:
+#define FLOW_URL_TYPE                   " HTTP/1.1\r\nHost: "
+
+// This identifier specifies with which FLOW device you are communicating. 
+// If you only have one devive there then you can just leave this as is.
+// Once your FLOW device has been initialized (Virtual Device Initialize clicked),
+// the Virtual Device will show up in M2X.  This is its "DEVICE SERIAL" field
+#define FLOW_DEVICE_NAME                "mobilelife001"
+
+// This constant defines how often sensors are read and sent up to FLOW
+#define SENSOR_UPDATE_INTERVAL_MS       30000; //30 seconds
+
+// Specify here how many sensor parameters you want reported to FLOW.
+// You can use only the temperature and humidity from the shield HTS221
+// or you can add the reading of the FXO8700CQ motion sensor on the FRDM-K64F board
+// or if you have a SiLabs PMOD plugged into the shield, you can add its proximity sensor,
+// UV light, visible ambient light and infrared ambient light readings
+// If you run the Windows "Sensor Simulator" utility, 8 additional virtual
+// sensors can also be made available via USB.
+
+#define SHIELDTEMP_ACCELEROMETER_BATTERY                            1
+#define SHIELDTEMP_ACCELEROMETER_BATTERY_INTRUSION                  2
+#define SHIELDTEMP_ACCELEROMETER_BATTERY_GPS                        3
+#define SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP               4
+#define SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS           5
+#define SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS_INTRUSION 6
+static int iSensorsToReport = SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS_INTRUSION; //modify this to change your selection
+
+
+// This is the APN name for the cellular network, you will need to change this, check the instructions included with your SIM card kit:
+static const char * MY_APN_STR          = "m2m.com.attz";
+
+//This is for normal HTTP.  If you want to use TCP to a specific port, change that here:
+static const char * MY_PORT_STR         = "80";
+
+#endif
diff -r 000000000000 -r bd276b1f1249 hardware.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hardware.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,64 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef Hardware_H_
+#define Hardware_H_
+#include "MODSERIAL.h"
+
+extern I2C i2c;    //SDA, SCL -- define the I2C pins being used
+extern MODSERIAL pc; //UART to USB host
+extern MODSERIAL mdm; //UART to WNC modem
+//extern SerialBuffered mdm; //UART to WNC modem
+
+//Un-comment the definition below if you want to use the USB rx for another purpose.
+//otherwise the USB rx will be used to receive virtual sensor data from Avnet's
+//"Sensor Simulator Dashboard"  utility
+#define USE_VIRTUAL_SENSORS
+
+// comment out the following line if color is not supported on the terminal
+#define USE_COLOR
+#ifdef USE_COLOR
+ #define BLK "\033[30m"
+ #define RED "\033[31m"
+ #define GRN "\033[32m"
+ #define YEL "\033[33m"
+ #define BLU "\033[34m"
+ #define MAG "\033[35m"
+ #define CYN "\033[36m"
+ #define WHT "\033[37m"
+ #define DEF "\033[39m"
+#else
+ #define BLK
+ #define RED
+ #define GRN
+ #define YEL
+ #define BLU
+ #define MAG
+ #define CYN
+ #define WHT
+ #define DEF
+#endif
+
+#ifdef _ULINK_PRINT
+#include "itm_output.h"
+#else
+#define PRINTF pc.printf
+#define PUTS   pc.puts
+#endif
+
+
+#endif
diff -r 000000000000 -r bd276b1f1249 hts221_driver.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hts221_driver.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,266 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#include "HTS221.h"
+
+
+// ------------------------------------------------------------------------------
+//jmf  -- define I2C pins and functions to read & write to I2C device
+
+#include <string>
+#include "mbed.h"
+
+#include "hardware.h"
+//I2C i2c(PTC11, PTC10);    //SDA, SCL -- define the I2C pins being used. Defined in a 
+//common locatioin since sensors also use I2C
+
+// Read a single unsigned char from addressToRead and return it as a unsigned char
+unsigned char HTS221::readRegister(unsigned char slaveAddress, unsigned char ToRead)
+{
+    char data = ToRead;
+
+    //i2c.write(slaveAddress, &data, 1, 0);
+    i2c.write(slaveAddress, &data, 1, 1); //by Stefan
+    i2c.read(slaveAddress, &data, 1, 0);
+    return data;
+}
+
+// Writes a single unsigned char (dataToWrite) into regToWrite
+int HTS221::writeRegister(unsigned char slaveAddress, unsigned char regToWrite, unsigned char dataToWrite)
+{
+    const char data[] = {regToWrite, dataToWrite};
+
+    return i2c.write(slaveAddress,data,2,0);
+}
+
+
+//jmf end
+// ------------------------------------------------------------------------------
+
+//static inline int humidityReady(uint8_t data) {
+//    return (data & 0x02);
+//}
+//static inline int temperatureReady(uint8_t data) {
+//    return (data & 0x01);
+//}
+
+
+HTS221::HTS221(void) : _address(HTS221_ADDRESS)
+{
+    _temperature = 0;
+    _humidity = 0;
+}
+
+
+int HTS221::begin(void)
+{
+    uint8_t data;
+
+    data = readRegister(_address, WHO_AM_I);
+    if (data == WHO_AM_I_RETURN){
+        if (activate()){
+            storeCalibration();
+            return data;
+        }
+    }
+
+    return 0;
+}
+
+int
+HTS221::storeCalibration(void)
+{
+    uint8_t data;
+    uint16_t tmp;
+
+    for (int reg=CALIB_START; reg<=CALIB_END; reg++) {
+        if ((reg!=CALIB_START+8) && (reg!=CALIB_START+9) && (reg!=CALIB_START+4)) {
+
+            data = readRegister(HTS221_ADDRESS, reg);
+
+            switch (reg) {
+            case CALIB_START:
+                _h0_rH = data;
+                break;
+            case CALIB_START+1:
+            _h1_rH = data;
+            break;
+            case CALIB_START+2:
+            _T0_degC = data;
+            break;
+            case CALIB_START+3:
+            _T1_degC = data;
+            break;
+
+            case CALIB_START+5:
+            tmp = _T0_degC;
+            _T0_degC = (data&0x3)<<8;
+            _T0_degC |= tmp;
+
+            tmp = _T1_degC;
+            _T1_degC = ((data&0xC)>>2)<<8;
+            _T1_degC |= tmp;
+            break;
+            case CALIB_START+6:
+            _H0_T0 = data;
+            break;
+            case CALIB_START+7:
+            _H0_T0 |= data<<8;
+            break;
+            case CALIB_START+0xA:
+            _H1_T0 = data;
+            break;
+            case CALIB_START+0xB:
+            _H1_T0 |= data <<8;
+            break;
+            case CALIB_START+0xC:
+            _T0_OUT = data;
+            break;
+            case CALIB_START+0xD:
+            _T0_OUT |= data << 8;
+            break;
+            case CALIB_START+0xE:
+            _T1_OUT = data;
+            break;
+            case CALIB_START+0xF:
+            _T1_OUT |= data << 8;
+            break;
+
+
+            case CALIB_START+8:
+            case CALIB_START+9:
+            case CALIB_START+4:
+            //DO NOTHING
+            break;
+
+            // to cover any possible error
+            default:
+                return false;
+            } /* switch */
+        } /* if */
+    }  /* for */
+    return true;
+}
+
+
+int
+HTS221::activate(void)
+{
+    uint8_t data;
+
+    data = readRegister(_address, CTRL_REG1);
+    data |= POWER_UP;
+    data |= ODR0_SET;
+    writeRegister(_address, CTRL_REG1, data);
+
+    return true;
+}
+
+
+int HTS221::deactivate(void)
+{
+    uint8_t data;
+
+    data = readRegister(_address, CTRL_REG1);
+    data &= ~POWER_UP;
+    writeRegister(_address, CTRL_REG1, data);
+    return true;
+}
+
+
+int
+HTS221::bduActivate(void)
+{
+    uint8_t data;
+
+    data = readRegister(_address, CTRL_REG1);
+    data |= BDU_SET;
+    writeRegister(_address, CTRL_REG1, data);
+
+    return true;
+}
+
+
+int
+HTS221::bduDeactivate(void)
+{
+    uint8_t data;
+
+    data = readRegister(_address, CTRL_REG1);
+    data &= ~BDU_SET;
+    writeRegister(_address, CTRL_REG1, data);
+    return true;
+}
+
+
+int
+HTS221::readHumidity(void)
+{
+    uint8_t data   = 0;
+    uint16_t h_out = 0;
+    double h_temp  = 0.0;
+    double hum     = 0.0;
+
+    data = readRegister(_address, STATUS_REG);
+
+    if (data & HUMIDITY_READY) {
+        data = readRegister(_address, HUMIDITY_H_REG);
+        h_out = data << 8;  // MSB
+        data = readRegister(_address, HUMIDITY_L_REG);
+        h_out |= data;      // LSB
+
+        // Decode Humidity
+        hum = ((int16_t)(_h1_rH) - (int16_t)(_h0_rH))/2.0;  // remove x2 multiple
+
+        // Calculate humidity in decimal of grade centigrades i.e. 15.0 = 150.
+        h_temp = (((int16_t)h_out - (int16_t)_H0_T0) * hum) / ((int16_t)_H1_T0 - (int16_t)_H0_T0);
+        hum    = ((int16_t)_h0_rH) / 2.0; // remove x2 multiple
+        _humidity = (int16_t)((hum + h_temp)); // provide signed % measurement unit
+    }
+    return _humidity;
+}
+
+
+
+double
+HTS221::readTemperature(void)
+{
+    uint8_t data   = 0;
+    uint16_t t_out = 0;
+    double t_temp  = 0.0;
+    double deg     = 0.0;
+
+    data = readRegister(_address, STATUS_REG);
+
+    if (data & TEMPERATURE_READY) {
+
+        data= readRegister(_address, TEMP_H_REG);
+        t_out = data  << 8; // MSB
+        data = readRegister(_address, TEMP_L_REG);
+        t_out |= data;      // LSB
+
+        // Decode Temperature
+        deg    = ((int16_t)(_T1_degC) - (int16_t)(_T0_degC))/8.0; // remove x8 multiple
+
+        // Calculate Temperature in decimal of grade centigrades i.e. 15.0 = 150.
+        t_temp = (((int16_t)t_out - (int16_t)_T0_OUT) * deg) / ((int16_t)_T1_OUT - (int16_t)_T0_OUT);
+        deg    = ((int16_t)_T0_degC) / 8.0;     // remove x8 multiple
+        _temperature = deg + t_temp;   // provide signed celsius measurement unit
+    }
+
+    return _temperature;
+}
diff -r 000000000000 -r bd276b1f1249 itm_output.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/itm_output.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,91 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+//Used for ULINK output only
+//
+
+/* ITM registers */
+#define ITM_PORT0_U8          (*((volatile unsigned int  *)0xE0000000))
+#define ITM_PORT0_U32         (*((volatile unsigned long *)0xE0000000))
+#define ITM_TER               (*((volatile unsigned long *)0xE0000E00))
+#define ITM_TCR               (*((volatile unsigned long *)0xE0000E80))
+
+#define ITM_TCR_ITMENA_Msk    (1UL << 0)
+
+/*!< Value identifying \ref ITM_RxBuffer is ready for next character. */
+#define ITM_RXBUFFER_EMPTY    0x5AA55AA5
+
+/*!< Variable to receive characters. */
+extern
+volatile int ITM_RxBuffer;
+volatile int ITM_RxBuffer = ITM_RXBUFFER_EMPTY;
+
+/** \brief  ITM Send Character
+
+    The function transmits a character via the ITM channel 0, and
+    \li Just returns when no debugger is connected that has booked the output.
+    \li Is blocking when a debugger is connected, but the previous character
+        sent has not been transmitted.
+
+    \param [in]     ch  Character to transmit.
+
+    \returns            Character to transmit.
+ */
+int ITM_putc (int ch) {
+  if ((ITM_TCR & ITM_TCR_ITMENA_Msk) && /* ITM enabled */
+      (ITM_TER & (1UL << 0)        )) { /* ITM Port #0 enabled */
+    while (ITM_PORT0_U32 == 0);
+    ITM_PORT0_U8 = (int)ch;
+  }
+  return (ch);
+}
+
+/** \brief  ITM Receive Character
+
+    The function inputs a character via the external variable \ref ITM_RxBuffer.
+    This variable is monitored and altered by the debugger to provide input.
+
+    \return             Received character.
+    \return         -1  No character pending.
+ */
+int ITM_getc (void) {
+  int ch = -1;                      /* no character available */
+
+  if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) {
+    ch = ITM_RxBuffer;
+    ITM_RxBuffer = ITM_RXBUFFER_EMPTY;  /* ready for next character */
+  }
+
+  return (ch);
+}
+
+/** \brief  ITM send string
+
+    The function sends a null terminated string via the external variable \ref ITM_RxBuffer.
+    This variable is monitored and altered by the debugger to provide input.
+
+    \return             Received character.
+    \return         -1  No character pending.
+ */
+int ITM_puts (char * str) {
+  int i=0;
+
+  while(str[i])
+    ITM_putc(str[i++]);
+  return i;
+}
+
diff -r 000000000000 -r bd276b1f1249 itm_output.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/itm_output.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,31 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef __ITM_OUTPUT__
+#define __ITM_OUTPUT__
+
+//This file is only used when building for ULINK output
+
+#define PRINTF(format, ...)     { char xyz[80]; sprintf (xyz, format, ## __VA_ARGS__); ITM_puts(xyz);}
+#define PUTS(st)                                                        ITM_puts((char*)st);
+
+
+int ITM_putc (int ch);
+int ITM_getc (void);
+int ITM_puts ((char *) str);
+
+#endif
diff -r 000000000000 -r bd276b1f1249 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,271 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+=======================================================
+Modified by Robert Bolling
+January 2017 
+for the Mobile Life IoT project
+  - refactored to add new sensor lists from 
+    "config_me.h", and "sensors.cpp"
+=======================================================
+
+======================================================================== */
+
+#include "mbed.h" 
+#include <cctype>
+#include <string>
+#include "config_me.h"
+#include "sensors.h"
+#include "cell_modem.h"
+#include "hardware.h"
+
+I2C i2c(PTC11, PTC10);    //SDA, SCL -- define the I2C pins being used - I2C1
+MODSERIAL pc(USBTX, USBRX, 256, 256); // tx, rx with default tx, rx buffer sizes
+MODSERIAL mdm(PTD3, PTD2, 4096, 4096);
+DigitalOut led_green(LED_GREEN);
+DigitalOut led_red(LED_RED);
+DigitalOut led_blue(LED_BLUE);
+
+
+//********************************************************************************************************************************************
+//* Create string with sensor readings that can be sent to flow as an HTTP get
+//********************************************************************************************************************************************
+K64F_Sensors_t  SENSOR_DATA =
+{
+    .Temperature        = "0",
+    .Humidity           = "0",
+    .AccelX             = "0",
+    .AccelY             = "0",
+    .AccelZ             = "0",
+    .MagnetometerX      = "0",
+    .MagnetometerY      = "0",
+    .MagnetometerZ      = "0",
+    .Temperature_Si7020 = "0",
+    .Humidity_Si7020    = "0",
+    .GPS_Satellites     = "0",
+    .GPS_Latitude       = "0",
+    .GPS_Longitude      = "0",
+    .GPS_Altitude       = "0",
+    .GPS_Speed          = "0",
+    .GPS_Course         = "0",
+    .Battery_Voltage    = "0",
+    .Intrusion_Detected = "0"
+};
+
+void display_app_firmware_version(void)
+{
+    PUTS("\r\n\r\nApp Firmware: Release 1.0 - built: "__DATE__" "__TIME__"\r\n\r\n");
+}
+
+void GenerateModemString(char * modem_string)
+{
+    switch(iSensorsToReport)
+    {
+        case SHIELDTEMP_ACCELEROMETER_BATTERY:
+        {
+            sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, FLOW_URL_TYPE, MY_SERVER_URL);
+            break;
+        }
+        case SHIELDTEMP_ACCELEROMETER_BATTERY_INTRUSION:
+        {
+            sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&intrusion=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Intrusion_Detected, FLOW_URL_TYPE, MY_SERVER_URL);
+            break;
+        }
+        case SHIELDTEMP_ACCELEROMETER_BATTERY_GPS:
+        {
+            sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&gps_satellites=%s&latitude=%s&longitude=%s&altitude=%s&speed=%s&course=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.GPS_Satellites,SENSOR_DATA.GPS_Latitude,SENSOR_DATA.GPS_Longitude,SENSOR_DATA.GPS_Altitude,SENSOR_DATA.GPS_Speed,SENSOR_DATA.GPS_Course, FLOW_URL_TYPE, MY_SERVER_URL);
+            break;
+        }
+        case SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP:
+        {
+            sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&temp2=%s&humidity2=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Temperature_Si7020, SENSOR_DATA.Humidity_Si7020, FLOW_URL_TYPE, MY_SERVER_URL);
+            break;
+        }
+        case SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS:
+        {
+            sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&temp2=%s&humidity2=%s&gps_satellites=%s&latitude=%s&longitude=%s&altitude=%s&speed=%s&course=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Temperature_Si7020, SENSOR_DATA.Humidity_Si7020, SENSOR_DATA.GPS_Satellites,SENSOR_DATA.GPS_Latitude,SENSOR_DATA.GPS_Longitude,SENSOR_DATA.GPS_Altitude,SENSOR_DATA.GPS_Speed,SENSOR_DATA.GPS_Course, FLOW_URL_TYPE, MY_SERVER_URL);
+            break;
+        }
+        case SHIELDTEMP_ACCELEROMETER_BATTERY_EXTERNALTEMP_GPS_INTRUSION:
+        {
+            sprintf(modem_string, "GET %s%s?serial=%s&temp=%s&humidity=%s&accelX=%s&accelY=%s&accelZ=%s&batt_volt=%s&temp2=%s&humidity2=%s&gps_satellites=%s&latitude=%s&longitude=%s&altitude=%s&speed=%s&course=%s&intrusion=%s %s%s\r\n\r\n", FLOW_BASE_URL, FLOW_INPUT_NAME, FLOW_DEVICE_NAME, SENSOR_DATA.Temperature, SENSOR_DATA.Humidity, SENSOR_DATA.AccelX,SENSOR_DATA.AccelY, SENSOR_DATA.AccelZ, SENSOR_DATA.Battery_Voltage, SENSOR_DATA.Temperature_Si7020, SENSOR_DATA.Humidity_Si7020, SENSOR_DATA.GPS_Satellites,SENSOR_DATA.GPS_Latitude,SENSOR_DATA.GPS_Longitude,SENSOR_DATA.GPS_Altitude,SENSOR_DATA.GPS_Speed,SENSOR_DATA.GPS_Course, SENSOR_DATA.Intrusion_Detected, FLOW_URL_TYPE, MY_SERVER_URL);
+            break;
+        }
+        default:
+        {
+            sprintf(modem_string, "Invalid sensor selected\r\n\r\n");
+            break;
+        }
+    } //switch(iSensorsToReport)
+} //GenerateModemString        
+            
+            
+//Periodic timer
+Ticker OneMsTicker;
+volatile bool bTimerExpiredFlag = false;
+int OneMsTicks = 0;
+int iTimer1Interval_ms = 1000;
+//********************************************************************************************************************************************
+//* Periodic 1ms timer tick
+//********************************************************************************************************************************************
+void OneMsFunction() 
+{
+    OneMsTicks++;
+    if ((OneMsTicks % iTimer1Interval_ms) == 0)
+    {
+        bTimerExpiredFlag = true;
+    }            
+} //OneMsFunction()
+
+//********************************************************************************************************************************************
+//* Set the RGB LED's Color
+//* LED Color 0=Off to 7=White.  3 bits represent BGR (bit0=Red, bit1=Green, bit2=Blue) 
+//********************************************************************************************************************************************
+void SetLedColor(unsigned char ucColor)
+{
+    //Note that when an LED is on, you write a 0 to it:
+    led_red = !(ucColor & 0x1); //bit 0
+    led_green = !(ucColor & 0x2); //bit 1
+    led_blue = !(ucColor & 0x4); //bit 2
+} //SetLedColor()
+
+//********************************************************************************************************************************************
+//* Process the JSON response.  In this example we are only extracting a LED color. 
+//********************************************************************************************************************************************
+bool parse_JSON(char* json_string)
+{
+    char* beginquote;
+    char token[] = "\"LED\":\"";
+    beginquote = strstr(json_string, token );
+    if ((beginquote != 0))
+    {
+        char cLedColor = beginquote[strlen(token)];
+        PRINTF(GRN "LED Found : %c" DEF "\r\n", cLedColor);
+        switch(cLedColor)
+        {
+            case 'O':
+            { //Off
+                SetLedColor(0);
+                break;
+            }
+            case 'R':
+            { //Red
+                SetLedColor(1);
+                break;
+            }
+            case 'G':
+            { //Green
+                SetLedColor(2);
+                break;
+            }
+            case 'Y':
+            { //Yellow
+                SetLedColor(3);
+                break;
+            }
+            case 'B':
+            { //Blue
+                SetLedColor(4);
+                break;
+            }
+            case 'M':
+            { //Magenta
+                SetLedColor(5);
+                break;
+            }
+            case 'T':
+            { //Turquoise
+                SetLedColor(6);
+                break;
+            }
+            case 'W':
+            { //White
+                SetLedColor(7);
+                break;
+            }
+            default:
+            {
+                break;
+            }
+        } //switch(cLedColor)
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+} //parse_JSON
+
+int main() {
+    static unsigned ledOnce = 0;
+    //delay so that the debug terminal can open after power-on reset:
+    wait (5.0);
+    pc.baud(115200);
+    
+    display_app_firmware_version();
+    
+    PRINTF(GRN "Hello World from the Cellular IoT Kit!\r\n\r\n");
+
+    //Initialize the I2C sensors that are present
+    sensors_init();
+    read_sensors();
+
+    // Set LED to RED until init finishes
+    SetLedColor(0x1); //Red
+    // Initialize the modem
+    PRINTF("\r\n");
+    
+//TODO: comment out these next two lines for local testing (no modem send) to keep from initializing the modem
+    cell_modem_init();
+    display_wnc_firmware_rev();
+
+    // Set LED BLUE for partial init
+    SetLedColor(0x4); //Blue
+
+    //Create a 1ms timer tick function:
+    iTimer1Interval_ms = SENSOR_UPDATE_INTERVAL_MS;
+    OneMsTicker.attach(OneMsFunction, 0.001f) ;
+
+    // Send and receive data perpetually
+    while(1) {
+        if  (bTimerExpiredFlag)
+        {
+            bTimerExpiredFlag = false;
+            PRINTF("Sensor readings... \n\r");
+            read_sensors(); //read available external sensors from external and on-board temp and motion sensors
+            PRINTF("...end sensor readings \n\r\n\r");
+
+            
+          
+            char modem_string[512];
+            GenerateModemString(&modem_string[0]);
+            PRINTF(modem_string);   //TODO: check what is being sent
+// TODO: comment out to the next "TODO" for local testing to keep from sendng to modem
+            char myJsonResponse[512];
+            if (cell_modem_Sendreceive(&modem_string[0], &myJsonResponse[0]))
+            {
+                if (!ledOnce)
+                {
+                    ledOnce = 1;
+                    SetLedColor(0x2); //Green
+                }
+                parse_JSON(&myJsonResponse[0]);
+            }
+// TODO: end testing comment out section
+
+
+        } //bTimerExpiredFlag
+    } //forever loop
+}
diff -r 000000000000 -r bd276b1f1249 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/f9eeca106725
\ No newline at end of file
diff -r 000000000000 -r bd276b1f1249 sensors.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,419 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+=======================================================
+Modified by Robert Bolling
+January 2017 
+for the Mobile Life IoT project
+  - refactored Si7020 to Si7021 sensor
+  - added voltage and intrusion sensor
+  - some other clean up including removing unused code
+    for virtual sensors and the Si1145
+=======================================================
+
+======================================================================== */
+
+#include "mbed.h"
+#include "sensors.h"
+#include "hardware.h"
+#include "config_me.h"
+#include "FXOS8700CQ.h"
+#include "HTS221.h"
+#include "xadow_gps.h"
+#include <string>
+
+#define Si7020_PMOD_I2C_ADDR   0x80 //this is for 7-bit I2C addr 0x4 for the Si7021 external sensor
+
+// Storage for the data from the motion sensor
+SRAWDATA accel_data;
+SRAWDATA magn_data;
+//InterruptIn fxos_int1(PTC6); // unused, common with SW2 on FRDM-K64F
+InterruptIn fxos_int2(PTC13); // should just be the Data-Ready interrupt
+
+bool fxos_int2_triggered = false;
+void trigger_fxos_int2(void)
+{
+    fxos_int2_triggered = true;
+
+}
+
+#define VOLTS_SCALE 18.6 //scale battery voltage measurement based on R1 and R2
+AnalogIn Analog0(PTC0); //  Had to use J1-11 for PTC0 to deconflict from wnc shield pins
+
+
+/*------------------------------------------------------------------------------
+ * Perform I2C single read.
+ *------------------------------------------------------------------------------*/
+unsigned char I2C_ReadSingleByte(unsigned char ucDeviceAddress)
+{
+    char rxbuffer [1];
+    i2c.read(ucDeviceAddress, rxbuffer, 1 );
+    return (unsigned char)rxbuffer[0];
+} //I2C_ReadSingleByte()
+
+/*------------------------------------------------------------------------------
+ * Perform I2C single read from address.
+ *------------------------------------------------------------------------------*/
+unsigned char I2C_ReadSingleByteFromAddr(unsigned char ucDeviceAddress, unsigned char Addr)
+{
+    char txbuffer [1];
+    char rxbuffer [1];
+    txbuffer[0] = (char)Addr;
+    i2c.write(ucDeviceAddress, txbuffer, 1 );
+    i2c.read(ucDeviceAddress, rxbuffer, 1 );
+    return (unsigned char)rxbuffer[0];
+} //I2C_ReadSingleByteFromAddr()
+
+/*------------------------------------------------------------------------------
+ * Perform I2C read of more than 1 byte.
+ *------------------------------------------------------------------------------*/
+int I2C_ReadMultipleBytes(unsigned char ucDeviceAddress, char *ucData, unsigned char ucLength)
+{
+    int status;
+    status = i2c.read(ucDeviceAddress, ucData, ucLength);
+    return status;
+} //I2C_ReadMultipleBytes()
+
+/*------------------------------------------------------------------------------
+ * Perform I2C write of a single byte.
+ *------------------------------------------------------------------------------*/
+int I2C_WriteSingleByte(unsigned char ucDeviceAddress, unsigned char Data, bool bSendStop)
+{
+    int status;
+    char txbuffer [1];
+    txbuffer[0] = (char)Data; //data
+    status = i2c.write(ucDeviceAddress, txbuffer, 1, !bSendStop); //true: do not send stop
+    return status;
+} //I2C_WriteSingleByte()
+
+/*------------------------------------------------------------------------------
+ * Perform I2C write of 1 byte to an address.
+ *------------------------------------------------------------------------------*/
+int I2C_WriteSingleByteToAddr(unsigned char ucDeviceAddress, unsigned char Addr, unsigned char Data, bool bSendStop)
+{
+    int status;
+    char txbuffer [2];
+    txbuffer[0] = (char)Addr; //address
+    txbuffer[1] = (char)Data; //data
+    //status = i2c.write(ucDeviceAddress, txbuffer, 2, false); //stop at end
+    status = i2c.write(ucDeviceAddress, txbuffer, 2, !bSendStop); //true: do not send stop
+    return status;
+} //I2C_WriteSingleByteToAddr()
+
+/*------------------------------------------------------------------------------
+ * Perform I2C write of more than 1 byte.
+ *------------------------------------------------------------------------------*/
+int I2C_WriteMultipleBytes(unsigned char ucDeviceAddress, char *ucData, unsigned char ucLength, bool bSendStop)
+{
+    int status;
+    status = i2c.write(ucDeviceAddress, ucData, ucLength, !bSendStop); //true: do not send stop
+    return status;
+} //I2C_WriteMultipleBytes()
+
+//********************************************************************************************************************************************
+//* Battery Voltage
+//********************************************************************************************************************************************
+
+void Read_Battery_Volts(void)
+{
+        float Volts;
+        Volts = Analog0 * VOLTS_SCALE;
+        PRINTF("Voltage: %0.3f Volts \r\n", Volts); 
+        sprintf(SENSOR_DATA.Battery_Voltage, "%0.2f", Volts);
+}
+
+//********************************************************************************************************************************************
+//* Si7020/Si7021 temperature & humidity sensor
+//********************************************************************************************************************************************
+
+bool bSi7020_present = false;
+void Init_Si7020(void)
+{
+    char SN_7020 [8];
+    //SN part 1:
+    I2C_WriteSingleByteToAddr(Si7020_PMOD_I2C_ADDR, 0xFA, 0x0F, false);
+    I2C_ReadMultipleBytes(Si7020_PMOD_I2C_ADDR, &SN_7020[0], 4);
+
+    //SN part 1:
+    I2C_WriteSingleByteToAddr(Si7020_PMOD_I2C_ADDR, 0xFC, 0xC9, false);
+    I2C_ReadMultipleBytes(Si7020_PMOD_I2C_ADDR, &SN_7020[4], 4);
+
+    char Ver_7020 [2];
+    //FW version:
+    I2C_WriteSingleByteToAddr(Si7020_PMOD_I2C_ADDR, 0x84, 0xB8, false);
+    I2C_ReadMultipleBytes(Si7020_PMOD_I2C_ADDR, &Ver_7020[0], 2);
+
+    if (SN_7020[4] != 0x15)  //Si7021 this is 0x15, for Si7020 this is 0x14
+    {
+        bSi7020_present = false;
+        PRINTF("Si7020 sensor not found. SN=0x%02X Si7020addr=0x%02X \r\n", SN_7020[4], Si7020_PMOD_I2C_ADDR  );  //TODO: take out SN print
+    }
+    else 
+    {
+        bSi7020_present = true;
+        PRINTF("Si7020 SN = 0x%02X%02X%02X%02X%02X%02X%02X%02X \r\n", SN_7020[0], SN_7020[1], SN_7020[2], SN_7020[3], SN_7020[4], SN_7020[5], SN_7020[6], SN_7020[7]);
+        PRINTF("Si7020 Version# = 0x%02X \r\n", Ver_7020[0]);
+    } //bool bSi7020_present = true
+
+} //Init_Si7020()
+
+void Read_Si7020(void)
+{
+    if (bSi7020_present)
+    {   
+        char Humidity [2];
+        char Temperature [2];
+        //Command to measure humidity (temperature also gets measured):
+        I2C_WriteSingleByte(Si7020_PMOD_I2C_ADDR, 0xF5, false); //no hold, must do dummy read
+        I2C_ReadMultipleBytes(Si7020_PMOD_I2C_ADDR, &Humidity[0], 1); //dummy read, should get an nack until it is done
+        wait (0.05); //wait for measurement.  Can also keep reading until no NACK is received
+        //I2C_WriteSingleByte(Si7020_PMOD_I2C_ADDR, 0xE5, false); //Hold mod, the device does a clock stretch on the read until it is done (crashes the I2C bus...
+        I2C_ReadMultipleBytes(Si7020_PMOD_I2C_ADDR, &Humidity[0], 2); //read humidity
+        //PRINTF("Read Si7020 Humidity = 0x%02X%02X\n", Humidity[0], Humidity[1]);
+        int rh_code = (Humidity[0] << 8) + Humidity[1];
+        float fRh = (125.0*rh_code/65536.0) - 6.0; //from datasheet
+        PRINTF("Si7020 Humidity = %0.1f %% \r\n", fRh); //double % sign for escape //PRINTF("%*.*f\n", myFieldWidth, myPrecision, myFloatValue);
+        sprintf(SENSOR_DATA.Humidity_Si7020, "%0.1f", fRh);
+        
+        //Command to read temperature when humidity is already done:
+        I2C_WriteSingleByte(Si7020_PMOD_I2C_ADDR, 0xE0, false);
+        I2C_ReadMultipleBytes(Si7020_PMOD_I2C_ADDR, &Temperature[0], 2); //read temperature
+        //PRINTF("Read Si7020 Temperature = 0x%02X%02X\n", Temperature[0], Temperature[1]);
+        int temp_code = (Temperature[0] << 8) + Temperature[1];
+        float fTemp = (175.72*temp_code/65536.0) - 46.85; //from datasheet in Celcius
+        PRINTF("Si7020 Temperature = %0.1f deg F \r\n", CTOF(fTemp));
+        sprintf(SENSOR_DATA.Temperature_Si7020, "%0.1f", CTOF(fTemp));
+    } //bool bSi7020_present = true
+
+} //Read_Si7020()
+
+
+//********************************************************************************************************************************************
+//* Read the FXOS8700CQ - 6-axis combo Sensor Accelerometer and Magnetometer
+//********************************************************************************************************************************************
+bool bMotionSensor_present = false;
+void Init_motion_sensor()
+{
+    // Note: this class is instantiated here because if it is statically declared, the cellular shield init kills the I2C bus...
+    // Class instantiation with pin names for the motion sensor on the FRDM-K64F board:
+    FXOS8700CQ fxos(PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1); // SDA, SCL, (addr << 1)
+    int iWhoAmI = fxos.get_whoami();
+
+    PRINTF("FXOS8700CQ WhoAmI = %X\r\n", iWhoAmI);
+    // Iterrupt for active-low interrupt line from FXOS
+    // Configured with only one interrupt on INT2 signaling Data-Ready
+    //fxos_int2.fall(&trigger_fxos_int2);
+    if (iWhoAmI != 0xC7)
+    {
+        bMotionSensor_present = false;
+        PRINTF("FXOS8700CQ motion sensor not found\r\n");
+    }
+    else
+    {
+        bMotionSensor_present = true;
+        fxos.enable();
+    }
+} //Init_motion_sensor()
+
+void Read_motion_sensor()
+{
+    // Note: this class is instantiated here because if it is statically declared, the cellular shield init kills the I2C bus...
+    // Class instantiation with pin names for the motion sensor on the FRDM-K64F board:
+    FXOS8700CQ fxos(PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1); // SDA, SCL, (addr << 1)
+    if (bMotionSensor_present)
+    {
+        fxos.enable();
+        fxos.get_data(&accel_data, &magn_data);
+        //PRINTF("Roll=%5d, Pitch=%5d, Yaw=%5d;\r\n", magn_data.x, magn_data.y, magn_data.z);
+        sprintf(SENSOR_DATA.MagnetometerX, "%5d", magn_data.x);
+        sprintf(SENSOR_DATA.MagnetometerY, "%5d", magn_data.y);
+        sprintf(SENSOR_DATA.MagnetometerZ, "%5d", magn_data.z);
+    
+        //Try to normalize (/2048) the values so they will match the eCompass output:
+        float fAccelScaled_x, fAccelScaled_y, fAccelScaled_z;
+        fAccelScaled_x = (accel_data.x/2048.0);
+        fAccelScaled_y = (accel_data.y/2048.0);
+        fAccelScaled_z = (accel_data.z/2048.0);
+        PRINTF("Acc: X=%2.3f Y=%2.3f Z=%2.3f;\r\n", fAccelScaled_x, fAccelScaled_y, fAccelScaled_z);
+        sprintf(SENSOR_DATA.AccelX, "%2.3f", fAccelScaled_x);
+        sprintf(SENSOR_DATA.AccelY, "%2.3f", fAccelScaled_y);
+        sprintf(SENSOR_DATA.AccelZ, "%2.3f", fAccelScaled_z);
+    } //bMotionSensor_present
+} //Read_motion_sensor()
+
+
+//********************************************************************************************************************************************
+//* Read the HTS221 temperature & humidity sensor on the Cellular Shield
+//********************************************************************************************************************************************
+// These are to be built on the fly
+string my_temp;
+string my_humidity;
+HTS221 hts221;
+
+//#define CTOF(x)  ((x)*1.8+32)
+bool bHTS221_present = false;
+void Init_HTS221()
+{
+    int i;
+    void hts221_init(void);
+    i = hts221.begin();
+    if (i)
+    {
+        bHTS221_present = true;
+        PRINTF(BLU "HTS221 Detected (0x%02X)\n\r",i);
+        PRINTF("  Temp  is: %0.2f F \n\r",CTOF(hts221.readTemperature()));
+        PRINTF("  Humid is: %02d %%\n\r",hts221.readHumidity());
+    }
+    else
+    {
+        bHTS221_present = false;
+        PRINTF(RED "HTS221 NOT DETECTED!\n\r");
+    }
+} //Init_HTS221()
+
+void Read_HTS221()
+{
+    if (bHTS221_present)
+    {
+        sprintf(SENSOR_DATA.Temperature, "%0.1f", CTOF(hts221.readTemperature()));
+        PRINTF("HTS221 Temp  is: %0.1f F \n\r",CTOF(hts221.readTemperature()));
+        sprintf(SENSOR_DATA.Humidity, "%02d", hts221.readHumidity());
+        PRINTF("HTS221 Humid is: %02d %%\n\r",hts221.readHumidity());     
+        
+    } //bHTS221_present
+} //Read_HTS221()
+
+//********************************************************************************************************************************************
+//* Read the xadow gps module connedted to i2c1
+//********************************************************************************************************************************************
+
+bool bGPS_present = false;
+void Init_GPS(void)
+{
+    char scan_id[GPS_SCAN_SIZE+2]; //The first two bytes are the response length (0x00, 0x04)
+    I2C_WriteSingleByte(GPS_DEVICE_ADDR, GPS_SCAN_ID, true); //no hold, must do read
+
+    unsigned char i;
+    for(i=0;i<(GPS_SCAN_SIZE+2);i++)
+    {
+        scan_id[i] = I2C_ReadSingleByte(GPS_DEVICE_ADDR);
+    }
+
+    if(scan_id[5] != GPS_DEVICE_ID)
+    {
+        bGPS_present = false;
+        PRINTF("Xadow GPS not found \r\n");
+    }
+    else 
+    {
+        bGPS_present = true;
+        PRINTF("Xadow GPS Scan ID response = 0x%02X%02X (length), 0x%02X%02X%02X%02X\r\n", scan_id[0], scan_id[1], scan_id[2], scan_id[3], scan_id[4], scan_id[5]);
+        char status = gps_get_status();
+        
+         
+ /*  rather not wait for valid GPS before reporting sensors       
+        if ((status != 'A') && (iSensorsToReport == TEMP_HUMIDITY_ACCELEROMETER_GPS))
+          { //we must wait for GPS to initialize
+              PRINTF("Waiting for GPS to become ready... ");
+              while (status != 'A')
+              {
+                  wait (5.0);        
+                  status = gps_get_status();
+                  unsigned char num_satellites = gps_get_sate_in_veiw();
+                  PRINTF("%c%d", status, num_satellites);
+              }
+              PRINTF("\r\n");
+          } //we must wait for GPS to initialize
+ */
+ 
+        PRINTF("gps_check_online is %d\r\n", gps_check_online());
+        unsigned char *data;
+        data = gps_get_utc_date_time();       
+        PRINTF("gps_get_utc_date_time : %d-%d-%d,%d:%d:%d\r\n", data[0], data[1], data[2], data[3], data[4], data[5]); 
+        PRINTF("gps_get_status        : %c ('A' = Valid, 'V' = Invalid)\r\n", gps_get_status());
+        PRINTF("gps_get_latitude      : %c:%f\r\n", gps_get_ns(), gps_get_latitude());
+        PRINTF("gps_get_longitude     : %c:%f\r\n", gps_get_ew(), gps_get_longitude());
+        PRINTF("gps_get_altitude      : %f meters\r\n", gps_get_altitude());
+        PRINTF("gps_get_speed         : %f knots\r\n", gps_get_speed());
+        PRINTF("gps_get_course        : %f degrees\r\n", gps_get_course());
+        PRINTF("gps_get_position_fix  : %c\r\n", gps_get_position_fix());
+        PRINTF("gps_get_sate_in_view  : %d satellites\r\n", gps_get_sate_in_veiw());
+        PRINTF("gps_get_sate_used     : %d\r\n", gps_get_sate_used());
+        PRINTF("gps_get_mode          : %c ('A' = Automatic, 'M' = Manual)\r\n", gps_get_mode());
+        PRINTF("gps_get_mode2         : %c ('1' = no fix, '1' = 2D fix, '3' = 3D fix)\r\n", gps_get_mode2()); 
+    } //bool bGPS_present = true
+} //Init_GPS()
+
+void Read_GPS()
+{
+    unsigned char gps_satellites = 0; //default
+    int lat_sign;
+    int long_sign;
+    if (bGPS_present)
+    {
+        if ((gps_get_status() == 'A') && (gps_get_mode2() != '1'))
+        {
+            gps_satellites = gps_get_sate_in_veiw(); //show the number of satellites
+        }
+        if (gps_get_ns() == 'S')
+        {
+            lat_sign = -1; //negative number
+        }
+        else
+        {
+            lat_sign = 1;
+        }    
+        if (gps_get_ew() == 'W')
+        {
+            long_sign = -1; //negative number
+        }
+        else
+        {
+            long_sign = 1;
+        }    
+#if (1)
+        PRINTF("gps_satellites        : %d\r\n", gps_satellites);
+        PRINTF("gps_get_latitude      : %f\r\n", (lat_sign * gps_get_latitude()));
+        PRINTF("gps_get_longitude     : %f\r\n", (long_sign * gps_get_longitude()));
+        PRINTF("gps_get_altitude      : %f meters\r\n", gps_get_altitude());
+        PRINTF("gps_get_speed         : %f knots\r\n", gps_get_speed());
+        PRINTF("gps_get_course        : %f degrees\r\n", gps_get_course());
+#endif
+        sprintf(SENSOR_DATA.GPS_Satellites, "%d", gps_satellites);
+        sprintf(SENSOR_DATA.GPS_Latitude, "%f", (lat_sign * gps_get_latitude()));
+        sprintf(SENSOR_DATA.GPS_Longitude, "%f", (long_sign * gps_get_longitude()));
+        sprintf(SENSOR_DATA.GPS_Altitude, "%f", gps_get_altitude());
+        sprintf(SENSOR_DATA.GPS_Speed, "%f", gps_get_speed());
+        sprintf(SENSOR_DATA.GPS_Course, "%f", gps_get_course());
+    } //bGPS_present
+} //Read_GPS()
+
+ 
+void sensors_init(void)
+{
+    Init_HTS221();
+    Init_Si7020();
+    Init_motion_sensor();
+    Init_GPS();
+} //sensors_init
+
+void read_sensors(void)
+{
+    Read_Battery_Volts();
+    Read_HTS221();
+    Read_Si7020();
+    Read_motion_sensor();
+    Read_GPS();
+} //read_sensors
diff -r 000000000000 -r bd276b1f1249 sensors.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,51 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef __SENSORS_H_
+#define __SENSORS_H_
+
+void sensors_init(void);
+void read_sensors(void);
+
+#define CTOF(x)  ((x)*1.8+32)
+
+#define SENSOR_FIELD_LEN_LIMIT  32
+typedef struct
+{
+    char  Temperature[SENSOR_FIELD_LEN_LIMIT];
+    char  Humidity[SENSOR_FIELD_LEN_LIMIT];
+    char  AccelX[SENSOR_FIELD_LEN_LIMIT];
+    char  AccelY[SENSOR_FIELD_LEN_LIMIT];
+    char  AccelZ[SENSOR_FIELD_LEN_LIMIT];
+    char  MagnetometerX[SENSOR_FIELD_LEN_LIMIT];
+    char  MagnetometerY[SENSOR_FIELD_LEN_LIMIT];
+    char  MagnetometerZ[SENSOR_FIELD_LEN_LIMIT];
+    char  Temperature_Si7020[SENSOR_FIELD_LEN_LIMIT];
+    char  Humidity_Si7020[SENSOR_FIELD_LEN_LIMIT];
+    char  GPS_Satellites[SENSOR_FIELD_LEN_LIMIT];
+    char  GPS_Latitude[SENSOR_FIELD_LEN_LIMIT];
+    char  GPS_Longitude[SENSOR_FIELD_LEN_LIMIT];
+    char  GPS_Altitude[SENSOR_FIELD_LEN_LIMIT];
+    char  GPS_Speed[SENSOR_FIELD_LEN_LIMIT];
+    char  GPS_Course[SENSOR_FIELD_LEN_LIMIT];
+    char  Battery_Voltage [SENSOR_FIELD_LEN_LIMIT];
+    char  Intrusion_Detected [SENSOR_FIELD_LEN_LIMIT];
+} K64F_Sensors_t ;
+
+extern K64F_Sensors_t  SENSOR_DATA;
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r bd276b1f1249 wnc_control.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wnc_control.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,683 @@
+/* ===================================================================
+Copyright c 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#include "mbed.h"
+#include <cctype>
+#include <string>
+#include "config_me.h"
+#include "wnc_control.h"
+#include "hardware.h"
+
+// Outputs detailed WNC command info
+#define WNC_CMD_DEBUG_ON
+
+// Full debug output, longer cmds and extra cellular status checking
+#undef WNC_CMD_DEBUG_ON_VERBOSE
+
+extern string MyServerIpAddress;
+extern string MySocketData;
+
+int reinitialize_mdm(void);
+
+enum WNC_ERR_e {
+    WNC_OK =0,
+    WNC_CMD_ERR = -1,
+    WNC_NO_RESPONSE = -2,
+    WNC_CELL_LINK_DOWN = -3,
+    WNC_EXTERR = -4
+};
+
+// Contains result of last call to send_wnc_cmd(..)
+WNC_ERR_e WNC_MDM_ERR = WNC_OK;
+
+// Contains the RAW WNC UART responses
+static string wncStr;
+static int socketOpen = 0;
+
+void software_init_mdm(void)
+{
+ // Temp put here to fix new boards needing init,
+ //  the check for on the cellular network was preventing the PDNSET from happening!!!!
+ {  
+    PUTS("SET APN STRING!\r\n");
+    string * pRespStr;
+    string cmd_str("AT%PDNSET=1,");
+    cmd_str += MY_APN_STR;
+    cmd_str += ",IP";
+    at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, 4*WNC_TIMEOUT_MS); // Set APN, cmd seems to take a little longer sometimes
+ }   
+
+  static bool reportStatus = true;
+  do
+  {
+      PUTS("------------ software_init_mdm! --------->\r\n");
+      if (check_wnc_ready() == 0)
+      {
+          if (reportStatus == false)
+          {
+              PUTS("Re-connected to cellular network!\n\r");
+              reportStatus = true;
+          }
+    
+          // WNC has SIM and registered on network
+          do
+          {
+              WNC_MDM_ERR = WNC_OK;
+              at_init_wnc();
+              if (WNC_MDM_ERR == WNC_NO_RESPONSE)
+              {
+                  reinitialize_mdm();
+                  at_init_wnc(true);  // Hard reset occurred so make it go through the software init();
+              }
+          } while (WNC_MDM_ERR != WNC_OK);
+      }
+      else
+      {
+          if (reportStatus == true)
+          {
+               PUTS("Not connected to cellular network!\n\r");
+               reportStatus = false;
+          }
+     // Atempt to re-register
+//     string * pRespStr;
+//     PUTS("Force re-register!\r\n");
+//     at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, WNC_TIMEOUT_MS);
+//     wait_ms(31000);
+//     at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, WNC_TIMEOUT_MS);
+//     wait_ms(31000);
+          WNC_MDM_ERR = WNC_CELL_LINK_DOWN;
+      }
+  } while (WNC_MDM_ERR != WNC_OK);
+}
+
+void display_modem_firmware_version(void)
+{
+    string * pRespStr;
+
+    PUTS("<-------- WNC Firmware Revision --------\r\n");
+    at_send_wnc_cmd("ATI", &pRespStr, WNC_TIMEOUT_MS);
+    PUTS(pRespStr->c_str());
+    PUTS("\r\n");    
+    PUTS("--------------------------------------->\r\n");
+}
+
+void resolve_mdm(void)
+{
+    do
+    {
+      WNC_MDM_ERR = WNC_OK;
+      at_dnsresolve_wnc(MY_SERVER_URL, &MyServerIpAddress);
+      if (WNC_MDM_ERR == WNC_NO_RESPONSE)
+      {
+        software_init_mdm();
+      }
+      else if (WNC_MDM_ERR == WNC_CMD_ERR)
+      {
+        PUTS("Bad URL!!!!!!\r\n");
+      }
+    } while (WNC_MDM_ERR != WNC_OK);
+    
+    PRINTF("My Server IP: %s\r\n", MyServerIpAddress.c_str());
+}
+
+void sockopen_mdm(void)
+{
+    do
+    {
+      WNC_MDM_ERR = WNC_OK;
+      at_sockopen_wnc(MyServerIpAddress, MY_PORT_STR);
+      if (WNC_MDM_ERR == WNC_NO_RESPONSE)
+      {
+        software_init_mdm();
+      }
+      else if (WNC_MDM_ERR == WNC_CMD_ERR)
+        PUTS("Socket open fail!!!!\r\n");
+      else
+        socketOpen = 1;
+    } while (WNC_MDM_ERR != WNC_OK);
+}
+
+void sockwrite_mdm(const char * s)
+{
+    if (socketOpen == 1)
+    {
+    do
+    {
+      WNC_MDM_ERR = WNC_OK;
+      at_sockwrite_wnc(s);
+      if (WNC_MDM_ERR == WNC_NO_RESPONSE)
+      {
+        PUTS("Sock write no response!\r\n");
+        software_init_mdm();
+      }
+      else if (WNC_MDM_ERR == WNC_CMD_ERR)
+      {
+        PUTS("Socket Write fail!!!\r\n");
+        software_init_mdm();
+      }else if (WNC_MDM_ERR == WNC_EXTERR)
+      {
+        PUTS("Socket Disconnected (broken) !!!\r\n");
+        sockclose_mdm();
+        sockopen_mdm();
+        //software_init_mdm();
+      }
+    } while (WNC_MDM_ERR != WNC_OK);
+    }
+    else
+      PUTS("Socket is closed for write!\r\n");
+}
+
+unsigned sockread_mdm(string * sockData, int len, int retries)
+{
+    unsigned n = 0;
+    
+    if (socketOpen == 1)
+    {
+    do
+    {
+      WNC_MDM_ERR = WNC_OK;
+      n = at_sockread_wnc(sockData, len, retries);
+      if (WNC_MDM_ERR == WNC_NO_RESPONSE)
+      {
+        if (n == 0)
+            software_init_mdm();
+        else
+            PUTS("Sock read partial data!!!\r\n");
+      }
+      else if (WNC_MDM_ERR == WNC_CMD_ERR)
+        PUTS("Sock read fail!!!!\r\n");
+    } while (WNC_MDM_ERR == WNC_NO_RESPONSE);
+    }
+    else
+    {
+      PUTS("Socket is closed for read\r\n");
+      sockData->erase();
+    }
+      
+    return (n);
+}
+
+void sockclose_mdm(void)
+{
+    do
+    {
+      WNC_MDM_ERR = WNC_OK;
+      at_sockclose_wnc();
+      // Assume close happened even if it went bad
+      // going bad will result in a re-init anyways and if close
+      // fails we're pretty much in bad state and not much can do
+      socketOpen = 0;
+      if (WNC_MDM_ERR == WNC_NO_RESPONSE)
+      {
+        software_init_mdm();
+      }
+      else if (WNC_MDM_ERR == WNC_CMD_ERR)
+        PUTS("Sock close fail!!!\r\n");
+    } while (WNC_MDM_ERR != WNC_OK);
+}
+
+/**                                                                                                                                                          
+ * C++ version 0.4 char* style "itoa":                                                                                                                       
+ * Written by Lukas Chmela                                                                                                                                   
+ * Released under GPLv3.                                                                                                                                     
+*/
+ 
+char* itoa(int value, char* result, int base)                                                                                                          
+{                                                                                                                                                        
+    // check that the base if valid                                                                                                                      
+    if ( base < 2 || base > 36 ) {                                                                                                                       
+        *result = '\0';                                                                                                                                  
+        return result;                                                                                                                                   
+    }                                                                                                                                                    
+ 
+    char* ptr = result, *ptr1 = result, tmp_char;                                                                                                        
+    int tmp_value;                                                                                                                                       
+ 
+    do {                                                                                                                                                 
+        tmp_value = value;                                                                                                                               
+        value /= base;                                                                                                                                   
+        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)];                             
+    } while ( value );                                                                                                                                   
+ 
+    // Apply negative sign                                                                                                                               
+    if ( tmp_value < 0 )                                                                                                                                 
+    *ptr++ = '-';                                                                                                                                    
+    *ptr-- = '\0';                                                                                                                                       
+ 
+    while ( ptr1 < ptr ) {                                                                                                                               
+    tmp_char = *ptr;                                                                                                                                 
+    *ptr-- = *ptr1;                                                                                                                                  
+    *ptr1++ = tmp_char;                                                                                                                              
+    }                                                                                                                                                    
+ 
+    return result;                                                                                                                                       
+}
+
+extern int mdm_sendAtCmdRsp(const char *cmd, const char **rsp_list, int timeout_ms, string * rsp, int * len);
+
+int check_wnc_ready(void)
+{
+    string * pRespStr;
+    size_t pos;
+    int regSts;
+    int cmdRes1, cmdRes2;
+
+#ifdef WNC_CMD_DEBUG_ON_VERBOSE
+    PUTS("<-------- Begin Cell Status ------------\r\n");
+#endif
+    cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, WNC_TIMEOUT_MS);       // Check RSSI,BER
+    cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, WNC_TIMEOUT_MS);      // Check if SIM locked
+    
+    if ((cmdRes1 != 0) && (cmdRes2 != 0))
+    {
+#ifdef WNC_CMD_DEBUG_ON_VERBOSE
+        PUTS("------------ WNC No Response! --------->\r\n");
+#endif
+        return (-2);      
+    }
+  
+    // If SIM Card not ready don't bother with commands!
+    if (pRespStr->find("CPIN: READY") == string::npos)
+    {
+#ifdef WNC_CMD_DEBUG_ON_VERBOSE
+        PUTS("------------ WNC SIM Problem! --------->\r\n");
+#endif
+        return (-1);
+    }
+  
+    // SIM card OK, now check for signal and cellular network registration
+    cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, WNC_TIMEOUT_MS);      // Check if registered on network
+    if (pRespStr->size() > 0)
+    {
+    pos = pRespStr->find("CREG: ");
+    if (pos != string::npos)
+    {
+        // The registration is the 2nd arg in the comma separated list
+        *pRespStr = pRespStr->substr(pos+8, 1);
+        regSts = atoi(pRespStr->c_str());
+        // 1 - registered home, 5 - registered roaming
+        if ((regSts != 1) && (regSts != 5))
+        {
+#ifdef WNC_CMD_DEBUG_ON_VERBOSE
+            PUTS("------------ WNC Cell Link Down! ------>\r\n");
+#endif
+            return (-2);
+        }
+    }
+
+#ifdef WNC_CMD_DEBUG_ON_VERBOSE
+    PUTS("------------ WNC Ready ---------------->\r\n");
+#endif
+    }
+    else
+    {
+#ifdef WNC_CMD_DEBUG_ON_VERBOSE
+        PUTS("------------ CREG No Reply !----------->\r\n");
+#endif
+        return (-2);
+    }
+
+    return (0);
+}
+
+// Sets a global with failure or success, assumes 1 thread all the time
+int send_wnc_cmd(const char * s, string ** r, int ms_timeout)
+{
+  int cmdRes;
+  
+  if (check_wnc_ready() < 0)
+  {
+     static string noRespStr;
+
+#ifdef WNC_CMD_DEBUG_ON
+     PUTS("FAIL send cmd: ");
+     #ifdef WNC_CMD_DEBUG_ON_VERBOSE
+     PUTS(s);
+     PUTS("\r\n");
+     #else
+     string truncStr(s, 50);
+     truncStr += "\r\n";
+     PUTS(truncStr.c_str());
+     #endif
+#else
+     PUTS("FAIL send cmd!\r\n");
+#endif
+
+     WNC_MDM_ERR = WNC_CELL_LINK_DOWN;
+     noRespStr.erase();
+     *r = &noRespStr;
+     return (-3);
+  }
+
+#ifdef WNC_CMD_DEBUG_ON
+  #ifdef WNC_CMD_DEBUG_ON_VERBOSE
+  PUTS("[---------- Network Status -------------\r\n");
+  #endif
+  string * pRespStr;
+  at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, 5000);
+  #ifdef WNC_CMD_DEBUG_ON_VERBOSE
+  PUTS("---------------------------------------]\r\n");
+  #endif
+#endif
+
+  // If WNC ready, send user command
+  cmdRes = at_send_wnc_cmd(s, r, ms_timeout);
+  
+  if (cmdRes == -1)
+     WNC_MDM_ERR = WNC_CMD_ERR;
+  
+  if (cmdRes == -2)
+     WNC_MDM_ERR = WNC_NO_RESPONSE;
+     
+  if (cmdRes == -3) {
+     WNC_MDM_ERR = WNC_EXTERR;
+     PRINTF("[[WNC_MDM_ERR = WNC_EXTERR]] \r\n");
+  }
+
+ if (cmdRes == 0)
+     WNC_MDM_ERR = WNC_OK;
+  
+  return (cmdRes);
+}
+
+int at_send_wnc_cmd(const char * s, string ** r, int ms_timeout)
+{
+   //Eaddy
+  static const char * rsp_lst[] = { "OK", "ERROR","@EXTERR", "+CME", NULL };
+  int len;
+
+#ifdef WNC_CMD_DEBUG_ON
+  #ifdef WNC_CMD_DEBUG_ON_VERBOSE
+  
+  #else
+  if (strlen(s) > 60)
+  {
+      string truncStr(s,57);
+      truncStr += "...";
+      PRINTF("Send: <<%s>>\r\n",truncStr.c_str());
+  }
+  else
+  #endif
+      PRINTF("Send: <<%s>>\r\n",s);
+#endif
+
+  int res = mdm_sendAtCmdRsp(s, rsp_lst, ms_timeout, &wncStr, &len);
+  *r = &wncStr;   // Return a pointer to the static string
+      
+  if (res >= 0)
+  {
+
+#ifdef WNC_CMD_DEBUG_ON   
+      PUTS("[");
+      #ifdef WNC_CMD_DEBUG_ON_VERBOSE
+      PUTS(wncStr.c_str());
+      PUTS("]\r\n");
+      #else
+      if (wncStr.size() < 51)
+          PUTS(wncStr.c_str());
+      else
+      {
+          string truncStr = wncStr.substr(0,50) + "...";
+          PUTS(truncStr.c_str());
+      }
+      PUTS("]\r\n");
+      #endif
+#endif
+
+#if 0
+      if (res > 0)
+          return -1;
+      else
+          return 0;
+#else
+    //Eaddy added         
+       if (res == 0) {
+          /* OK */
+          return 0;
+      } else if (res == 2) {
+          /* @EXTERR */
+          PRINTF("@EXTERR and res = %d \r\n", res);
+          return -3;
+      } else
+          return -1;
+#endif
+  }
+  else
+  {
+      PUTS("No response from WNC!\n\r");
+      return -2;
+  }
+}
+
+
+void at_at_wnc(void)
+{
+    string * pRespStr;
+    send_wnc_cmd("AT", &pRespStr, WNC_TIMEOUT_MS); // Heartbeat?
+}
+
+void at_init_wnc(bool hardReset)
+{
+  static bool pdnSet = false;
+  static bool intSet = false;
+  static bool sockDialSet = false;  
+  string * pRespStr;
+  int cmdRes;
+  
+  if (hardReset == true)
+  {
+      PUTS("Hard Reset!\r\n");
+      pdnSet = false;
+      intSet = false;
+      sockDialSet = false;
+  }
+  
+  PUTS("Start AT init of WNC:\r\n");
+  // Quick commands below do not need to check cellular connectivity
+  cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_TIMEOUT_MS);             // Heartbeat?
+  cmdRes += at_send_wnc_cmd("ATE0", &pRespStr, WNC_TIMEOUT_MS);           // Echo Off
+  cmdRes += at_send_wnc_cmd("AT+CMEE=2", &pRespStr, WNC_TIMEOUT_MS);      // 2 - verbose error, 1 - numeric error, 0 - just ERROR
+  
+  // If the simple commands are not working no chance of more complex.
+  //  I have seen re-trying commands make it worse.
+  if (cmdRes < 0)
+  {
+      // Since I used the at_send_wnc_cmd I am setting the error state based upon
+      //  the responses.  And since these are simple commands, even if the WNC
+      //  is saying ERROR, treat it like a no response.
+      WNC_MDM_ERR = WNC_NO_RESPONSE;
+      return ;
+  }
+  
+  if (intSet == false)
+    cmdRes = send_wnc_cmd("AT@INTERNET=1", &pRespStr, WNC_TIMEOUT_MS);
+  
+  if (cmdRes == 0)
+    intSet = true;
+  else
+    return ;
+  
+  if (pdnSet == false)
+  {
+    string cmd_str("AT%PDNSET=1,");
+    cmd_str += MY_APN_STR;
+    cmd_str += ",IP";
+    cmdRes = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 4*WNC_TIMEOUT_MS); // Set APN, cmd seems to take a little longer sometimes
+  }
+  
+  if (cmdRes == 0)
+    pdnSet = true;
+  else
+    return ;
+  
+  if (sockDialSet == false)
+    cmdRes = send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, WNC_TIMEOUT_MS);
+  
+  if (cmdRes == 0)
+    sockDialSet = true;
+  else
+    return ;
+  
+  PUTS("SUCCESS: AT init of WNC!\r\n");
+}
+
+void at_sockopen_wnc(const string & ipStr, const char * port )
+{
+  string * pRespStr;
+  send_wnc_cmd("AT@SOCKCREAT=1", &pRespStr, WNC_TIMEOUT_MS);
+  string cmd_str("AT@SOCKCONN=1,\"");
+  cmd_str += ipStr;
+  cmd_str += "\",";
+  cmd_str += port;
+  cmd_str += ",30";
+  int cmd = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 31000);
+  if (cmd != WNC_OK) {
+      // Per WNC: re-close even if open fails!
+      at_sockclose_wnc();
+  }
+}
+
+void at_sockclose_wnc(void)
+{
+  string * pRespStr;
+  send_wnc_cmd("AT@SOCKCLOSE=1", &pRespStr, WNC_TIMEOUT_MS);
+}
+
+int at_dnsresolve_wnc(const char * s, string * ipStr)
+{
+  string * pRespStr;
+  string str(s);
+  str = "AT@DNSRESVDON=\"" + str + "\"";
+  if (send_wnc_cmd(str.c_str(), &pRespStr, 60000) == 0)
+  {
+    size_t pos_start = pRespStr->find(":\"") + 2;
+    size_t pos_end = pRespStr->find("\"", pos_start) - 1;
+    if ((pos_start !=  string::npos) && (pos_end != string::npos))
+    {
+        if (pos_end > pos_start)
+        {
+          // Make a copy for use later (the source string is re-used)
+          *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1);
+          return 1;
+        }
+        else
+          PUTS("URL Resolve fail, substr Err\r\n");
+    }
+    else
+      PUTS("URL Resolve fail, no quotes\r\n");
+  }
+  else
+    PUTS("URL Resolve fail, WNC cmd fail\r\n");
+  
+  *ipStr = "192.168.0.1";
+  
+  return -1;
+}
+
+void at_sockwrite_wnc(const char * s)
+{
+  string * pRespStr;
+  char num2str[6];
+  size_t sLen = strlen(s);
+  int res;
+  if (sLen <= 1500)
+  {
+    string cmd_str("AT@SOCKWRITE=1,");
+    itoa(sLen, num2str, 10);
+    cmd_str += num2str;
+    cmd_str += ",\"";
+    while(*s != '\0')
+    {
+      itoa((int)*s++, num2str, 16);
+      // Always 2-digit ascii hex:
+      if (strlen(num2str) == 1)
+      {
+        num2str[2] = '\0';
+        num2str[1] = num2str[0];
+        num2str[0] = '0';
+      }
+      cmd_str += num2str;
+    }
+    cmd_str += "\"";
+    res = send_wnc_cmd(cmd_str.c_str(), &pRespStr, 120000);
+    if (res == -3)
+        PUTS("sockwrite is disconnect \r\n");
+  }
+  else
+    PUTS("sockwrite Err, string to long\r\n");
+}
+
+unsigned at_sockread_wnc(string * pS, unsigned n, unsigned retries = 0)
+{
+  unsigned i, numBytes = 0;
+  string * pRespStr;
+  string cmd_str("AT@SOCKREAD=1,");
+
+  // Clean slate
+  pS->erase();
+  
+  if (n <= 1500)
+  {
+    char num2str[6];
+    
+    itoa(n, num2str, 10);
+    cmd_str += num2str;
+    retries += 1;
+    while (retries--)
+    {
+      // Assuming someone is sending then calling this to receive response, invoke
+      // a pause to give the response some time to come back and then also
+      // between each retry.
+      wait_ms(10);
+      
+      if (send_wnc_cmd(cmd_str.c_str(), &pRespStr, WNC_TIMEOUT_MS) == 0)
+      {
+        size_t pos_start = pRespStr->find("\"")  + 1;
+        size_t pos_end   = pRespStr->rfind("\"") - 1;
+      
+        // Make sure search finds what it's looking for!
+        if (pos_start != string::npos && pos_end != string::npos)
+          i = (pos_end - pos_start + 1);  // Num hex chars, 2 per byte
+        else
+          i = 0;
+          
+        if (i > 0)
+        {
+            retries = 1;  // If any data found retry 1 more time to catch data that might be in another
+                          //  WNC payload
+            string byte;
+            while (pos_start < pos_end)
+            {
+              byte = pRespStr->substr(pos_start, 2);
+              *pS += (char)strtol(byte.c_str(), NULL, 16);
+              pos_start += 2;
+            }
+            numBytes += i/2;
+        }
+      }
+      else
+      {
+          PUTS("no readsock reply!\r\n");
+          return (0);
+      }
+    }
+  }
+  else
+    PUTS("sockread Err, to many to read\r\n");
+  
+  return (numBytes);
+}
diff -r 000000000000 -r bd276b1f1249 wnc_control.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wnc_control.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,48 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef __WNC_CONTROL_H_
+#define __WNC_CONTROL_H_
+
+static const unsigned WNC_TIMEOUT_MS = 10000;
+
+// Core function that sends data to the WNC UART
+extern int send_wnc_cmd(const char * s, string ** r, int ms_timeout);
+
+// Low level command functions
+extern void at_init_wnc(bool hardReset = false);
+extern void at_sockopen_wnc(const string & ipStr, const char * port );
+extern void at_sockclose_wnc(void);
+extern int at_dnsresolve_wnc(const char * s, string * ipStr);
+extern void at_sockwrite_wnc(const char * s);
+extern unsigned at_sockread_wnc(string * pS, unsigned n, unsigned retries);
+extern void at_at_wnc(void);
+extern int at_send_wnc_cmd(const char * s, string ** r, int ms_timeout);
+extern int check_wnc_ready(void);
+
+// High level functions that attempt to correct for things going bad with the WNC
+extern void software_init_mdm(void);
+extern void resolve_mdm(void);
+extern void sockopen_mdm(void);
+extern void sockwrite_mdm(const char * s);
+extern unsigned sockread_mdm(string * sockData, int len, int retries);
+extern void sockclose_mdm(void);
+extern void display_modem_firmware_version(void);
+
+#endif
+
+
diff -r 000000000000 -r bd276b1f1249 xadow_gps.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xadow_gps.cpp	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,303 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#include "mbed.h"
+#include "xadow_gps.h"
+#include "hardware.h"
+
+//  Xadow code based on Eclipse test project at
+//  https://github.com/WayenWeng/Xadow_GPS_v2_test/
+
+//  These first 3 routines are to allow the mbed I2C to be used instead of what was in the Eclipse test code
+void dlc_i2c_configure(int slave_addr, int speed)
+{ 
+} //dlc_i2c_configure
+
+unsigned char dlc_i2c_receive_byte(void)
+{
+    char rxbuffer [1];
+    i2c.read(GPS_DEVICE_ADDR, rxbuffer, 1 );
+    return (unsigned char)rxbuffer[0];
+} //dlc_i2c_receive_byte()
+
+unsigned char dlc_i2c_send_byte(unsigned char ucData)
+{
+    int status;
+    char txbuffer [1];
+    txbuffer[0] = (char)ucData;
+    status = i2c.write(GPS_DEVICE_ADDR, txbuffer, 1, false); //true: do not send stop
+    return status;
+} //dlc_i2c_send_byte()
+ 
+
+unsigned char gps_check_online(void)
+{
+    unsigned char data[GPS_SCAN_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_SCAN_ID);
+
+    for(i=0;i<(GPS_SCAN_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    if(data[5] == GPS_DEVICE_ID)
+    return 1;
+    else return 0;
+}
+ 
+unsigned char gps_utc_date_time[GPS_UTC_DATE_TIME_SIZE] = {0};
+
+unsigned char* gps_get_utc_date_time(void)
+{
+    unsigned char data[GPS_UTC_DATE_TIME_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_UTC_DATE_TIME_ID);
+ 
+    for(i=0;i<(GPS_UTC_DATE_TIME_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    for(i=0;i<GPS_UTC_DATE_TIME_SIZE;i++)
+    gps_utc_date_time[i] = data[i+2];
+
+    return gps_utc_date_time;
+} 
+
+unsigned char gps_get_status(void)
+{
+    unsigned char data[GPS_STATUS_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_STATUS_ID);
+    for(i=0;i<(GPS_STATUS_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    return data[2];
+} 
+
+float gps_get_latitude(void)
+{
+    char data[GPS_LATITUDE_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_LATITUDE_ID);
+    for(i=0;i<(GPS_LATITUDE_SIZE+2);i++)
+    {
+        data[i] = (char)dlc_i2c_receive_byte();
+    }
+
+    return atof(&data[2]);
+}
+
+unsigned char gps_get_ns(void)
+{
+    unsigned char data[GPS_NS_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_NS_ID);
+    for(i=0;i<(GPS_NS_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    if(data[2] == 'N' || data[2] == 'S')return data[2];
+    else return data[2] = '-';
+
+}
+
+float gps_get_longitude(void)
+{
+    char data[GPS_LONGITUDE_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_LONGITUDE_ID);
+    for(i=0;i<(GPS_LONGITUDE_SIZE+2);i++)
+    {
+        data[i] = (char)dlc_i2c_receive_byte();
+    }
+
+    return atof(&data[2]);
+}
+
+unsigned char gps_get_ew(void)
+{
+    unsigned char data[GPS_EW_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_EW_ID);
+    for(i=0;i<(GPS_EW_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    if(data[2] == 'E' || data[2] == 'W')return data[2];
+    else return data[2] = '-';
+}
+
+float gps_get_speed(void)
+{
+    char data[GPS_SPEED_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_SPEED_ID);
+    for(i=0;i<(GPS_SPEED_SIZE+2);i++)
+    {
+        data[i] = (char)dlc_i2c_receive_byte();
+    }
+
+    return atof(&data[2]);
+}
+
+float gps_get_course(void)
+{
+    char data[GPS_COURSE_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_COURSE_ID);
+    for(i=0;i<(GPS_COURSE_SIZE+2);i++)
+    {
+        data[i] = (char)dlc_i2c_receive_byte();
+    }
+
+    return atof(&data[2]);
+}
+
+unsigned char gps_get_position_fix(void)
+{
+    unsigned char data[GPS_POSITION_FIX_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_POSITION_FIX_ID);
+    for(i=0;i<(GPS_POSITION_FIX_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    return data[2];
+}
+
+unsigned char gps_get_sate_used(void)
+{
+    unsigned char data[GPS_SATE_USED_SIZE+2];
+    unsigned char i;
+    unsigned char value;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_SATE_USED_ID);
+    for(i=0;i<(GPS_SATE_USED_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    if(data[3] >= '0' && data[3] <= '9')value = (data[3] - '0') * 10;
+    else value = 0;
+    if(data[2] >= '0' && data[2] <= '9')value += (data[2] - '0');
+    else value += 0;
+
+    return value;
+}
+
+float gps_get_altitude(void)
+{
+    char data[GPS_ALTITUDE_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_ALTITUDE_ID);
+    for(i=0;i<(GPS_ALTITUDE_SIZE+2);i++)
+    {
+        data[i] = (char)dlc_i2c_receive_byte();
+    }
+
+    return atof(&data[2]);
+}
+
+unsigned char gps_get_mode(void)
+{
+    unsigned char data[GPS_MODE_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_MODE_ID);
+    for(i=0;i<(GPS_MODE_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    return data[2];
+}
+
+unsigned char gps_get_mode2(void)
+{
+    unsigned char data[GPS_MODE2_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_MODE2_ID);
+    for(i=0;i<(GPS_MODE2_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    return data[2];
+}
+
+unsigned char gps_get_sate_in_veiw(void)
+{
+    unsigned char data[GPS_SATE_IN_VIEW_SIZE+2];
+    unsigned char i;
+
+    dlc_i2c_configure(GPS_DEVICE_ADDR, 100);
+
+    dlc_i2c_send_byte(GPS_SATE_IN_VIEW_ID);
+    for(i=0;i<(GPS_SATE_IN_VIEW_SIZE+2);i++)
+    {
+        data[i] = dlc_i2c_receive_byte();
+    }
+
+    return data[2];
+}
diff -r 000000000000 -r bd276b1f1249 xadow_gps.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xadow_gps.h	Sun Apr 02 12:28:21 2017 +0000
@@ -0,0 +1,280 @@
+/* ===================================================================
+Copyright © 2016, AVNET Inc.  
+
+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.
+
+======================================================================== */
+
+#ifndef __XADOW_GPS_H_
+#define __XADOW_GPS_H_
+
+/*!
+    \def GPS_DEVICE_ADDR
+    The I2C address GPS
+
+    \def GPS_SCAN_ID
+    The id of scan data, the format is 0,0,0,Device address
+    \def GPS_SCAN_SIZE
+    The length of scan data
+
+    \def GPS_UTC_DATE_TIME_ID
+    The id of utc date and time, the format is YMDHMS
+    \def GPS_UTC_DATE_TIME_SIZE
+    The length of utc date and time data
+
+    \def GPS_STATUS_ID
+    The id of GPS status, the format is A/V
+    \def GPS_STATUS_SIZE
+    The length of GPS status data
+
+    \def GPS_LATITUDE_ID
+    The id of latitude, the format is dd.dddddd
+    \def GPS_LATITUDE_SIZE
+    The length of latitude data
+
+    \def GPS_NS_ID
+    The id of latitude direction, the format is N/S
+    \def GPS_NS_SIZE
+    The length of latitude direction data
+
+    \def GPS_LONGITUDE_ID
+    The id of longitude, the format is ddd.dddddd
+    \def GPS_LONGITUDE_SIZE
+    The length of longitude data
+
+    \def GPS_EW_ID
+    The id of longitude direction, the format is E/W
+    \def GPS_EW_SIZE
+    The length of longitude direction data
+
+    \def GPS_SPEED_ID
+    The id of speed, the format is 000.0~999.9 Knots
+    \def GPS_SPEED_SIZE
+    The length of speed data
+
+    \def GPS_COURSE_ID
+    The id of course, the format is 000.0~359.9
+    \def GPS_COURSE_SIZE
+    The length of course data
+
+    \def GPS_POSITION_FIX_ID
+    The id of position fix status, the format is 0,1,2,6
+    \def GPS_POSITION_FIX_SIZE
+    The length of position fix status data
+
+    \def GPS_SATE_USED_ID
+    The id of state used, the format is 00~12
+    \def GPS_SATE_USED_SIZE
+    The length of sate used data
+
+    \def GPS_ALTITUDE_ID
+    The id of altitude, the format is -9999.9~99999.9
+    \def GPS_ALTITUDE_SIZE
+    The length of altitude data
+
+    \def GPS_MODE_ID
+    The id of locate mode, the format is A/M
+    \def GPS_MODE_SIZE
+    The length of locate mode data
+
+    \def GPS_MODE2_ID
+    The id of current status, the format is 1,2,3
+    \def GPS_MODE2_SIZE
+    The length of current status data
+
+    \def GPS_SATE_IN_VIEW_ID
+    The id of sate in view
+    \def GPS_SATE_IN_VIEW_SIZE
+    The length of sate in view data
+*/
+
+/* Data format:
+ * ID(1 byte), Data length(1 byte), Data 1, Data 2, ... Data n (n bytes, n = data length)
+ * For example, get the scan data.
+ * First, Send GPS_SCAN_ID(1 byte) to device.
+ * Second, Receive scan data(ID + Data length + GPS_SCAN_SIZE = 6 bytes).
+ * Third, The scan data begin from the third data of received.
+ * End
+ */
+
+#define GPS_DEVICE_ID         0x05
+//#define GPS_DEVICE_ADDR         0x05
+#define GPS_DEVICE_ADDR         0x0A //For mbed, the address has to be  << 1
+
+#define GPS_SCAN_ID             0 // 4 bytes
+#define GPS_SCAN_SIZE           4 // 0,0,0,Device address
+
+#define GPS_UTC_DATE_TIME_ID    1 // YMDHMS
+#define GPS_UTC_DATE_TIME_SIZE  6 // 6 bytes
+
+#define GPS_STATUS_ID           2 // A/V
+#define GPS_STATUS_SIZE         1 // 1 byte
+
+#define GPS_LATITUDE_ID         3 // dd.dddddd
+#define GPS_LATITUDE_SIZE       9 // 9 bytes
+
+#define GPS_NS_ID               4 // N/S
+#define GPS_NS_SIZE             1 // 1 byte
+
+#define GPS_LONGITUDE_ID        5 // ddd.dddddd
+#define GPS_LONGITUDE_SIZE      10 // 10 bytes
+
+#define GPS_EW_ID               6 // E/W
+#define GPS_EW_SIZE             1 // 1 byte
+
+#define GPS_SPEED_ID            7 // 000.0~999.9 Knots
+#define GPS_SPEED_SIZE          5 // 5 bytes
+
+#define GPS_COURSE_ID           8 // 000.0~359.9
+#define GPS_COURSE_SIZE         5 // 5 bytes
+
+#define GPS_POSITION_FIX_ID     9 // 0,1,2,6
+#define GPS_POSITION_FIX_SIZE   1 // 1 byte
+
+#define GPS_SATE_USED_ID        10 // 00~12
+#define GPS_SATE_USED_SIZE      2 // 2 bytes
+
+#define GPS_ALTITUDE_ID         11 // -9999.9~99999.9
+#define GPS_ALTITUDE_SIZE       7 // 7 bytes
+
+#define GPS_MODE_ID             12 // A/M
+#define GPS_MODE_SIZE           1 // 1 byte
+
+#define GPS_MODE2_ID            13 // 1,2,3
+#define GPS_MODE2_SIZE          1 // 1 byte
+
+#define GPS_SATE_IN_VIEW_ID     14 // 0~12
+#define GPS_SATE_IN_VIEW_SIZE   1 // 1 byte
+
+
+/**
+ *  \brief Get the status of the device.
+ *
+ *  \return Return TRUE or FALSE. TRUE is on line, FALSE is off line.
+ *
+ */
+unsigned char gps_check_online(void);
+
+/**
+ *  \brief Get the utc date and time.
+ *
+ *  \return Return the pointer of utc date sand time, the format is YMDHMS.
+ *
+ */
+unsigned char* gps_get_utc_date_time(void);
+
+/**
+ *  \brief Get the status of GPS.
+ *
+ *  \return Return A or V. A is orientation, V is navigation.
+ *
+ */
+unsigned char gps_get_status(void);
+
+/**
+ *  \brief Get the altitude.
+ *
+ *  \return Return altitude data. The format is dd.dddddd.
+ *
+ */
+float gps_get_latitude(void);
+
+/**
+ *  \brief Get the lattitude direction.
+ *
+ *  \return Return lattitude direction data. The format is N/S. N is north, S is south.
+ *
+ */
+unsigned char gps_get_ns(void);
+
+/**
+ *  \brief Get the longitude.
+ *
+ *  \return Return longitude data. The format is ddd.dddddd.
+ *
+ */
+float gps_get_longitude(void);
+
+/**
+ *  \brief Get the longitude direction.
+ *
+ *  \return Return longitude direction data. The format is E/W. E is east, W is west.
+ *
+ */
+unsigned char gps_get_ew(void);
+
+/**
+ *  \brief Get the speed.
+ *
+ *  \return Return speed data. The format is 000.0~999.9 Knots.
+ *
+ */
+float gps_get_speed(void);
+
+/**
+ *  \brief Get the course.
+ *
+ *  \return Return course data. The format is 000.0~359.9.
+ *
+ */
+float gps_get_course(void);
+
+/**
+ *  \brief Get the status of position fix.
+ *
+ *  \return Return position fix data. The format is 0,1,2,6.
+ *
+ */
+unsigned char gps_get_position_fix(void);
+
+/**
+ *  \brief Get the number of state used¡£
+ *
+ *  \return Return number of state used. The format is 0-12.
+ *
+ */
+unsigned char gps_get_sate_used(void);
+
+/**
+ *  \brief Get the altitude¡£ the format is -9999.9~99999.9
+ *
+ *  \return Return altitude data. The format is -9999.9~99999.9.
+ *
+ */
+float gps_get_altitude(void);
+
+/**
+ *  \brief Get the mode of location.
+ *
+ *  \return Return mode of location. The format is A/M. A:automatic, M:manual.
+ *
+ */
+unsigned char gps_get_mode(void);
+
+/**
+ *  \brief Get the current status of GPS.
+ *
+ *  \return Return current status. The format is 1,2,3. 1:null, 2:2D, 3:3D.
+ *
+ */
+unsigned char gps_get_mode2(void);
+
+/**
+ *  \brief Get the number of sate in view.
+ *
+ *  \return Return the number of sate in view.
+ *
+ */
+unsigned char gps_get_sate_in_veiw(void);
+ 
+#endif
\ No newline at end of file