Proswift with BLE EV-BL652ARDZ

Fork of ADISense1000_Example_FW by Analog Devices

Files at this revision

API Documentation at this revision

Comitter:
nfathurr
Date:
Fri Aug 24 08:58:48 2018 +0000
Parent:
0:76fed7dd9235
Commit message:
test

Changed in this revision

ADISense1000_MBED.c Show annotated file Show diff for this revision Revisions of this file
common/utils.c Show annotated file Show diff for this revision Revisions of this file
common/utils.h Show annotated file Show diff for this revision Revisions of this file
inc/JENKINS_AUTOGEN_PLATFORM.h Show annotated file Show diff for this revision Revisions of this file
inc/adisense1000_boot.h Show annotated file Show diff for this revision Revisions of this file
inc/ble_interface/bl652.h Show annotated file Show diff for this revision Revisions of this file
inc/ble_interface/ble_interface.h Show annotated file Show diff for this revision Revisions of this file
inc/bootloader.h Show annotated file Show diff for this revision Revisions of this file
inc/communications.h Show annotated file Show diff for this revision Revisions of this file
inc/eeprom_virtual/eeprom.h Show annotated file Show diff for this revision Revisions of this file
inc/led.h Show annotated file Show diff for this revision Revisions of this file
inc/myproswift_error_codes.h Show annotated file Show diff for this revision Revisions of this file
inc/myproswift_eval.h Show annotated file Show diff for this revision Revisions of this file
inc/myproswift_periph.h Show annotated file Show diff for this revision Revisions of this file
inc/pc_interface/pc_conversions.h Show annotated file Show diff for this revision Revisions of this file
inc/pc_interface/pc_interface.h Show annotated file Show diff for this revision Revisions of this file
inc/pc_interface/pc_serial.h Show annotated file Show diff for this revision Revisions of this file
inc/rcc_backup_registers/rcc_backup_registers.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
src/adisense1000_boot.cpp Show annotated file Show diff for this revision Revisions of this file
src/ble_interface/bl652.cpp Show annotated file Show diff for this revision Revisions of this file
src/ble_interface/ble_interface.cpp Show annotated file Show diff for this revision Revisions of this file
src/bootloader.cpp Show annotated file Show diff for this revision Revisions of this file
src/communications.cpp Show annotated file Show diff for this revision Revisions of this file
src/eeprom_virtual/eeprom.c Show annotated file Show diff for this revision Revisions of this file
src/led.cpp Show annotated file Show diff for this revision Revisions of this file
src/myproswift_eval.cpp Show annotated file Show diff for this revision Revisions of this file
src/myproswift_periph.cpp Show annotated file Show diff for this revision Revisions of this file
src/pc_interface/pc_interface.cpp Show annotated file Show diff for this revision Revisions of this file
src/pc_interface/pc_json_conversions.cpp Show annotated file Show diff for this revision Revisions of this file
src/pc_interface/pc_serial.cpp Show annotated file Show diff for this revision Revisions of this file
src/rcc_backup_registers/rcc_backup_registers.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/ADISense1000_MBED.c	Thu Jan 25 16:00:23 2018 +0000
+++ b/ADISense1000_MBED.c	Fri Aug 24 08:58:48 2018 +0000
@@ -1,114 +1,193 @@
-/*!
- ******************************************************************************
- * @file:   config.c
- * @brief:
- *-----------------------------------------------------------------------------
- *
-Copyright (c) 2017 Emutex Ltd. / Analog Devices, Inc.
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-  - Redistributions of source code must retain the above copyright notice,
-    this list of conditions and the following disclaimer.
-  - Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-  - Modified versions of the software must be conspicuously marked as such.
-  - This software is licensed solely and exclusively for use with processors
-    manufactured by or for Analog Devices, Inc.
-  - This software may not be combined or merged with other code in any manner
-    that would cause the software to become subject to terms and conditions
-    which differ from those listed here.
-  - Neither the name of Analog Devices, Inc. nor the names of its
-    contributors may be used to endorse or promote products derived
-    from this software without specific prior written permission.
-  - The use of this software may or may not infringe the patent rights of one
-    or more patent holders.  This license does not release you from the
-    requirement that you obtain separate licenses from these patent holders
-    to use this software.
-
-THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
-TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF CLAIMS OF INTELLECTUAL
-PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#include "inc/adi_sense_config_types.h"
-
-ADI_SENSE_CONFIG config = {
-    .versionId = { .major = 1, .minor = 4 },
-    .adisense1000 = {
-            .power = {
-                .powerMode = ADI_SENSE_1000_POWER_MODE_FULL,
-                .supplyVoltage = 3.3,
-            },
-            .measurement = {
-                .operatingMode = ADI_SENSE_1000_OPERATING_MODE_CONTINUOUS,
-                .dataReadyMode = ADI_SENSE_1000_DATAREADY_PER_CYCLE,
-                .cycleInterval = 0,
-            },
-            .channels = {
-                [ADI_SENSE_1000_CHANNEL_ID_SENSOR_0] = {
-                    .enableChannel = true,
-                    .disablePublishing = false,
-                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_CJC_0,
-                    .measurementsPerCycle = 1,
-                    .extraSettlingTime = 0.0000,
-                    .measurementUnit = ADI_SENSE_1000_MEASUREMENT_UNIT_CELSIUS,
-                    .adcChannelConfig = {
-                        .sensor = ADI_SENSE_1000_ADC_SENSOR_THERMOCOUPLE_T_DEF_L1,
-                        .gain = ADI_SENSE_1000_ADC_GAIN_128X,
-                        .current = {
-                            .outputLevel = ADI_SENSE_1000_ADC_EXC_CURRENT_NONE,
-                            .swapOption = ADI_SENSE_1000_ADC_EXC_CURRENT_SWAP_NONE,
-                        },
-                        .filter = {
-                            .type = ADI_SENSE_1000_ADC_FILTER_SINC4,
-                            .fs = 1920,
-                        },
-                        .reference = {
-                            .type = ADI_SENSE_1000_ADC_REFERENCE_VOLTAGE_INTERNAL,
-                            .disableBuffer = false,
-                        },
-                        .enableVbias = true,
-                    },
-                },
-                [ADI_SENSE_1000_CHANNEL_ID_CJC_0] = {
-                    .enableChannel = true,
-                    .disablePublishing = false,
-                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_NONE,
-                    .measurementsPerCycle = 1,
-                    .extraSettlingTime = 0.0000,
-                    .measurementUnit = ADI_SENSE_1000_MEASUREMENT_UNIT_CELSIUS,
-                    .adcChannelConfig = {
-                        .sensor = ADI_SENSE_1000_ADC_SENSOR_RTD_2WIRE_PT100_DEF_L1,
-                        .gain = ADI_SENSE_1000_ADC_GAIN_128X,
-                        .current = {
-                            .outputLevel = ADI_SENSE_1000_ADC_EXC_CURRENT_500uA,
-                            .swapOption = ADI_SENSE_1000_ADC_EXC_CURRENT_SWAP_NONE,
-                        },
-                        .filter = {
-                            .type = ADI_SENSE_1000_ADC_FILTER_SINC4,
-                            .fs = 1920,
-                        },
-                        .reference = {
-                            .type = ADI_SENSE_1000_ADC_REFERENCE_RESISTOR_INTERNAL_1,
-                            .disableBuffer = false,
-                        },
-                        .enableVbias = false,
-                    },
-                },
-            },
-    },
-};
+/*!
+ ******************************************************************************
+ * @file:   config.c
+ * @brief:
+ *-----------------------------------------------------------------------------
+ *
+Copyright (c) 2018 Analog Devices, Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+  - Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  - Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  - Modified versions of the software must be conspicuously marked as such.
+  - This software is licensed solely and exclusively for use with processors
+    manufactured by or for Analog Devices, Inc.
+  - This software may not be combined or merged with other code in any manner
+    that would cause the software to become subject to terms and conditions
+    which differ from those listed here.
+  - Neither the name of Analog Devices, Inc. nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+  - The use of this software may or may not infringe the patent rights of one
+    or more patent holders.  This license does not release you from the
+    requirement that you obtain separate licenses from these patent holders
+    to use this software.
+
+THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF CLAIMS OF INTELLECTUAL
+PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include "inc/adi_sense_config_types.h"
 
+ADI_SENSE_CONFIG adi_sense_config = {
+    .versionId = { .major = 1, .minor = 4 },
+    .productId = ADI_SENSE_PRODUCT_ID_1000,
+    .adisense1000 = {
+            .power = {
+                .powerMode = ADI_SENSE_1000_POWER_MODE_FULL,
+                .supplyVoltage = 3.3,
+            },
+            .measurement = {
+                .operatingMode = ADI_SENSE_1000_OPERATING_MODE_CONTINUOUS,
+                .dataReadyMode = ADI_SENSE_1000_DATAREADY_PER_CYCLE,
+                .cycleInterval = 0,
+            },
+            .channels = {
+                [ADI_SENSE_1000_CHANNEL_ID_CJC_0] = {
+                    .enableChannel = true,
+                    .disablePublishing = false,
+                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_NONE,
+                    .measurementsPerCycle = 1,
+                    .extraSettlingTime = 0.0000,
+                    .measurementUnit = ADI_SENSE_1000_MEASUREMENT_UNIT_CELSIUS,
+                    .adcChannelConfig = {
+                        .sensor = ADI_SENSE_1000_ADC_SENSOR_RTD_2WIRE_PT100_DEF_L1,
+                        .gain = ADI_SENSE_1000_ADC_GAIN_32X,
+                        .current = {
+                            .outputLevel = ADI_SENSE_1000_ADC_EXC_CURRENT_500uA,
+                            .swapOption = ADI_SENSE_1000_ADC_EXC_CURRENT_SWAP_NONE,
+                        },
+                        .filter = {
+                            .type = ADI_SENSE_1000_ADC_FILTER_FIR_25SPS,
+                            .fs = 0,
+                            //.type = ADI_SENSE_1000_ADC_FILTER_SINC4,
+                            //.fs = 1920,
+                        },
+                        .reference = {
+                            .type = ADI_SENSE_1000_ADC_REFERENCE_RESISTOR_INTERNAL_1,
+                            .disableBuffer = false,
+                        },
+                        .enableVbias = false,
+                    },
+                },
+                [ADI_SENSE_1000_CHANNEL_ID_SENSOR_0] = {
+                    .enableChannel = true,
+                    .disablePublishing = false,
+                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_CJC_0,
+                    .measurementsPerCycle = 1,
+                    .extraSettlingTime = 0.0000,
+                    .measurementUnit = ADI_SENSE_1000_MEASUREMENT_UNIT_CELSIUS,
+                    .adcChannelConfig = {
+                        .sensor = ADI_SENSE_1000_ADC_SENSOR_THERMOCOUPLE_K_DEF_L1,
+                        .gain = ADI_SENSE_1000_ADC_GAIN_128X,
+                        .current = {
+                            .outputLevel = ADI_SENSE_1000_ADC_EXC_CURRENT_NONE,
+                            .swapOption = ADI_SENSE_1000_ADC_EXC_CURRENT_SWAP_NONE,
+                        },
+                        .filter = {
+                            .type = ADI_SENSE_1000_ADC_FILTER_FIR_25SPS,
+                            .fs = 0,
+                            //.type = ADI_SENSE_1000_ADC_FILTER_SINC4,
+                            //.fs = 1920,
+                        },
+                        .reference = {
+                            .type = ADI_SENSE_1000_ADC_REFERENCE_VOLTAGE_INTERNAL,
+                            .disableBuffer = false,
+                        },
+                        .enableVbias = true,
+                    },
+                },
+                [ADI_SENSE_1000_CHANNEL_ID_VOLTAGE_0] = {
+                    .enableChannel = true,
+                    .disablePublishing = false,
+                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_NONE,
+                    .measurementsPerCycle = 1,
+                    .extraSettlingTime = 0.0000,
+                    .measurementUnit = ADI_SENSE_1000_MEASUREMENT_UNIT_DEFAULT,
+                    .adcChannelConfig = {
+                        .sensor = ADI_SENSE_1000_ADC_SENSOR_VOLTAGE_PRESSURE_AMPHENOL_NPA300X,
+                        .gain = ADI_SENSE_1000_ADC_GAIN_2X,
+                        .current = {
+                            .outputLevel = ADI_SENSE_1000_ADC_EXC_CURRENT_NONE,
+                            .swapOption = ADI_SENSE_1000_ADC_EXC_CURRENT_SWAP_NONE,
+                        },
+                        .filter = {
+                            .type = ADI_SENSE_1000_ADC_FILTER_FIR_25SPS,
+                            .fs = 0,
+                            //.type = ADI_SENSE_1000_ADC_FILTER_SINC4,
+                            //.fs = 1920,
+                        },
+                        .reference = {
+                            .type = ADI_SENSE_1000_ADC_REFERENCE_VOLTAGE_INTERNAL,
+                            .disableBuffer = false,
+                        },
+                        .enableVbias = false,
+                    },
+                },
+                [ADI_SENSE_1000_CHANNEL_ID_I2C_0] = {
+                    .enableChannel = true,
+                    .disablePublishing = false,
+                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_NONE,
+                    .measurementsPerCycle = 1,
+                    .extraSettlingTime = 0.0000,
+                    .i2cChannelConfig = {
+                        .sensor = ADI_SENSE_1000_I2C_SENSOR_HUMIDITY_SENSIRION_SHT3X,
+                        .deviceAddress = 0x44,
+                    },
+                },
+                [ADI_SENSE_1000_CHANNEL_ID_SPI_0] = {
+                    /* Accelerometer X-Axis (and common settings for physical channel) */
+                    .enableChannel = true,
+                    .disablePublishing = false,
+                    .compensationChannel = ADI_SENSE_1000_CHANNEL_ID_NONE,
+                    .measurementsPerCycle = 1,
+                    .extraSettlingTime = 10,
+                    .offsetAdjustment = -0.15,
+                    /* Optional threshold limits applied to the processed measurement results */
+                    .lowThreshold = -2.0,
+                    .highThreshold = 2.0,
+                    .spiChannelConfig = {
+                    .sensor = ADI_SENSE_1000_SPI_SENSOR_ACCELEROMETER_ADI_ADXL362,
+                    .configurationCommand = {
+                        .command = { 0x0A, 0x2C, 0x03 }, /* +/-8G range */
+                        .commandLength = 3,
+                    },
+                  },
+                },
+                [ADI_SENSE_1000_CHANNEL_ID_SPI_1] = {
+                /* Accelerometer Y-Axis (virtual channel) */
+                .enableChannel = true,
+                .offsetAdjustment = -0.15,
+                /* Optional threshold limits applied to the processed measurement results */
+                .lowThreshold = -2.0,
+                .highThreshold = 2.0,
+                },
+                [ADI_SENSE_1000_CHANNEL_ID_SPI_2] = {
+                /* Accelerometer Z-Axis (virtual channel) */
+                .enableChannel = true,
+                /* Optional adjustment applied to the PROCESSED OUTPUT value from the sensor */
+                .offsetAdjustment = -0.4,
+                /* Optional threshold limits applied to the processed measurement results */
+                .lowThreshold = -2,
+                .highThreshold = 2,
+                },
+            },
+    },
+};
+
--- a/common/utils.c	Thu Jan 25 16:00:23 2018 +0000
+++ b/common/utils.c	Fri Aug 24 08:58:48 2018 +0000
@@ -1,389 +1,455 @@
-#include <stdlib.h>
-
-#include "utils.h"
-#include "inc/adi_sense_log.h"
-
-void utils_printStatus(
-    ADI_SENSE_STATUS *pStatus)
-{
-    ADI_SENSE_LOG_INFO("Status Summary:");
-
-    if (pStatus->deviceStatus == 0)
-    {
-        ADI_SENSE_LOG_INFO("\tNo errors detected");
-    }
-    else
-    {
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_BUSY)
-            ADI_SENSE_LOG_INFO("\tCommand running");
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_DATAREADY)
-            ADI_SENSE_LOG_INFO("\tData ready");
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR)
-            ADI_SENSE_LOG_INFO("\tActive Errors - RESET REQUIRED");
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_FIFO_ERROR)
-            ADI_SENSE_LOG_INFO("\tActive FIFO Errors - ATTENTION REQUIRED");
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_CONFIG_ERROR)
-            ADI_SENSE_LOG_INFO("\tActive Configuration Errors - ATTENTION REQUIRED");
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_LUT_ERROR)
-            ADI_SENSE_LOG_INFO("\tActive Look-Up Table Errors - ATTENTION REQUIRED");
-
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR)
-        {
-            ADI_SENSE_LOG_INFO("\tActive Errors - ATTENTION REQUIRED");
-            ADI_SENSE_LOG_INFO("\t\tLast Error Code: %u (0x%X)",
-                               pStatus->errorCode, pStatus->errorCode);
-
-            if (pStatus->diagnosticsStatus == 0)
-            {
-                ADI_SENSE_LOG_INFO("\t\tNo diagnostics faults detected");
-            }
-            else
-            {
-                ADI_SENSE_LOG_INFO("\t\tActive diagnostics faults:");
-
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CHECKSUM_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tInternal Checksum fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_COMMS_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tInternal Communications fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_MONITOR_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tSupply Monitor fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_CAP_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tSupply Regulator Capacitor fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINM_UV_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tNegative Analog Input Under-Voltage fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINM_OV_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tNegative Analog Input Over-Voltage fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINP_UV_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tPositive Analog Input Under-Voltage fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINP_OV_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tPositive Analog Input Over-Voltage fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CONVERSION_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tInternal ADC Conversions fault detected");
-                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CALIBRATION_ERROR)
-                    ADI_SENSE_LOG_INFO("\t\t\tInternal Device Calibrations fault detected");
-            }
-        }
-
-        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ALERT)
-        {
-            ADI_SENSE_LOG_INFO("\tActive Alerts - ATTENTION REQUIRED:");
-            ADI_SENSE_LOG_INFO("\t\tLast Alert Code: %u (0x%X)",
-                               pStatus->alertCode, pStatus->alertCode);
-
-            for (unsigned i = 0; i < ADI_SENSE_1000_MAX_CHANNELS; i++)
-            {
-                if (pStatus->channelAlerts[i] == 0)
-                    continue;
-
-                ADI_SENSE_LOG_INFO("\t\tChannel #%u:", i);
-                ADI_SENSE_LOG_INFO("\t\t\tLast Alert Code: %u (0x%X)",
-                                   pStatus->channelAlertCodes[i],
-                                   pStatus->channelAlertCodes[i]);
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_TIMEOUT)
-                    ADI_SENSE_LOG_INFO("\t\t\tTimeout alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_UNDER_RANGE)
-                    ADI_SENSE_LOG_INFO("\t\t\tUnder Range alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_OVER_RANGE)
-                    ADI_SENSE_LOG_INFO("\t\t\tOver Range alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LOW_LIMIT)
-                    ADI_SENSE_LOG_INFO("\t\t\tLow limit alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_HIGH_LIMIT)
-                    ADI_SENSE_LOG_INFO("\t\t\tHigh Limit alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_SENSOR_OPEN)
-                    ADI_SENSE_LOG_INFO("\t\t\tSensor Fault alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_REF_DETECT)
-                    ADI_SENSE_LOG_INFO("\t\t\tReference Detection alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_CONFIG_ERR)
-                    ADI_SENSE_LOG_INFO("\t\t\tConfiguration Error alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_ERR)
-                    ADI_SENSE_LOG_INFO("\t\t\tLook-Up Table Error alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_SENSOR_NOT_READY)
-                    ADI_SENSE_LOG_INFO("\t\t\tSensor Not Ready alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_COMP_NOT_READY)
-                    ADI_SENSE_LOG_INFO("\t\t\tCompensation Channel Not Ready alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_UNDER_VOLTAGE)
-                    ADI_SENSE_LOG_INFO("\t\t\tUnder Voltage alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_OVER_VOLTAGE)
-                    ADI_SENSE_LOG_INFO("\t\t\tOver Voltage alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_UNDER_RANGE)
-                    ADI_SENSE_LOG_INFO("\t\t\tUnder Look-Up Table Range alert detected");
-                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_OVER_RANGE)
-                    ADI_SENSE_LOG_INFO("\t\t\tOver Look-Up Table Range alert detected");
-            }
-        }
-    }
-}
-
-void utils_printSamples(
-    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
-    uint32_t nNumSamples)
-{
-    for (uint32_t i = 0; i < nNumSamples; i++)
-    {
-        ADI_SENSE_LOG_INFO("Sample # %2d Channel # %2d :: Raw %8d  :: Processed %.7f :: flags: %s %s",
-                           i+1,
-                           pSampleBuffer[i].channelId,
-                           pSampleBuffer[i].rawValue,
-                           pSampleBuffer[i].processedValue,
-                           pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ERROR ? "ERROR" : "",
-                           pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ALERT ? "ALERT" : "");
-    }
-}
-
-static void gpioCallbackFn(ADI_SENSE_GPIO_PIN ePinId, void * pArg)
-{
-    volatile bool_t *pbFlag = (volatile bool_t *)pArg;
-    *pbFlag = true;
-}
-
-ADI_SENSE_RESULT utils_registerCallbacks(
-    ADI_SENSE_DEVICE_HANDLE hDevice,
-    volatile bool_t *pbDataReady,
-    volatile bool_t *pbError,
-    volatile bool_t *pbAlert)
-{
-    ADI_SENSE_RESULT res;
-
-    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
-                                         gpioCallbackFn, (void *)pbDataReady);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to register DATAREADY callback");
-        return res;
-    }
-
-    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
-                                         gpioCallbackFn, (void *)pbError);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to register ERROR callback");
-        return res;
-    }
-
-    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
-                                         gpioCallbackFn, (void *)pbAlert);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to register ALERT callback");
-        return res;
-    }
-
-    return ADI_SENSE_SUCCESS;
-}
-
-ADI_SENSE_RESULT utils_deregisterCallbacks(
-    ADI_SENSE_DEVICE_HANDLE hDevice)
-{
-    ADI_SENSE_RESULT res;
-
-    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
-                                         NULL, NULL);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to deregister DATAREADY callback");
-        return res;
-    }
-
-    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
-                                         NULL, NULL);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to deregister ERROR callback");
-        return res;
-    }
-
-    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
-                                         NULL, NULL);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_INFO("Failed to deregister ALERT callback");
-        return res;
-    }
-
-    return ADI_SENSE_SUCCESS;
-}
-
-ADI_SENSE_RESULT utils_runMeasurement(
-    ADI_SENSE_DEVICE_HANDLE hDevice,
-    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode)
-{
-    ADI_SENSE_RESULT res;
-
-    volatile bool_t bDataReady = false;
-    volatile bool_t bError = false;
-    volatile bool_t bAlert = false;
-    res = utils_registerCallbacks(hDevice, &bDataReady, &bError, &bAlert);
-    if (res != ADI_SENSE_SUCCESS)
-        return res;
-
-    /*
-     * Retrieve the number of samples per cycle, per DATAREADY pulse, etc. for this configuration.
-     */
-    ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
-    ADI_SENSE_1000_DATAREADY_MODE eDataReadyMode;
-    uint32_t nSamplesPerDataready;
-    uint32_t nSamplesPerCycle;
-    res = adi_sense_1000_GetDataReadyModeInfo(hDevice,
-                                              eMeasurementMode,
-                                              &eOperatingMode,
-                                              &eDataReadyMode,
-                                              &nSamplesPerDataready,
-                                              &nSamplesPerCycle);
-    if (res != ADI_SENSE_SUCCESS)
-        return res;
-
-    /*
-     * Allocate a buffer to store the samples retrieved on each DATAREADY pulse
-     * However, if the DATAREADY pulse is per-conversion, allocate a bigger buffer
-     * to accumulate a full cycle of samples before printing them
-     */
-    ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
-    if (eDataReadyMode == ADI_SENSE_1000_DATAREADY_PER_CONVERSION)
-        pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) * nSamplesPerCycle);
-    else
-        pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) * nSamplesPerDataready);
-    if (pSampleBuffer == NULL)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to allocate sample buffer");
-        return ADI_SENSE_NO_MEM;
-    }
-
-    /*
-     * Kick off the measurement cycle(s) here
-     */
-    res = adi_sense_StartMeasurement(hDevice, eMeasurementMode);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to start measurement");
-        return res;
-    }
-
-    /*
-     * Loop continuously unless operating mode is single-cycle
-     */
-    do {
-        ADI_SENSE_STATUS status;
-        uint32_t nCurrentSamples;
-        uint32_t nReturned;
-        nCurrentSamples = 0;
-
-        /*
-         * Accumulate the samples from a cycle and print them
-         * NOTE: requires a sufficient idle time between cycles to allow printing to occur
-         */
-        do {
-            /*
-             * Wait for the cycle to complete, continuously checking DATAREADY until it is asserted
-             */
-            while (! (bDataReady || bError))
-                ;
-
-            if (! bError)
-            {
-                /*
-                 * Retrieve the data samples from the measurement cycle, if no error has occurred
-                 */
-                bDataReady = false;
-                res = adi_sense_GetData(hDevice, eMeasurementMode, &pSampleBuffer[nCurrentSamples], nSamplesPerDataready, &nReturned);
-                nCurrentSamples += nReturned;
-                if (res != ADI_SENSE_SUCCESS)
-                {
-                    if (res == ADI_SENSE_INCOMPLETE)
-                    {
-                        /* For this case, let's get the device status and print
-                         * any samples we did get */
-                        ADI_SENSE_LOG_WARN("Failed to retrieve all requested data samples");
-                        break;
-                    }
-                    else
-                    {
-                        ADI_SENSE_LOG_WARN("Failed to retrieve data samples from device");
-                        return res;
-                    }
-                }
-            }
-        } while (!bError && (nCurrentSamples < nSamplesPerCycle));
-
-        /*
-         * Display the data samples
-         */
-        utils_printSamples(pSampleBuffer, nCurrentSamples);
-
-        /*
-         * Check and print device status if errors/alerts have been triggered
-         */
-        if (bError || bAlert)
-        {
-            res = adi_sense_GetStatus(hDevice, &status);
-            if (res != ADI_SENSE_SUCCESS)
-            {
-                ADI_SENSE_LOG_ERROR("Failed to retrieve device status");
-                return res;
-            }
-
-            if (status.deviceStatus &
-                (ADI_SENSE_DEVICE_STATUS_ERROR | ADI_SENSE_DEVICE_STATUS_ALERT))
-            {
-                utils_printStatus(&status);
-
-                /* Break out of the loop if any errors are raised */
-                if (bError)
-                    break;
-            }
-        }
-    } while (eOperatingMode != ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE);
-
-    res = adi_sense_StopMeasurement(hDevice);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to send stop measurement");
-        return res;
-    }
-
-    free(pSampleBuffer);
-
-    res = utils_deregisterCallbacks(hDevice);
-    if (res != ADI_SENSE_SUCCESS)
-        return res;
-
-    return ADI_SENSE_SUCCESS;
-}
-
-ADI_SENSE_RESULT utils_printCalTable(
-    ADI_SENSE_DEVICE_HANDLE hDevice)
-{
-    ADI_SENSE_RESULT res;
-    unsigned dataLen, nRows, nColumns, maxLen = 1024;
-
-    float *pCalDataBuffer = malloc(maxLen);
-    if (pCalDataBuffer == NULL)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to allocate calibration data buffer");
-        return ADI_SENSE_NO_MEM;
-    }
-
-    res = adi_sense_1000_ReadCalTable(hDevice,
-                                      pCalDataBuffer, maxLen,
-                                      &dataLen, &nRows, &nColumns);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to read calibration data");
-        free(pCalDataBuffer);
-        return res;
-    }
-
-    ADI_SENSE_LOG_INFO("Calibration Table:\r\n");
-    ADI_SENSE_LOG_INFO("%6s| %10s | %10s | %10s |", "index", "25", "-40", "85");
-    for (unsigned row = 0; row < nRows; row++)
-    {
-        ADI_SENSE_LOG_INFO("%6d| %10f | %10f | %10f |",
-                           row,
-                           pCalDataBuffer[(row * nColumns) + 0],
-                           pCalDataBuffer[(row * nColumns) + 1],
-                           pCalDataBuffer[(row * nColumns) + 2]);
-    }
-
-    free(pCalDataBuffer);
-    return ADI_SENSE_SUCCESS;
-}
+#include <stdlib.h>
+
+#include "utils.h"
+#include "inc/adi_sense_log.h"
+
+void utils_printStatus(
+    ADI_SENSE_STATUS *pStatus)
+{
+    ADI_SENSE_LOG_INFO("Status Summary:");
+
+    if (pStatus->deviceStatus == 0)
+    {
+        ADI_SENSE_LOG_INFO("\tNo errors detected");
+    }
+    else
+    {
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_BUSY)
+            ADI_SENSE_LOG_INFO("\tCommand running");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_DATAREADY)
+            ADI_SENSE_LOG_INFO("\tData ready");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive Errors - RESET REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_FIFO_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive FIFO Errors - ATTENTION REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_CONFIG_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive Configuration Errors - ATTENTION REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_LUT_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive Look-Up Table Errors - ATTENTION REQUIRED");
+
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR)
+        {
+            ADI_SENSE_LOG_INFO("\tActive Errors - ATTENTION REQUIRED");
+            ADI_SENSE_LOG_INFO("\t\tLast Error Code: %u (0x%X)",
+                               pStatus->errorCode, pStatus->errorCode);
+
+            if (pStatus->diagnosticsStatus == 0)
+            {
+                ADI_SENSE_LOG_INFO("\t\tNo diagnostics faults detected");
+            }
+            else
+            {
+                ADI_SENSE_LOG_INFO("\t\tActive diagnostics faults:");
+
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CHECKSUM_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal Checksum fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_COMMS_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal Communications fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_MONITOR_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tSupply Monitor fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_CAP_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tSupply Regulator Capacitor fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINM_UV_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tNegative Analog Input Under-Voltage fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINM_OV_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tNegative Analog Input Over-Voltage fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINP_UV_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tPositive Analog Input Under-Voltage fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_AINP_OV_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tPositive Analog Input Over-Voltage fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CONVERSION_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal ADC Conversions fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CALIBRATION_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal Device Calibrations fault detected");
+            }
+        }
+
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ALERT)
+        {
+            ADI_SENSE_LOG_INFO("\tActive Alerts - ATTENTION REQUIRED:");
+            ADI_SENSE_LOG_INFO("\t\tLast Alert Code: %u (0x%X)",
+                               pStatus->alertCode, pStatus->alertCode);
+
+            for (unsigned i = 0; i < ADI_SENSE_1000_MAX_CHANNELS; i++)
+            {
+                if (pStatus->channelAlerts[i] == 0)
+                    continue;
+
+                ADI_SENSE_LOG_INFO("\t\tChannel #%u:", i);
+                ADI_SENSE_LOG_INFO("\t\t\tLast Alert Code: %u (0x%X)",
+                                   pStatus->channelAlertCodes[i],
+                                   pStatus->channelAlertCodes[i]);
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_TIMEOUT)
+                    ADI_SENSE_LOG_INFO("\t\t\tTimeout alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_UNDER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tUnder Range alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_OVER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tOver Range alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LOW_LIMIT)
+                    ADI_SENSE_LOG_INFO("\t\t\tLow limit alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_HIGH_LIMIT)
+                    ADI_SENSE_LOG_INFO("\t\t\tHigh Limit alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_SENSOR_OPEN)
+                    ADI_SENSE_LOG_INFO("\t\t\tSensor Fault alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_REF_DETECT)
+                    ADI_SENSE_LOG_INFO("\t\t\tReference Detection alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_CONFIG_ERR)
+                    ADI_SENSE_LOG_INFO("\t\t\tConfiguration Error alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_ERR)
+                    ADI_SENSE_LOG_INFO("\t\t\tLook-Up Table Error alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_SENSOR_NOT_READY)
+                    ADI_SENSE_LOG_INFO("\t\t\tSensor Not Ready alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_COMP_NOT_READY)
+                    ADI_SENSE_LOG_INFO("\t\t\tCompensation Channel Not Ready alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_UNDER_VOLTAGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tUnder Voltage alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_OVER_VOLTAGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tOver Voltage alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_UNDER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tUnder Look-Up Table Range alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_OVER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tOver Look-Up Table Range alert detected");
+            }
+        }
+    }
+}
+
+void utils_printSamples(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t nNumSamples)
+{
+    for (uint32_t i = 0; i < nNumSamples; i++)
+    {
+        ADI_SENSE_LOG_INFO("Sample # %2d Channel # %2d :: Raw %8d  :: Processed %.7f :: flags: %s %s",
+                           i+1,
+                           pSampleBuffer[i].channelId,
+                           pSampleBuffer[i].rawValue,
+                           pSampleBuffer[i].processedValue,
+                           pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ERROR ? "ERROR" : "",
+                           pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ALERT ? "ALERT" : "");
+    }
+}
+
+void utils_printSamples_alt(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t nNumSamples)
+{
+    //for (uint32_t i = 0; i < nNumSamples; i++)
+    //{  
+    //temp_comp temp pressure himidity AccX AccY AccZ
+        ADI_SENSE_LOG_INFO("%8d\t%.5f\t%8d\t%.5f\t%8d\t%.5f\t%8d\t%.5f\t%8d\t%.5f\t%8d\t%.5f\t%8d\t%.5f\t",
+                           //temp_comp
+                           pSampleBuffer[0].rawValue,
+                           pSampleBuffer[0].processedValue,
+                           //temp
+                           pSampleBuffer[1].rawValue,
+                           pSampleBuffer[1].processedValue,
+                           //pressure
+                           pSampleBuffer[2].rawValue,
+                           pSampleBuffer[2].processedValue,
+                           //humidity
+                           pSampleBuffer[3].rawValue,
+                           pSampleBuffer[3].processedValue,
+                           //AccX
+                           pSampleBuffer[4].rawValue,
+                           pSampleBuffer[4].processedValue,
+                           //AccY
+                           pSampleBuffer[5].rawValue,
+                           pSampleBuffer[5].processedValue,
+                           //AccZ
+                           pSampleBuffer[6].rawValue,
+                           pSampleBuffer[6].processedValue);
+    //}  
+}
+
+void utils_printSamples_pro(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t nNumSamples)
+{
+    //for (uint32_t i = 0; i < nNumSamples; i++)
+    //{  
+    //temp_comp temp pressure himidity AccX AccY AccZ
+        ADI_SENSE_LOG_INFO("%.5f %.5f %.5f %.5f %.5f %.5f %.5f",
+                           //temp_comp
+                           //pSampleBuffer[0].rawValue,
+                           pSampleBuffer[0].processedValue,
+                           //temp
+                           //pSampleBuffer[1].rawValue,
+                           pSampleBuffer[1].processedValue,
+                           //pressure
+                           //pSampleBuffer[2].rawValue,
+                           pSampleBuffer[2].processedValue,
+                           //humidity
+                           //pSampleBuffer[3].rawValue,
+                           pSampleBuffer[3].processedValue,
+                           //AccX
+                           //pSampleBuffer[4].rawValue,
+                           pSampleBuffer[4].processedValue,
+                           //AccY
+                           //pSampleBuffer[5].rawValue,
+                           pSampleBuffer[5].processedValue,
+                           //AccZ
+                           //pSampleBuffer[6].rawValue,
+                           pSampleBuffer[6].processedValue);
+    //}  
+}
+
+static void gpioCallbackFn(ADI_SENSE_GPIO_PIN ePinId, void * pArg)
+{
+    volatile bool_t *pbFlag = (volatile bool_t *)pArg;
+    *pbFlag = true;
+}
+
+ADI_SENSE_RESULT utils_registerCallbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice,
+    volatile bool_t *pbDataReady,
+    volatile bool_t *pbError,
+    volatile bool_t *pbAlert)
+{
+    ADI_SENSE_RESULT res;
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+                                         gpioCallbackFn, (void *)pbDataReady);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to register DATAREADY callback");
+        return res;
+    }
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
+                                         gpioCallbackFn, (void *)pbError);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to register ERROR callback");
+        return res;
+    }
 
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
+                                         gpioCallbackFn, (void *)pbAlert);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to register ALERT callback");
+        return res;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+ADI_SENSE_RESULT utils_deregisterCallbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice)
+{
+    ADI_SENSE_RESULT res;
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+                                         NULL, NULL);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to deregister DATAREADY callback");
+        return res;
+    }
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
+                                         NULL, NULL);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to deregister ERROR callback");
+        return res;
+    }
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
+                                         NULL, NULL);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_INFO("Failed to deregister ALERT callback");
+        return res;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+ADI_SENSE_RESULT utils_runMeasurement(
+    ADI_SENSE_DEVICE_HANDLE hDevice,
+    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode)
+{
+    ADI_SENSE_RESULT res;
+
+    volatile bool_t bDataReady = false;
+    volatile bool_t bError = false;
+    volatile bool_t bAlert = false;
+    res = utils_registerCallbacks(hDevice, &bDataReady, &bError, &bAlert);
+    if (res != ADI_SENSE_SUCCESS)
+        return res;
+
+    /*
+     * Retrieve the number of samples per cycle, per DATAREADY pulse, etc. for this configuration.
+     */
+    ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
+    ADI_SENSE_1000_DATAREADY_MODE eDataReadyMode;
+    uint32_t nSamplesPerDataready;
+    uint32_t nSamplesPerCycle;
+    res = adi_sense_1000_GetDataReadyModeInfo(hDevice,
+                                              eMeasurementMode,
+                                              &eOperatingMode,
+                                              &eDataReadyMode,
+                                              &nSamplesPerDataready,
+                                              &nSamplesPerCycle);
+    if (res != ADI_SENSE_SUCCESS)
+        return res;
+
+    /*
+     * Allocate a buffer to store the samples retrieved on each DATAREADY pulse
+     * However, if the DATAREADY pulse is per-conversion, allocate a bigger buffer
+     * to accumulate a full cycle of samples before printing them
+     */
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
+    if (eDataReadyMode == ADI_SENSE_1000_DATAREADY_PER_CONVERSION)
+        pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) * nSamplesPerCycle);
+    else
+        pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) * nSamplesPerDataready);
+    if (pSampleBuffer == NULL)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to allocate sample buffer");
+        return ADI_SENSE_NO_MEM;
+    }
+
+    /*
+     * Kick off the measurement cycle(s) here
+     */
+    res = adi_sense_StartMeasurement(hDevice, eMeasurementMode);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to start measurement");
+        return res;
+    }
+
+    /*
+     * Loop continuously unless operating mode is single-cycle
+     */
+    do {
+        ADI_SENSE_STATUS status;
+        uint32_t nCurrentSamples;
+        uint32_t nReturned;
+        nCurrentSamples = 0;
+
+        /*
+         * Accumulate the samples from a cycle and print them
+         * NOTE: requires a sufficient idle time between cycles to allow printing to occur
+         */
+        do {
+            /*
+             * Wait for the cycle to complete, continuously checking DATAREADY until it is asserted
+             */
+            while (! (bDataReady || bError))
+                ;
+
+            if (! bError)
+            {
+                /*
+                 * Retrieve the data samples from the measurement cycle, if no error has occurred
+                 */
+                bDataReady = false;
+                res = adi_sense_GetData(hDevice, eMeasurementMode, &pSampleBuffer[nCurrentSamples], nSamplesPerDataready, &nReturned);
+                nCurrentSamples += nReturned;
+                if (res != ADI_SENSE_SUCCESS)
+                {
+                    if (res == ADI_SENSE_INCOMPLETE)
+                    {
+                        /* For this case, let's get the device status and print
+                         * any samples we did get */
+                        ADI_SENSE_LOG_WARN("Failed to retrieve all requested data samples");
+                        break;
+                    }
+                    else
+                    {
+                        ADI_SENSE_LOG_WARN("Failed to retrieve data samples from device");
+                        return res;
+                    }
+                }
+            }
+        } while (!bError && (nCurrentSamples < nSamplesPerCycle));
+
+        /*
+         * Display the data samples
+         */
+        //utils_printSamples(pSampleBuffer, nCurrentSamples);
+        //use alternative print utils
+        //utils_printSamples_alt(pSampleBuffer, nCurrentSamples);
+        utils_printSamples_pro(pSampleBuffer, nCurrentSamples);
+        /*
+         * Check and print device status if errors/alerts have been triggered
+         */
+        if (bError || bAlert)
+        {
+            res = adi_sense_GetStatus(hDevice, &status);
+            if (res != ADI_SENSE_SUCCESS)
+            {
+                ADI_SENSE_LOG_ERROR("Failed to retrieve device status");
+                return res;
+            }
+
+            if (status.deviceStatus &
+                (ADI_SENSE_DEVICE_STATUS_ERROR | ADI_SENSE_DEVICE_STATUS_ALERT))
+            {
+                utils_printStatus(&status);
+
+                /* Break out of the loop if any errors are raised */
+                if (bError)
+                    break;
+            }
+        }
+    } while (eOperatingMode != ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE);
+
+    res = adi_sense_StopMeasurement(hDevice);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to send stop measurement");
+        return res;
+    }
+
+    free(pSampleBuffer);
+
+    res = utils_deregisterCallbacks(hDevice);
+    if (res != ADI_SENSE_SUCCESS)
+        return res;
+
+    return ADI_SENSE_SUCCESS;
+}
+
+ADI_SENSE_RESULT utils_printCalTable(
+    ADI_SENSE_DEVICE_HANDLE hDevice)
+{
+    ADI_SENSE_RESULT res;
+    unsigned dataLen, nRows, nColumns, maxLen = 1024;
+
+    float *pCalDataBuffer = malloc(maxLen);
+    if (pCalDataBuffer == NULL)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to allocate calibration data buffer");
+        return ADI_SENSE_NO_MEM;
+    }
+
+    res = adi_sense_1000_ReadCalTable(hDevice,
+                                      pCalDataBuffer, maxLen,
+                                      &dataLen, &nRows, &nColumns);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to read calibration data");
+        free(pCalDataBuffer);
+        return res;
+    }
+
+    ADI_SENSE_LOG_INFO("Calibration Table:\r\n");
+    ADI_SENSE_LOG_INFO("%6s| %10s | %10s | %10s |", "index", "25", "-40", "85");
+    for (unsigned row = 0; row < nRows; row++)
+    {
+        ADI_SENSE_LOG_INFO("%6d| %10f | %10f | %10f |",
+                           row,
+                           pCalDataBuffer[(row * nColumns) + 0],
+                           pCalDataBuffer[(row * nColumns) + 1],
+                           pCalDataBuffer[(row * nColumns) + 2]);
+    }
+
+    free(pCalDataBuffer);
+    return ADI_SENSE_SUCCESS;
+}
+
--- a/common/utils.h	Thu Jan 25 16:00:23 2018 +0000
+++ b/common/utils.h	Fri Aug 24 08:58:48 2018 +0000
@@ -1,46 +1,56 @@
-#ifndef __UTILS_H__
-#define __UTILS_H__
-
-#include "inc/adi_sense_api.h"
-#include "inc/adi_sense_1000/adi_sense_1000_api.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Utility function to print the status read from the ADI Sense device */
-void utils_printStatus(
-    ADI_SENSE_STATUS *pStatus);
-
-/* Utility function to print data samples read from the ADI Sense device */
-void utils_printSamples(
-    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
-    uint32_t numSamples);
-
-/* Utility function to register callbacks for ADI Sense device notification signals  */
-ADI_SENSE_RESULT utils_registerCallbacks(
-    ADI_SENSE_DEVICE_HANDLE hDevice,
-    volatile bool_t *pbDataReady,
-    volatile bool_t *pbError,
-    volatile bool_t *pbAlert);
-
-/* Utility function to de-register callbacks for ADI Sense device notification signals */
-ADI_SENSE_RESULT utils_deregisterCallbacks(
-    ADI_SENSE_DEVICE_HANDLE hDevice);
-
-/* Utility function to run measurements on ADI Sense device, according to its current
- * configuration, and display data samples and device status following each cycle */
-ADI_SENSE_RESULT utils_runMeasurement(
-    ADI_SENSE_DEVICE_HANDLE hDevice,
-    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode);
- 
-/* Utility function to retrieve and print the factory calibration coefficients table from the ADI Sense device */
-ADI_SENSE_RESULT utils_printCalTable(
-    ADI_SENSE_DEVICE_HANDLE hDevice);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UTILS_H__ */
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include "inc/adi_sense_api.h"
+#include "inc/adi_sense_1000/adi_sense_1000_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Utility function to print the status read from the ADI Sense device */
+void utils_printStatus(
+    ADI_SENSE_STATUS *pStatus);
 
+/* Utility function to print data samples read from the ADI Sense device */
+void utils_printSamples(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t numSamples);
+    
+/* Alternative print utility */
+void utils_printSamples_alt(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t numSamples);
+    
+/* Alternative print utility */
+void utils_printSamples_pro(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t numSamples);
+    
+/* Utility function to register callbacks for ADI Sense device notification signals  */
+ADI_SENSE_RESULT utils_registerCallbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice,
+    volatile bool_t *pbDataReady,
+    volatile bool_t *pbError,
+    volatile bool_t *pbAlert);
+
+/* Utility function to de-register callbacks for ADI Sense device notification signals */
+ADI_SENSE_RESULT utils_deregisterCallbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice);
+
+/* Utility function to run measurements on ADI Sense device, according to its current
+ * configuration, and display data samples and device status following each cycle */
+ADI_SENSE_RESULT utils_runMeasurement(
+    ADI_SENSE_DEVICE_HANDLE hDevice,
+    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode);
+ 
+/* Utility function to retrieve and print the factory calibration coefficients table from the ADI Sense device */
+ADI_SENSE_RESULT utils_printCalTable(
+    ADI_SENSE_DEVICE_HANDLE hDevice);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTILS_H__ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/JENKINS_AUTOGEN_PLATFORM.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,7 @@
+#ifndef _JENKINS_AUTOGEN_PLATFORM_H_
+#define _JENKINS_AUTOGEN_PLATFORM_H_
+
+#define PROSWIFT //#define MYSWIFT
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/adisense1000_boot.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,24 @@
+#ifndef __ADISENSE1000_BOOT_
+#define __ADISENSE1000_BOOT_
+
+#include "adi_sense_api.h"
+#include "pc_interface/pc_serial.h"
+#include "mbed.h"
+#include "pc_interface/pc_interface.h"
+
+//config structs for channels
+extern ADI_SENSE_CONFIG adi_sense_config;
+
+/*
+    Definitions
+*/
+
+/*
+    Function Prototypes
+*/
+
+//reset device to known state
+uint8_t Adisense1000_Boot(void);
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/ble_interface/bl652.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,50 @@
+#ifndef __BL652_H_
+#define __BL652_H_
+
+
+/******************************************************************************/
+/* Include Files                                                              */
+/******************************************************************************/
+
+#include <stdint.h>
+
+/******************************************************************************/
+/* BLE parameters                                                             */
+/******************************************************************************/
+
+//size of buffers used
+#define BLE_PACKET_SIZE 20
+
+//parameters for da14580
+#define RESET_LENGTH    10 //ms
+
+#define BLE_TX_PACKET_DELAY 100 //ms
+
+#define AT_COMMAND_DELIMITER '\r'
+
+#define AT_COMMAND_ERROR "ERROR"
+
+
+/******************************************************************************/
+/* Function Prototypes                                                        */
+/******************************************************************************/
+
+//boot BLE module
+uint32_t Bl652_Boot( void );
+
+//Write to BLE over UART
+uint32_t Bl652_Write( char *txBuffer, uint32_t byteCount );
+
+//Read from BLE over UART
+uint32_t Bl652_Read( char *rxBuffer, uint32_t byteCount );
+
+//setup for callback based read
+uint32_t Bl652_SetupReadCb( void *rxBuffer, uint32_t maxSize, volatile bool *bMessageReadFlag );
+
+//clear read callback
+uint32_t Bl652_ClearCb( void );
+
+//wait until BLE is awake
+uint32_t Bl652_WaitUntilAvailable( void );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/ble_interface/ble_interface.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,27 @@
+#ifndef __BLE_INTERFACE_H_
+#define __BLE_INTERFACE_H_
+
+#include "mbed.h"
+#include "adi_sense_api.h"
+#include "inc/adi_sense_1000/adi_sense_1000_api.h"
+#include "myproswift_error_codes.h"
+#include "myproswift_periph.h"
+#include "bl652.h"
+
+/*
+    Definitions
+*/
+
+#define MAX_MEASUREMENT_CYCLES 1
+
+#define BLE_PACKET_SIZE 20
+#define MEASUREMENT_NAME_MAX_LEN 15
+#define UNIT_NAME_MAX_LEN 3
+#define FIELD_NAMES_MAX_SIZE 16
+
+
+//parse a ble command, reading further bytes as required
+uint32_t Ble_ParseCommand( char *bleRxBuffer );
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bootloader.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,18 @@
+
+#ifndef __BOOTLOADER_H_
+#define __BOOTLOADER_H_
+
+
+#include <stdint.h>
+
+#include "mbed.h"
+
+
+#define BOOTLOADER_FLAG_BACKUP_REG 0x00
+
+
+// Enter bootloader mode
+void Bootloader_Init( void );
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/communications.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,28 @@
+#ifndef __COMMUNICATIONS_H_
+#define __COMMUNICATIONS_H_
+
+#include "mbed.h"
+
+/*
+    Definitions
+*/
+
+#define TIMEOUT_3_SEC 3.0f
+
+/*
+    Function Prototypes
+*/
+
+//init a uart handle
+int Uart_Init( Serial &serialHandle, int baudrate );
+
+//write to serial comms using comms handle
+int Uart_Write( Serial &serialHandle, const char* txBuffer, unsigned int length );
+
+//read from serial comms using comms handle
+int Uart_ReadCb( Serial &serialHandle, void ( *callback )( void ) );
+
+//clear attached callback
+int Uart_ClearCb( Serial &serialHandle );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/eeprom_virtual/eeprom.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,130 @@
+/**
+  ******************************************************************************
+  * @file    EEPROM/EEPROM_Emulation/inc/eeprom.h 
+  * @author  MCD Application Team
+  * @brief   This file contains all the functions prototypes for the EEPROM 
+  *          emulation firmware library.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright © 2017 STMicroelectronics International N.V. 
+  * All rights reserved.</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without 
+  * modification, are permitted, provided that the following conditions are met:
+  *
+  * 1. Redistribution of source code must retain the above copyright notice, 
+  *    this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright notice,
+  *    this list of conditions and the following disclaimer in the documentation
+  *    and/or other materials provided with the distribution.
+  * 3. Neither the name of STMicroelectronics nor the names of other 
+  *    contributors to this software may be used to endorse or promote products 
+  *    derived from this software without specific written permission.
+  * 4. This software, including modifications and/or derivative works of this 
+  *    software, must execute solely and exclusively on microcontroller or
+  *    microprocessor devices manufactured by or for STMicroelectronics.
+  * 5. Redistribution and use of this software other than as permitted under 
+  *    this license is void and will automatically terminate your rights under 
+  *    this license. 
+  *
+  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 
+  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 
+  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
+  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 
+  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
+  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __EEPROM_H
+#define __EEPROM_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx_hal.h"
+
+/* Exported constants --------------------------------------------------------*/
+
+
+
+/* EEPROM emulation firmware error codes */
+#define EE_OK      (uint32_t)HAL_OK
+#define EE_ERROR   (uint32_t)HAL_ERROR
+#define EE_BUSY    (uint32_t)HAL_BUSY
+#define EE_TIMEOUT (uint32_t)HAL_TIMEOUT
+
+/* Define the size of the sectors to be used */
+#define PAGE_SIZE               (uint32_t)0x4000  /* Page size = 16KByte */
+
+/* Device voltage range supposed to be [2.7V to 3.6V], the operation will 
+   be done by word  */
+#define VOLTAGE_RANGE           (uint8_t)VOLTAGE_RANGE_3
+
+/* EEPROM start address in Flash */
+#define EEPROM_START_ADDRESS  ((uint32_t)0x08008000) /* EEPROM emulation start address:
+                                                  from sector2 : after 16KByte of used 
+                                                  Flash memory */
+
+/* Pages 0 and 1 base and end addresses */
+#define PAGE0_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
+#define PAGE0_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
+#define PAGE0_ID               FLASH_SECTOR_2
+
+#define PAGE1_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + PAGE_SIZE))
+#define PAGE1_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))
+#define PAGE1_ID               FLASH_SECTOR_3
+
+/* Used Flash pages for EEPROM emulation */
+#define PAGE0                 ((uint16_t)0x0000)
+#define PAGE1                 ((uint16_t)0x0001) /* Page nb between PAGE0_BASE_ADDRESS & PAGE1_BASE_ADDRESS*/
+
+/* No valid page define */
+#define NO_VALID_PAGE         ((uint16_t)0x00AB)
+
+/* Page status definitions */
+#define ERASED                ((uint16_t)0xFFFF)     /* Page is empty */
+#define RECEIVE_DATA          ((uint16_t)0xEEEE)     /* Page is marked to receive data */
+#define VALID_PAGE            ((uint16_t)0x0000)     /* Page containing valid data */
+
+/* Valid pages in read and write defines */
+#define READ_FROM_VALID_PAGE  ((uint8_t)0x00)
+#define WRITE_IN_VALID_PAGE   ((uint8_t)0x01)
+
+/* Page full define */
+#define PAGE_FULL             ((uint8_t)0x80)
+
+/* Variables' number */
+#define NB_OF_VAR             ((uint8_t)0x02)
+
+//not sure why this is needed by the eeprom library
+static uint16_t VirtAddVarTab[NB_OF_VAR] = {0x00, 0x01};
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+	
+uint16_t EE_Init(void); 
+uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
+uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EEPROM_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/led.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,19 @@
+#ifndef __LED_H_
+#define __LED_H_
+
+#include "myproswift_periph.h"
+
+#define LED_BLINK_PERIOD	0.2//s
+
+// Blink led to indicate device is booting
+void Led_Boot( void );
+
+// Hold led on to indicate boot complete
+void Led_Idle( void );
+
+// Function to toggle led
+void Led_On( bool_t state );
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/myproswift_error_codes.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,42 @@
+
+
+/**
+ * @file my_proswift_error_codes.h
+ * @author Jake Greaves
+ * @date 05 Feb 2018
+ * @brief Error codes used by both interfaces
+ */
+
+#ifndef __MY_PROSWIFT_ERROR_CODES_H_
+#define __MY_PROSWIFT_ERROR_CODES_H_
+
+
+/**
+ * @brief Error values that may be returned.
+ */
+enum ErrorType {
+    NO_ERROR 					= 0x00,
+    NO_ERROR_BOOTLOADER				= 0x01,
+    ERROR_NO_COMMAND_MATCHED 			= 0x10,
+    ERROR_EXPECTED_DELIMITER 			= 0x11,
+    ERROR_SET_CONFIG				= 0x20,
+    ERROR_UPDATE_CONFIG				= 0x21,
+    ERROR_EXPECTED_COMMAND			= 0x22,
+    ERROR_GET_DRDY_INFO				= 0x30,
+    ERROR_ALLOCATE_BUFFER			= 0x31,
+    ERROR_GPIO_CALLBACK_REG 			= 0x32,
+    ERROR_START_MEASUREMENT			= 0x33,
+    ERROR_GET_DATA				= 0x34,
+    ERROR_SAMPLE_COUNT_MISMATCH		= 0x35,
+    ERROR_STREAM_NOT_STARTED			= 0x36,
+    ERROR_STOP_MEASUREMENT			= 0x37,
+    ERROR_EXPECTED_CHANNEL 			= 0x40,
+    ERROR_EXPECTED_KEYWORD			= 0x41,
+    ERROR_EXPECTED_VALUE			= 0x42,
+    ERROR_CONVERSION_FAILED			= 0x43,
+    ERROR_ATTR_NOT_SUPPORTED_ON_CHANNEL 	= 0x44,
+    ERROR_UNDEFINED				= 0xF0
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/myproswift_eval.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,20 @@
+#ifndef __MYSWIFT_H_
+#define __MYSWIFT_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/*
+    Definitions
+*/
+
+#define MSG_BUFFER_MAX_SIZE 500
+#define BLE_BUFFER_MAX_SIZE 20
+
+/*
+    Function Prototypes
+*/
+
+int32_t MyProSwift_Command( bool bleActive );
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/myproswift_periph.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,157 @@
+#ifndef __MYSWIFT_PERIPH_H_
+#define __MYSWIFT_PERIPH_H_
+
+
+#include "mbed.h"
+#include "adi_sense_api.h"
+#include "JENKINS_AUTOGEN_PLATFORM.h"
+
+
+#ifdef MYSWIFT
+#define DEVICE_NAME "ADI MySwift"
+#define FIRMWARE_VERSION "Version 1.0"
+#endif
+
+
+#ifdef PROSWIFT
+#define DEVICE_NAME "ADI ProSwift"
+#define FIRMWARE_VERSION "Version 1.0"
+#endif
+
+
+#if defined(MYSWIFT) && defined(PROSWIFT)
+#error "Only one platform must be defined"
+#endif
+
+
+#if !(defined(MYSWIFT) || defined(PROSWIFT))
+#error "At least one platform must be defined"
+#endif
+
+#define BL652
+
+/*
+ ******************************************************************************
+ * ADISense1000
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef MYSWIFT
+#define SENSE_SPI_FREQUENCY  	2000000
+#define SENSE_SPI_MOSI   	PA_7
+#define SENSE_SPI_MISO    	PA_6
+#define SENSE_SPI_SCK     	PA_5
+#define SENSE_SPI_CS     	PC_7
+//pin declarations
+#define SENSE_RST_PIN     	PB_10
+#define SENSE_ERROR_PIN     	PB_3 
+#define SENSE_ALERT_PIN     	PB_5 
+#define SENSE_DREADY_PIN 	PB_4
+#endif
+
+
+#ifdef PROSWIFT
+//spi frequency
+#define SENSE_SPI_FREQUENCY  	2000000
+#define SENSE_SPI_MOSI   	SPI_MOSI
+#define SENSE_SPI_MISO    	SPI_MISO
+#define SENSE_SPI_SCK     	SPI_SCK
+#define SENSE_SPI_CS     	SPI_CS
+//pin declarations
+#define SENSE_RST_PIN     	PB_10
+#define SENSE_ERROR_PIN     	PB_3 
+#define SENSE_ALERT_PIN     	PB_5 
+#define SENSE_DREADY_PIN 	PB_4
+#endif
+
+/*
+ ******************************************************************************
+ * Bluetooth Low Energy
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef BL652
+
+#ifdef MYSWIFT
+//pin declarations
+#define BLE_RST_PIN     	PA_8
+#define BLE_RTS_PIN     	PA_0
+#define BLE_CTS_PIN     	PB_2
+//uart pins and baudrate
+#define BLE_BAUD_RATE 		115200
+#define BLE_SERIAL_TX 		PA_2
+#define BLE_SERIAL_RX 		PA_3
+//mode pins
+#define BLE_MODE_0_PIN 		PB_0
+#define BLE_MODE_1_PIN		PA_1
+#endif
+
+#ifdef PROSWIFT
+//pin declarations
+#define BLE_RST_PIN     	PA_0
+#define BLE_RTS_PIN     	PA_8
+#define BLE_CTS_PIN     	PA_10
+//uart pins and baudrate
+#define BLE_BAUD_RATE 		115200
+#define BLE_SERIAL_TX 		PA_2
+#define BLE_SERIAL_RX 		PA_3
+//mode pins
+#define BLE_MODE_0_PIN 		PB_0
+#define BLE_MODE_1_PIN		PA_4
+#endif
+
+#endif
+
+
+/*
+ ******************************************************************************
+ * PC Serial
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef MYSWIFT
+#define PC_UART_TX_PIN   PA_9
+#define PC_UART_RX_PIN   PA_10
+#define PC_UART_BAUDRATE 921600
+#endif
+
+
+#ifdef PROSWIFT
+#define PC_UART_TX_PIN   PA_11
+#define PC_UART_RX_PIN   PA_12
+#define PC_UART_BAUDRATE 115200
+#endif
+
+/*
+ ******************************************************************************
+ * Battery
+ *-----------------------------------------------------------------------------
+ */
+#ifdef MYSWIFT
+//#define VCC 				3.3
+//#define BATTERY_V_PIN 		PH_0
+#endif
+
+/*
+ ******************************************************************************
+ * Status LED
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef MYSWIFT
+#define STATUS_LED_PIN 		PC_8
+#endif
+
+#ifdef PROSWIFT
+#define STATUS_LED_PIN 		LED1
+#endif
+	 
+#endif
+
+/*
+ ******************************************************************************
+ * VIRT_EEPROM
+ *-----------------------------------------------------------------------------
+ */
+
+#undef VIRT_EEPROM
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/pc_interface/pc_conversions.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,346 @@
+/**
+ * @file pc_conversions.h
+ * @author Jake Greaves
+ * @date 15 Dec 2017
+ * @brief Conversions between config file values and register settings
+ */ 
+
+
+#ifndef __PC_CONVERSIONS_H_
+#define __PC_CONVERSIONS_H_
+
+
+#include "adi_sense_config_types.h"
+
+
+/*! Calculate sizeof struct array containing possible values */
+#if !defined(ARRAY_SIZE)
+#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
+#endif
+
+
+/*! Struct typedef of possible config values, coupled with equivalent register values */
+typedef struct {
+    	char *stringVal;
+    	int32_t structVal;
+} StringToStructVals;
+
+/*! Struct containing config file keyword, paired with the conversion struct array and the array size */
+struct keywordConvert {
+	char *stringEquiv;
+	StringToStructVals *valsConvert;
+	unsigned int valCount;
+};
+
+
+/*! ProductID Values */
+static StringToStructVals productIdVals[] = {
+	{"N/A", 				ADI_SENSE_PRODUCT_ID_1000},
+	{"0x0020", 				ADI_SENSE_PRODUCT_ID_1000}
+};
+
+/*! OperationalMode Values */
+static StringToStructVals operationalModeVals[] = {
+	{"N/A",        			ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE},
+	{"SingleCycle",        		ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE},
+	{"ContinuousConversion",  	ADI_SENSE_1000_OPERATING_MODE_CONTINUOUS},
+	{"MultiCycle",            	ADI_SENSE_1000_OPERATING_MODE_MULTICYCLE}
+};
+
+/*! PowerMode Values */
+static StringToStructVals powerModeVals[] = {
+	{"N/A",     			ADI_SENSE_1000_POWER_MODE_LOW},
+	{"Low",     			ADI_SENSE_1000_POWER_MODE_LOW},
+	{"Mid",     			ADI_SENSE_1000_POWER_MODE_MID},
+	{"Full",    			ADI_SENSE_1000_POWER_MODE_FULL}
+};
+
+/*! CycleTime Values */
+static StringToStructVals cycleTimeVals[] = {
+	{"N/A",     			0}
+};
+
+/*! DataReadyMode Values */
+static StringToStructVals dataReadyModeVals[] = {
+	{"N/A", 				ADI_SENSE_1000_DATAREADY_PER_CONVERSION},
+	{"PerMeasurement", 		ADI_SENSE_1000_DATAREADY_PER_CONVERSION},
+	{"PerCycle", 			ADI_SENSE_1000_DATAREADY_PER_CYCLE},
+	{"PerFifoFill", 			ADI_SENSE_1000_DATAREADY_PER_MULTICYCLE_BURST}
+};
+
+/*! GlobalDiagnostic Values */
+static StringToStructVals globalDiagnosticVals[] = {
+	{"N/A", 				1},
+	{"False", 				1},
+	{"True", 				0}
+};
+
+/*! MeasurementDiagnostic Values */
+static StringToStructVals measurementDiagnosticVals[] = {
+	{"N/A", 				1},
+	{"False", 				1},
+	{"True", 				0}
+};
+
+/*! DiagnosticFrequency Values */
+static StringToStructVals diagnosticFrequencyVals[] = {
+	{"N/A", 				ADI_SENSE_1000_OPEN_SENSOR_DIAGNOSTICS_DISABLED},
+	{"None", 				ADI_SENSE_1000_OPEN_SENSOR_DIAGNOSTICS_DISABLED},
+	{"PerCycle", 			ADI_SENSE_1000_OPEN_SENSOR_DIAGNOSTICS_PER_CYCLE},
+	{"Per100Cycles", 			ADI_SENSE_1000_OPEN_SENSOR_DIAGNOSTICS_PER_100_CYCLES},
+	{"Per1000Cycles",			ADI_SENSE_1000_OPEN_SENSOR_DIAGNOSTICS_PER_1000_CYCLES}
+};
+
+/*! EnableChannel Values */
+static StringToStructVals enableChannelVals[] = {
+	{"N/A", 				0},
+	{"False", 				0},
+	{"True",  				1}
+};
+
+/*! MeasurementsPerCycle Values */
+static StringToStructVals measurementsPerCycleVals[] = {
+	{"N/A", 				1}
+};
+
+/*! MeasurementsPerCycle Values */
+static StringToStructVals settlingTimeVals[] = {
+	{"N/A", 				0}
+};
+
+/*! PublishMeasurement Values */
+static StringToStructVals publishMeasurementVals[] = {
+	{"N/A", 				0},
+	{"False", 				1},
+	{"True",  				0}
+};
+/*! ChannelID Values */
+static StringToStructVals channelIdVals[] = {
+	{"N/A",             		ADI_SENSE_1000_CHANNEL_ID_NONE},
+	{"Cjc0",            		ADI_SENSE_1000_CHANNEL_ID_CJC_0},
+	{"Cjc1",            		ADI_SENSE_1000_CHANNEL_ID_CJC_1},
+	{"Sensor0",        		ADI_SENSE_1000_CHANNEL_ID_SENSOR_0},
+	{"Sensor1",        		ADI_SENSE_1000_CHANNEL_ID_SENSOR_1},
+	{"Sensor2",        		ADI_SENSE_1000_CHANNEL_ID_SENSOR_2},
+	{"Sensor3",        		ADI_SENSE_1000_CHANNEL_ID_SENSOR_3},
+	{"Voltage0",       		ADI_SENSE_1000_CHANNEL_ID_VOLTAGE_0},
+	{"Current0",        		ADI_SENSE_1000_CHANNEL_ID_CURRENT_0},
+	{"I2c0",           		ADI_SENSE_1000_CHANNEL_ID_I2C_0},
+	{"I2c1",           		ADI_SENSE_1000_CHANNEL_ID_I2C_1},
+	{"Spi0",           		ADI_SENSE_1000_CHANNEL_ID_SPI_0},
+	{"Spi1",           		ADI_SENSE_1000_CHANNEL_ID_SPI_1},
+	{"Spi2",           		ADI_SENSE_1000_CHANNEL_ID_SPI_2}
+};
+
+/*! UnitTranslation Values */
+static StringToStructVals unitTranslationVals[] = {
+	{"N/A",         			ADI_SENSE_1000_MEASUREMENT_UNIT_DEFAULT},
+	{"Celsius",         		ADI_SENSE_1000_MEASUREMENT_UNIT_CELSIUS},
+	{"Fahrenheit",      		ADI_SENSE_1000_MEASUREMENT_UNIT_FAHRENHEIT},
+	{"Psi",         			ADI_SENSE_1000_MEASUREMENT_UNIT_DEFAULT}, //handle as default
+	{"%",      				ADI_SENSE_1000_MEASUREMENT_UNIT_DEFAULT}	//handle as default
+};
+
+/*! SensorID Values */
+static StringToStructVals sensorVals[] = {
+	{"N/A",  				ADI_SENSE_1000_ADC_SENSOR_THERMOCOUPLE_T_DEF_L1},
+	{"Thermocouple.T.Def.L1",  	ADI_SENSE_1000_ADC_SENSOR_THERMOCOUPLE_T_DEF_L1},
+	{"Thermocouple.J.Def.L1",  	ADI_SENSE_1000_ADC_SENSOR_THERMOCOUPLE_J_DEF_L1},
+	{"Thermocouple.K.Def.L1",  	ADI_SENSE_1000_ADC_SENSOR_THERMOCOUPLE_K_DEF_L1},
+	
+	{"RTD.2W.PT100.Def.L1",   	ADI_SENSE_1000_ADC_SENSOR_RTD_2WIRE_PT100_DEF_L1},
+	{"RTD.2W.PT1000.Def.L1",  	ADI_SENSE_1000_ADC_SENSOR_RTD_2WIRE_PT1000_DEF_L1},
+	{"RTD.3W.PT100.Def.L1", 	ADI_SENSE_1000_ADC_SENSOR_RTD_3WIRE_PT100_DEF_L1},
+	{"RTD.3W.PT1000.Def.L1", 	ADI_SENSE_1000_ADC_SENSOR_RTD_3WIRE_PT1000_DEF_L1},
+	{"RTD.4W.PT100.Def.L1", 	ADI_SENSE_1000_ADC_SENSOR_RTD_4WIRE_PT100_DEF_L1},
+	{"RTD.4W.PT1000.Def.L1", 	ADI_SENSE_1000_ADC_SENSOR_RTD_4WIRE_PT1000_DEF_L1},
+	
+	{"Thermistor.10K.A.Def.L1", 	ADI_SENSE_1000_ADC_SENSOR_THERMISTOR_A_10K_DEF_L1},
+	{"Thermistor.10K.B.Def.L1", 	ADI_SENSE_1000_ADC_SENSOR_THERMISTOR_B_10K_DEF_L1},
+	
+	{"Voltage.Pressure.A.Def.L1", ADI_SENSE_1000_ADC_SENSOR_VOLTAGE_PRESSURE_HONEYWELL_TRUSTABILITY},
+	{"Voltage.Pressure.B.Def.L1", ADI_SENSE_1000_ADC_SENSOR_VOLTAGE_PRESSURE_AMPHENOL_NPA300X},
+	
+	{"Current.Pressure.A.Def.L1", ADI_SENSE_1000_ADC_SENSOR_CURRENT_PRESSURE_HONEYWELL_PX2},
+	
+	{"I2C.Pressure.A.Def.L1", 	ADI_SENSE_1000_I2C_SENSOR_HUMIDITY_HONEYWELL_HUMIDICON},
+	{"I2C.Pressure.B.Def.L1", 	ADI_SENSE_1000_I2C_SENSOR_HUMIDITY_SENSIRION_SHT3X},
+	
+	{"SPI.Pressure.A.Def.L1", 	ADI_SENSE_1000_SPI_SENSOR_PRESSURE_HONEYWELL_TRUSTABILITY},
+	{"SPI.Accelerometer.A.Def.L1",ADI_SENSE_1000_SPI_SENSOR_ACCELEROMETER_ADI_ADXL362}
+};
+
+/*! MeasurementMaxValue Values */
+static StringToStructVals measurementMaxVals[] = {
+	{"N/A", 				0}
+};
+
+/*! MeasurementMinValue Values */
+static StringToStructVals measurementMinVals[] = {
+	{"N/A", 				0}
+};
+
+/*! Gain Values */
+static StringToStructVals gainVals[] = {
+	{"N/A", 				ADI_SENSE_1000_ADC_GAIN_1X},
+	{"1", 				ADI_SENSE_1000_ADC_GAIN_1X},
+	{"2",					ADI_SENSE_1000_ADC_GAIN_2X},
+	{"4", 				ADI_SENSE_1000_ADC_GAIN_4X},
+	{"8", 				ADI_SENSE_1000_ADC_GAIN_8X},
+	{"16", 				ADI_SENSE_1000_ADC_GAIN_16X},
+	{"32", 				ADI_SENSE_1000_ADC_GAIN_32X},
+	{"64", 				ADI_SENSE_1000_ADC_GAIN_64X},
+	{"128", 				ADI_SENSE_1000_ADC_GAIN_128X}
+};
+
+/*! CurrentOutput Values */
+static StringToStructVals currentOutputLevelVals[] = {
+	{"N/A", 				ADI_SENSE_1000_ADC_EXC_CURRENT_NONE},
+	{"0.00005", 			ADI_SENSE_1000_ADC_EXC_CURRENT_50uA},
+	{"0.0001", 				ADI_SENSE_1000_ADC_EXC_CURRENT_100uA},
+	{"0.00025", 			ADI_SENSE_1000_ADC_EXC_CURRENT_250uA},
+	{"0.0005", 				ADI_SENSE_1000_ADC_EXC_CURRENT_500uA},
+	{"0.00075", 			ADI_SENSE_1000_ADC_EXC_CURRENT_750uA},
+	{"0.001", 				ADI_SENSE_1000_ADC_EXC_CURRENT_1000uA}
+};
+
+/*! FilterType Values */
+static StringToStructVals filterTypeVals[] = {
+	{"N/A", 				ADI_SENSE_1000_ADC_FILTER_SINC4},
+	{"Sinc.4", 				ADI_SENSE_1000_ADC_FILTER_SINC4},
+	{"FIR.20SPS", 			ADI_SENSE_1000_ADC_FILTER_FIR_20SPS},
+	{"FIR.25SPS", 			ADI_SENSE_1000_ADC_FILTER_FIR_25SPS}
+};
+
+/*! FS Values */
+static StringToStructVals fsVals[] = {
+	{"N/A", 				0}
+};
+
+/*! Truth table used to determine reference settings due to differences in header and config file*/
+#define REF_SELECT_REFIN1		"Refin1"
+#define REF_SELECT_REFIN2		"Refin2"
+#define REF_SELECT_INTERNAL		"Internal"
+
+/*! ReferenceResistorSelect Values*/
+#define REF_RES_SELECT_INTERNAL	"Internal"
+#define REF_RES_SELECT_EXTERNAL	"External"
+#define REF_RES_SELECT_NA		"N/A"
+
+/*! ReferenceDisable Values */
+static StringToStructVals referenceDisableBufferVals[] = {
+	{"N/A",     			0},
+	{"False", 				0},
+	{"True",  				1}
+};
+
+/*! EnableVbias Values */
+static StringToStructVals enableVbiasVals[] = {
+	{"N/A",     			0},
+	{"False", 				0},
+	{"True",  				1}
+};
+
+/*! DeviceAddress Values */
+static StringToStructVals deviceAddressVals[] = {
+	{"N/A",     			0}
+};
+
+
+/*! Enum to identify the keyword being parsed. This relates directly to keywordConvert[]*/
+enum CONFIG_ATTRIBUTE {
+	PRODUCT_ID = 0,
+	OPERATIONAL_MODE,
+	POWER_MODE,
+	CYCLE_TIME,
+	DATA_READY_MODE,
+	GLOBAL_DIAGNOSTICS,
+	MEASUREMENT_SPECIFIC_DIAGNOSTICS,
+	DIAGNOSTIC_MEASUREMENT_FREQUENCY,
+	
+	MEASUREMENT_ENABLE,
+	MEASUREMENTS_PER_CYCLE,
+	SETTLING_TIME,
+	SENSOR_TYPE,
+	MEASUREMENT_MAX_VALUE,
+	MEASUREMENT_MIN_VALUE,
+	GAIN,
+	VBIAS_ENABLE,
+	EXCITATION_CURRENT,
+	REFERENCE,
+	FILTER_TYPE,
+	FILTER_FS,
+	ASSIGNED_COMPENSATION_MEASUREMENT_CHANNEL,    
+	PUBLISH_MEASUREMENT,
+	DISPLAY_UNIT,
+	
+	DEVICE_ADDRESS,
+	//NOT NEEDED FOR FIRST SAMPLING
+	/*
+	READ_COMMAND,
+	CONFIG_COMMAND,
+	NUMBER_OF_BITS,
+	FRAME_WIDTH,
+	LEFT_ALIGNMENT,
+	DATA_ENDIANNESS,
+	OFFSET,
+	CODING,
+	CPOL_CPHA,
+	*/
+	
+	//size of enum
+	ENUM_ATTRIBUTE_SIZE
+};
+
+
+/*! Struct used to match a keyword from the config file and locate a struct array of possible values*/
+static struct keywordConvert keywordConvert[] = {
+	//string               				//string values to struct values//amount of possible string values
+	//device wide parameters
+	{"ProductID",                             	productIdVals,            	ARRAY_SIZE(productIdVals)},
+	{"OperationalMode",                       	operationalModeVals,      	ARRAY_SIZE(operationalModeVals)},
+	{"PowerMode",                             	powerModeVals,            	ARRAY_SIZE(powerModeVals)},
+	{"CycleTime",                             	cycleTimeVals,                ARRAY_SIZE(cycleTimeVals)},
+	{"DataReadyMode",                         	dataReadyModeVals,      	ARRAY_SIZE(dataReadyModeVals)},
+	{"GlobalDiagnostics",					globalDiagnosticVals,		ARRAY_SIZE(globalDiagnosticVals)},
+	{"MeasurementSpecificDiagnostics",			measurementDiagnosticVals,	ARRAY_SIZE(measurementDiagnosticVals)},
+	{"DiagnosticMeasurementFrequency",			diagnosticFrequencyVals,	ARRAY_SIZE(diagnosticFrequencyVals)},
+	
+	//channel parameters
+	{"MeasurementEnable",                       	enableChannelVals,        	ARRAY_SIZE(enableChannelVals)},
+	{"MeasurementsPerCycle",                    	measurementsPerCycleVals,     ARRAY_SIZE(measurementsPerCycleVals)},
+	{"SettlingTime",                    		settlingTimeVals,           	ARRAY_SIZE(settlingTimeVals)}, /*< Requires two arguments, see documentation */
+	{"SensorType",                              	sensorVals,               	ARRAY_SIZE(sensorVals)},
+	{"MeasurementMaxValue",                     	measurementMaxVals,           ARRAY_SIZE(measurementMaxVals)},
+	{"MeasurementMinValue",                     	measurementMinVals,           ARRAY_SIZE(measurementMinVals)},
+	{"Gain",                                    	gainVals,                 	ARRAY_SIZE(gainVals)},
+	{"VBiasEnable",                             	enableVbiasVals,          	ARRAY_SIZE(enableVbiasVals)},
+	{"ExcitationCurrent",                       	currentOutputLevelVals,   	ARRAY_SIZE(currentOutputLevelVals)},
+	{"Reference",                 			0,      				0}, /*< Requires four arguments, see documentation. Handled by #define truth table */
+	{"FilterType",                              	filterTypeVals,           	ARRAY_SIZE(filterTypeVals)},
+	{"FS",                                      	fsVals,                     	ARRAY_SIZE(fsVals)},
+	{"AssignedCompensationMeasurementChannel",  	channelIdVals,            	ARRAY_SIZE(channelIdVals)},
+	{"PublishMeasurement",                      	publishMeasurementVals,    	ARRAY_SIZE(publishMeasurementVals)},
+	{"DisplayUnit",                             	unitTranslationVals,      	ARRAY_SIZE(unitTranslationVals)},
+	
+	//LUT and COEFF Table input here
+	
+	//digital parameters
+	{"DeviceAddress",          				deviceAddressVals,		ARRAY_SIZE(deviceAddressVals)}
+	//NOT NEEDED FOR FIRST SAMPLING
+	/*
+	{"ReadCommand",                 			NULL,                  		0},
+	{"ConfigCommand",                 			NULL,                  		0},
+	{"NumberOfBits",                 			NULL,                  		0},
+	{"FrameWidth",                 			NULL,                  		0},
+	{"LeftAlignment",                 			NULL,                  		0},
+	{"DataEndianness",                 			NULL,                  		0},
+	{"Offset",                 				NULL,                  		0},
+	{"Coding",                 				NULL,                  		0},
+	{"CPOL_CPHA",                 			NULL,                  		0}
+	*/
+};
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/pc_interface/pc_interface.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,217 @@
+
+
+/**
+ * @file pc_interface.h
+ * @author Jake Greaves
+ * @date 21 Dec 2017
+ * @brief The main interface to the pc application.
+ *
+ * This file handles all commands to and from the PC
+ * application.
+ */
+
+#ifndef __PC_INTERFACE_H_
+#define __PC_INTERFACE_H_
+
+#include "string.h"
+#include "adi_sense_api.h"
+#include "adi_sense_1000/adi_sense_1000_api.h"
+#include "pc_interface/pc_serial.h"
+#include "pc_interface/pc_conversions.h"
+#include "myproswift_periph.h"
+#include "core_cm4.h"
+#include "myproswift_error_codes.h"
+#include "rcc_backup_registers/rcc_backup_registers.h"
+#include "eeprom_virtual/eeprom.h"
+
+/*
+    Definitions
+*/
+
+#define RESPONSE_BUFFER_SIZE 	256
+#define PC_DELIMITER		'\n'
+#define PC_SEPERATOR		','
+
+#undef DEBUG
+#define BITP_VALID_DATA (7)
+
+/*
+    Command List
+*/
+
+
+#define COMMAND_DEVICE_INFO 		'i'
+#define COMMAND_FLASH_LED 		'f'
+#define COMMAND_RESET 			'r'
+#define COMMAND_CONFIGURE 		'c'
+#define COMMAND_APPLY			'u'
+#define COMMAND_SAMPLE 			's'
+#define COMMAND_START_STREAM 		'd'
+#define COMMAND_STOP_STREAM 		'h'
+#define COMMAND_UPDATE_FW_VERSION	'v'
+
+//not sure why this is needed by the eeprom library
+extern uint16_t VirtAddVarTab[NB_OF_VAR];
+
+/*
+    Function Prototypes
+*/
+
+/**
+ * @brief Tell any connected device that device is ready to use
+ *
+ * @param bBootLoader If device is entering bootloader, a different success code is given.
+ */
+int Pc_ResetSuccess(bool_t bBootLoader);
+
+/**
+ * @brief Read the next arg from a string.
+ *
+ * This function scans through the given command string
+ * searching for either the seperator value or the delimiter.
+ * On finding either of these chars, all text before is returned
+ * as the argument. If the size limit is reached before a delimiter
+ * this functions returns an error. The flag variable is set when
+ * the delimiter is found, useful for debugging and error handling
+ * when more arguments might be expected.
+ * 
+ * @param command Command string to be analysed.
+ * @param arg A found arg will be returned to this address.
+ * @param size The max size of the arg buffer.
+ * @param flag Set when delimiter is found.
+ *
+ * @return Returns 0 on success, 1 on error.
+ *
+ * @see PC_DELIMITER
+ * @see PC_SEPERATOR
+ */
+static int pc_read_next_arg(char *command, char *arg, int size, bool *flag);
+
+/**
+ * @brief Parse the device info command.
+ *
+ * This function handles the device info command, responding to the PC
+ * with the device name, battery voltage and firmware version.
+ *
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_device_info(void);
+
+/**
+ * @brief Parse the flash led command.
+ *
+ * This function handles the flash led command, pulsing an led
+ * to identify this device. This function also responds to the PC
+ * with the status code.
+ *
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_flash_led(void);
+
+/**
+ * @brief Reset the device.
+ *
+ * This function handles the reset command, performing a soft
+ * reset on the device. The reponse to the pc is handled in the boot
+ * sequence for this device.
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_reset(void);
+
+/**
+ * @brief Parse the configure command.
+ *
+ * This function handles the configure command. Identifiers such as channel,
+ * keyword and value are parsed and converted to struct values. The 
+ * configure struct is updated and applied to the device.
+ *
+ * @param commandString Args are parsed from this string.
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_configure(char *commandString);
+
+/**
+ * @brief Support for the parse configure command.
+ *
+ * If the configure command receives no channel, the configuration is for the 
+ * entire device. This function parses and applies the new value to the 
+ * configuration struct.
+ *
+ * @param attribute The attribute enum identifying which part of the struct 
+ * is to be changed.
+ *
+ * @param commandString The command string incase arguments are expected.
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_configure_device(CONFIG_ATTRIBUTE attribute, char *commandString);
+
+/**
+ * @brief Support for the parse configure command.
+ *
+ * If the configure command receives a channel, the configuration is channel 
+ * specific. This function parses and applies the new value to the 
+ * configuration struct.
+ *
+ * @param channelIndex Which channel is to be configured.
+ * 
+ * @param attribute The attribute enum identifying which part of the struct 
+ * is to be changed.
+ * 
+ * @param commandString The command string incase arguments are expected.
+ *
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_configure_channel(ADI_SENSE_1000_CHANNEL_ID channelIndex, CONFIG_ATTRIBUTE attribute, char *commandString);
+
+/**
+ * @brief Callback for sampling. Drdy is tied to this.
+ */
+static void pc_data_ready_callback(
+    	ADI_SENSE_GPIO_PIN ePinId,
+    	void *pArg);
+
+/**
+ * @brief Parse the sample command.
+ *
+ * Obtain as many samples as required for the given channels and return the raw
+ * 32-bit floats to the PC.
+ *
+ * @param commandString The amount of measurement cycles are obtained from this.
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_sample(char *commandString);
+
+/**
+ * @brief Parse the start stream command.
+ *
+ * Begin the sample stream, pushing out samples as fast as possible to the PC.
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+static int pc_parse_start_stream(void);
+
+/**
+ * @brief Handle an error.
+ *
+ * Send an error code to the PC.
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+int pc_handle_error(ErrorType error);
+
+/**
+ * @brief Find which command to be executed.
+ *
+ * parse the command character and execute the appropriate command.
+ * 
+ * @param commandString the received command from the PC
+ * 
+ * @return Returns 0 on success, 1 on error.
+ */
+int Pc_ParseCommand( char *commandString );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/pc_interface/pc_serial.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,42 @@
+#ifndef __PC_SERIAL_H_
+#define __PC_SERIAL_H_
+
+#include "mbed.h"
+#include "stdarg.h"
+#include "inc/communications.h"
+
+/*
+    Definitions
+*/
+
+//size of buffers used
+#define PC_BUFFER_SIZE 100
+
+//uart pins and baudrate
+#define PC_BAUD_RATE 115200
+#define PC_SERIAL_TX PA_11
+#define PC_SERIAL_RX PA_12
+
+/*
+    Function Prototypes
+*/
+
+//setup the callbck and vars necessary to read a pc json message
+uint32_t Pc_SetupReadLineCb( char *rxBuffer, uint32_t maxSize, volatile bool *bMessageReadFlag );
+
+//clear callback on pc serial handle
+uint32_t Pc_ClearReadLineCb( void );
+
+//read from pc
+uint32_t Pc_Read( char *rxBuffer, uint32_t maxSize );
+
+//wrapper for printf for general messages
+uint32_t Pc_Write( const char* txBuffer, uint32_t size );
+
+//wrapper for printf for error messages
+uint32_t Pc_WriteError( const char* txBuffer, ... );
+
+//wrapper for printf for debug messages
+uint32_t Pc_WriteDebug( const char* txBuffer, ... );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/rcc_backup_registers/rcc_backup_registers.h	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,37 @@
+/**
+ * @file rcc_backup_registers.h
+ * @author Jake Greaves
+ * @date 12 Feb 2018
+ * @brief Interface functions for writing to back-up registers
+ */
+ 
+#ifndef __RCC_BACKUP_REGISTERS_H_
+#define __RCC_BACKUP_REGISTERS_H_
+
+
+#include "stm32f4xx_hal.h"
+
+/**
+ * @brief Read a variable from the RCC registers
+ *
+ * Read back a variable from a given register and return it.
+ *
+ * @param BackupRegister The register to read.
+ *
+ * @return Returns the value of the register.
+ */
+uint32_t Rcc_ReadBackupReg( uint32_t BackupRegister );
+
+/**
+ * @brief Parse the device info command.
+ *
+ * This function handles the device info command, responding to the PC
+ * with the device name, battery voltage and firmware version.
+ *
+ * @return Returns 0 on success, 1 on error.
+ */
+void Rcc_WriteBackupReg( uint32_t BackupRegister, uint32_t data );
+
+
+#endif
+
--- a/main.cpp	Thu Jan 25 16:00:23 2018 +0000
+++ b/main.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -2,144 +2,92 @@
  ******************************************************************************
  * file:   main.cpp
  *-----------------------------------------------------------------------------
- *
-Copyright 2017 (c) Analog Devices, Inc.
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-  - Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
-  - Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in
-    the documentation and/or other materials provided with the
-    distribution.
-  - Neither the name of Analog Devices, Inc. nor the names of its
-    contributors may be used to endorse or promote products derived
-    from this software without specific prior written permission.
-  - The use of this software may or may not infringe the patent rights
-    of one or more patent holders. This license does not release you
-    from the requirement that you obtain separate licenses from these
-    patent holders to use this software.
-  - Use of the software either in source or binary form, must be run
-    on or directly connected to an Analog Devices Inc. component.
-
-THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
  *****************************************************************************/
 #include "mbed.h"
 #include "inc/adi_sense_api.h"
-#include "inc/adi_sense_1000/adi_sense_1000_api.h"
 #include "inc/adi_sense_log.h"
 #include "common/utils.h"
 
-extern ADI_SENSE_CONFIG config;
-
-/* Change the following pointer to select any of the configurations above */
-static ADI_SENSE_CONFIG *pSelectedConfig = &config;
+//additional libraries
+#include "adisense1000_boot.h"
+#include "ble_interface/ble_interface.h"
+#include "myproswift_eval.h"
+#include "eeprom_virtual/eeprom.h"
+#include "myproswift_periph.h"
+#include "led.h"
+#include "bootloader.h"
+#include "rcc_backup_registers.h"
 
-static ADI_SENSE_CONNECTION connectionInfo = {
-    .type = ADI_SENSE_CONNECTION_TYPE_SPI,
-    .spi = {
-        .mosiPin    = SPI_MOSI,
-        .misoPin    = SPI_MISO,
-        .sckPin     = SPI_SCK,
-        .csPin      = D10,
-        .maxSpeedHz = 2000000,
-    },
-    .gpio = {
-        .resetPin     = D6,
-        .errorPin     = D3,
-        .alertPin     = D4,
-        .datareadyPin = D5,
-    },
-};
+#ifdef BL652
+#include "ble_interface/bl652.h"
+#endif
 
-int main()
+
+int main( void )
 {
-    ADI_SENSE_RESULT res;
-    ADI_SENSE_DEVICE_HANDLE hDevice;
-    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode = ADI_SENSE_MEASUREMENT_MODE_NORMAL;
-    bool_t bDeviceReady;
-
-    /*
-     * Open an ADI Sense device instance.
-     */
-    res = adi_sense_Open(0, &connectionInfo, &hDevice);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to open device instance");
-        return res;
-    }
-
-    /*
-     * Reset the given ADI Sense device....
-     */
-    ADI_SENSE_LOG_INFO("Resetting ADI Sense device, please wait...");
-    res = adi_sense_Reset(hDevice);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to reset device");
-        return res;
+    int ret = 1;
+    bool bleActive;
+    
+    // Indicate device is booting
+    Led_Boot();
+     
+    // Check if device needs to enter bootloader function, this is set via a PC command
+    // Flag is stored in RTC registers that persist while vbat is powered
+    bool_t bBootLoader = Rcc_ReadBackupReg( BOOTLOADER_FLAG_BACKUP_REG ) == 1 ? true : false;
+    if( bBootLoader ) {
+        
+        // Let user know device is entering bootloader mode
+        Pc_ResetSuccess( bBootLoader );
+        
+        // Jump to bootloader
+        Bootloader_Init();
     }
-    /*
-     * ...and wait until the device is ready.
-     */
-    do {
-        wait_ms(100);
-        res = adi_sense_GetDeviceReadyState(hDevice, &bDeviceReady);
-        if (res != ADI_SENSE_SUCCESS)
-        {
-            ADI_SENSE_LOG_ERROR("Failed to get device ready-state");
-            return res;
-        }
-    } while (! bDeviceReady);
-    ADI_SENSE_LOG_INFO("ADI Sense device ready");
+    
+    // Otherwise, boot main program
+    
+    // Boot the adisense1000 to a known state
+    ret = Adisense1000_Boot();
+    bool adiSense1000Active = !ret;
+    
+#ifdef BL652
+    //boot BLE device
+    ret = Bl652_Boot();
+    if (ret == 0) {
+        ADI_SENSE_LOG_INFO("BLE Boot success..");
+    } else {
+        ADI_SENSE_LOG_INFO("BLE Boot unsuccessful..");
+    }    
+#endif
 
-    /*
-     * Write configuration settings to the device registers.
-     * Settings are not applied until adi_sense_ApplyConfigUpdates() is called.
-     */
-    ADI_SENSE_LOG_INFO("Setting device configuration");
-    res = adi_sense_SetConfig(hDevice, pSelectedConfig);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to set device configuration");
-        return res;
+    // Set if ble is present or not
+    // If not, the PC interface can still be initialised
+    bleActive = !ret;
+    
+    // Check adisense has booted correctly
+    if( adiSense1000Active ) {
+        Pc_ResetSuccess( bBootLoader );
+        ADI_SENSE_LOG_INFO("ADIsense boot successful...");
     }
-    res = adi_sense_ApplyConfigUpdates(hDevice);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to apply device configuration");
-        return res;
+    else {
+        // Cannot continue without adi_sense module
+        exit( 1 );
     }
-
-    /*
-     * Kick off the measurement cycle here
-     */
-    ADI_SENSE_LOG_INFO("Configuration completed, starting measurement cycles");
-    utils_runMeasurement(hDevice, eMeasurementMode);
-
-    /*
-     * Clean up and exit
-     */
-    res = adi_sense_Close(hDevice);
-    if (res != ADI_SENSE_SUCCESS)
-    {
-        ADI_SENSE_LOG_ERROR("Failed to close device instance");
-        return res;
+    
+    // Set led on to indicate boot has completed
+    
+    ADI_SENSE_LOG_INFO("Set LED Idle...");
+    Led_Idle();
+    
+    // Begin main program
+    ADI_SENSE_LOG_INFO("Begin main program...");
+    while(1) {
+        // Read in a command and handle appropriately
+        ret = MyProSwift_Command( bleActive );
+        if( ret != 0 ) {
+            // Errors should be handled at lower levels, using reponse codes 
+            // to the appropriate active interface
+            // exit(1);
+        }
     }
-
-    return 0;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/adisense1000_boot.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,108 @@
+/*
+ * ADISense1000 - Reset Device functions
+ *
+ * Author: Jake Greaves
+ */
+ 
+#include "inc/adisense1000_boot.h"
+
+ADI_SENSE_DEVICE_HANDLE hDevice;
+
+//connection information for initialising ADISense1000
+extern ADI_SENSE_CONNECTION connectionInfo;
+
+extern ADI_SENSE_CONFIG adi_sense_config;
+extern ADI_SENSE_CONFIG adi_sense_config_eeprom;
+//extern ADI_SENSE_DSP_LUT_RAW adi_sense_dsp_lut;
+
+/***************************************************************
+* Function Name: ADISense1000_Boot
+* Description  : open the ADISense1000 and reset it,
+                    loading default config
+***************************************************************/
+uint8_t Adisense1000_Boot(void)
+{    
+	bool_t bDeviceReady;
+	ADI_SENSE_PRODUCT_ID productId;
+	
+	//Open an ADI Sense device instance.
+	if(adi_sense_Open(0, &connectionInfo, &hDevice) != ADI_SENSE_SUCCESS)
+	    return 1;
+	
+	//Reset the given ADI Sense device, and wait until the device is ready
+	if(adi_sense_Reset(hDevice) != ADI_SENSE_SUCCESS)
+	   return 1;
+	
+	
+	//Wait until the device is ready.
+	do {
+	    wait_ms(100);
+	    if(adi_sense_GetDeviceReadyState(hDevice, &bDeviceReady) != ADI_SENSE_SUCCESS)
+		  return 1;
+	} while (! bDeviceReady);
+	
+	/*
+	 * Read the product ID from the device registers.
+	 */
+	if(adi_sense_GetProductID(hDevice, &productId) != ADI_SENSE_SUCCESS)
+	    return 1;
+		 
+	//apply config
+	if(adi_sense_SetConfig(hDevice, &adi_sense_config) != ADI_SENSE_SUCCESS)
+	    return 1;
+	//if(adi_sense_SetDspData(hDevice, &adi_sense_dsp_lut) == ADI_SENSE_SUCCESS);
+	if(adi_sense_ApplyConfigUpdates(hDevice) != ADI_SENSE_SUCCESS)
+	    return 1;
+
+// Prototype for saving and reading from EEPROM
+// Still needs testing
+#ifdef VIRT_EEPROM
+	//recall config from emulated eeprom
+	//Unlock the Flash Program Erase controller
+	HAL_FLASH_Unlock();
+	
+	//EEPROM Init
+	//cleans up eeprom area and handles pages
+	if(EE_Init() == EE_OK) {
+		
+		//flag to set if eeprom is currently valid
+		uint16_t eepromConfigValid;
+		
+		//if read of flag is successful
+		if((EE_ReadVariable(VirtAddVarTab[0], &eepromConfigValid)) == HAL_OK) {
+			
+			//if eeprom config is valid, read into working config struct
+			//0xAF is generic flag
+			if(eepromConfigValid == 0xAF) {
+				//read eeprom to adisenseconfig
+				uint16_t *p = (uint16_t*)&adi_sense_config_eeprom;
+				int i = 0;
+				
+				//read back all bytes, on error, read is broken
+				for(i = 0; i < sizeof(adi_sense_config_eeprom)/sizeof(uint16_t); i++, p++) {
+					//read struct back, break on error
+					if((EE_ReadVariable(VirtAddVarTab[1] + i, p)) != HAL_OK)
+						break;
+				}
+				
+				//if no error occurred and the config struct is complete
+				if(i == sizeof(adi_sense_config_eeprom)/sizeof(uint16_t)) {
+					//apply config
+					if(adi_sense_SetConfig(hDevice, &adi_sense_config_eeprom) != ADI_SENSE_SUCCESS)
+					    return 1;
+					//if(adi_sense_SetDspData(hDevice, &adi_sense_dsp_lut) == ADI_SENSE_SUCCESS);
+					if(adi_sense_ApplyConfigUpdates(hDevice) != ADI_SENSE_SUCCESS)
+					    return 1;
+				}
+			}
+		}
+	}
+	
+	//Lock the Flash Program Erase controller
+	HAL_FLASH_Lock();
+	
+#endif
+	
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ble_interface/bl652.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,234 @@
+/*
+ * bl652.cpp - BLE driver for serial port service
+ *
+ * Author: Jake Greaves
+ */
+
+#include "bl652.h"
+
+#include "mbed.h"
+#include "myproswift_periph.h"
+#include "communications.h"
+
+
+//used by callback
+static char *cbSerialBuffer;
+volatile bool *bBleMessageReceived;
+static uint32_t cbCount = 0;
+static uint32_t cbMaxSize;
+
+
+//reset pin of BLE module
+extern DigitalOut ble_rst;
+//flow control
+extern DigitalOut ble_Cts;
+extern DigitalIn ble_Rts;
+//Serial for ble
+extern Serial bleSerialDevice;
+//SPI
+extern SPI bleSpiDevice;
+extern DigitalOut cs_Ble;
+
+extern DigitalOut bleMode0;
+extern DigitalOut bleMode1;
+
+
+//ble requires a minimum delay between packets
+Timer timer;
+
+
+/***************************************************************
+* Function Name: Bl652_AtTransaction
+* Description  : Perform an AT command transaction
+***************************************************************/
+uint32_t Bl652_AtTransaction( char *command, char *resp )
+{
+	//write command to device
+	Bl652_Write( command, strlen(command) );
+	
+	//read response
+	int8_t i = -1;
+	do {
+		i++;
+		Bl652_Read( &resp[i], 1 );
+	} while(resp[i] != AT_COMMAND_DELIMITER);
+	
+	if( !strncmp(resp, AT_COMMAND_ERROR, strlen(AT_COMMAND_ERROR)) ) {
+		return 1;
+	}
+	   
+	else {
+		return 0;
+	}
+}
+
+/***************************************************************
+* Function Name: Bl652_Boot
+* Description  : Main boot function
+***************************************************************/
+uint32_t Bl652_Boot( void )
+{
+	
+	//setup device as vSP mode
+	bleMode0 = 1;
+	bleMode1 = 1;
+	
+	//reset device
+	ble_rst = 0;
+	wait_ms( RESET_LENGTH );
+	ble_rst = 1;
+	
+	//start sending timer for minimum packet delay
+	timer.start();
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: Bl652_Callback
+* Description  : callback for uart communications
+***************************************************************/
+static void Bl652_Callback( void )
+{	
+	while( bleSerialDevice.readable() ) {
+		//read next character
+		char c = bleSerialDevice.getc();
+		
+		//store char in buffer
+		if( cbSerialBuffer != NULL ) {
+		    cbSerialBuffer[cbCount] = c;
+		}
+		
+		//increment count
+		cbCount++;
+		
+		//check if buffer is filled
+		if( cbCount >= cbMaxSize ) {
+			
+		    //set flag that data has been received
+		    *bBleMessageReceived = 1;
+		    break;
+		}
+		//else continue sending
+		else {    
+			//indicate ble is clear to send
+			ble_Cts = 0;
+		}
+	}
+}
+
+/***************************************************************
+* Function Name: Bl652_WaitUntilAvailable
+* Description  : wait until ble is awake
+***************************************************************/
+static uint32_t Bl652_WaitUntilAvailable( void )
+{
+    //wait until BLE is available
+    while( ble_Rts );
+
+    return 0;
+}
+
+/***************************************************************
+* Function Name: Bl652_Write
+* Description  : write string to ble over uart
+***************************************************************/
+uint32_t Bl652_Write( char *txBuffer, uint32_t byteCount )
+{
+	uint8_t res = 0;
+	char padding[1] = {0x00};
+	
+	//check packet is not too large
+	if( byteCount > BLE_PACKET_SIZE ) {
+		return 1;
+	}
+	
+	//wait the time limit for packets to be sent 
+	while( timer.read_ms() < BLE_TX_PACKET_DELAY );
+	timer.stop();
+	
+	for( uint32_t i = 0; i < byteCount; i++ ) {
+		res = Bl652_WaitUntilAvailable();
+		res = Uart_Write( bleSerialDevice, txBuffer + i, 1 );
+	}
+	
+	//padding to 20 bytes
+	for( uint32_t i = 0; i < BLE_PACKET_SIZE - byteCount; i++ ) {
+		res = Bl652_WaitUntilAvailable();
+		res = Uart_Write( bleSerialDevice, padding, 1 );
+	}
+	
+	timer.reset();
+	timer.start();
+	
+	return res;
+}
+
+/***************************************************************
+* Function Name: ble_read
+* Description  : blocking read over uart
+***************************************************************/
+uint32_t Bl652_Read( char *rxBuffer, uint32_t byteCount )
+{
+    ble_Cts = 0;
+    
+    for(uint32_t i = 0; i < byteCount; i++) {
+	    rxBuffer[i] = bleSerialDevice.getc();
+    }
+	
+    ble_Cts = 1;
+    
+    return 0;
+}
+
+/***************************************************************
+* Function Name: ble_setup_read_cb
+* Description  : register callback and flag for receiving ble data
+***************************************************************/
+uint32_t Bl652_SetupReadCb( void *rxBuffer, uint32_t maxSize, volatile bool *bMessageReadFlag )
+{
+	uint32_t ret = 0;
+	
+    //setup global vars for handler funtions
+    cbCount = 0;
+    cbMaxSize = maxSize;
+    
+    //assign serial callback buffer
+    if( rxBuffer != NULL ) {
+	  cbSerialBuffer = ( char* )rxBuffer;
+    }
+    else {
+	    return 1;
+    }
+    
+    //register global flag
+    bBleMessageReceived = bMessageReadFlag;
+    
+    //assign callback buffer
+    cbSerialBuffer = ( char* )rxBuffer;
+
+    //call UART function
+    ret = Uart_ReadCb( bleSerialDevice, Bl652_Callback );
+  	
+    //wait until BLE is awake
+    //ble_wait_until_available();
+    
+    //indicate ble is clear to send
+    ble_Cts = 0;
+    
+    return ret;
+}
+
+/***************************************************************
+* Function Name: ble_clear_cb
+* Description  : clear cb and top receiing ble data
+***************************************************************/
+uint32_t Bl652_ClearCb( void )
+{
+    //indicate ble to stop sending
+    ble_Cts = 1;
+
+    //clear callback to uart handle
+    return Uart_ClearCb( bleSerialDevice );
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ble_interface/ble_interface.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,683 @@
+/*
+ * ble_interface.cpp - main interface to android application
+ *
+ * Author: Jake Greaves
+ */
+#include "ble_interface.h"
+
+//adisense1000 config as defined elsewhere
+extern ADI_SENSE_CONFIG adi_sense_config;
+extern ADI_SENSE_DEVICE_HANDLE hDevice;
+
+//ble uart device
+extern Serial bleSerialDevice;
+extern DigitalOut ble_Cts;
+
+//a work around for multiple requests received from app
+char lastFieldNameID = 0xFF;
+
+
+static char *fieldNames[ADI_SENSE_1000_MAX_CHANNELS] = {
+	"Cjc0",
+	"Cjc1",
+	"Sensor0",
+	"Sensor1",
+	"Sensor2",
+	"Sensor3",
+	"Voltage0",
+	"Current0",
+	"I2c0",
+	"I2c1",
+	"Spi0",
+	"Spi1",
+	"Spi2"
+};
+
+//send error response
+static uint32_t Ble_HandleError( ErrorType error );
+
+
+//command ID to be handled
+enum {
+	REQ_REG_PACKET_COUNT 	= 0x30, //'0'
+	REQ_REG_PACKETS 		= 0x31, //'1'
+	REQ_FIELD_NAMES 		= 0x32, //'2'
+	START_STREAM 		= 0x33, //'3'
+	STOP_STREAM 		= 0x34, //'4'
+} MSG_TYPE;
+
+/*
+enum {
+	REQ_REG_PACKET_COUNT 	= 0x10,
+	REQ_REG_PACKETS 		= 0x11,
+	REQ_FIELD_NAMES 		= 0x12,
+	START_STREAM 		= 0x20,
+	STOP_STREAM 		= 0x21,
+} MSG_TYPE;
+*/
+//possible measurement types
+enum {
+	TEMPERATURE = 0x00,
+	PRESSURE,
+	HUMIDITY,
+	ACCELEROMETER,
+	UNDEFINED
+} MEASUREMENT_TYPES;
+
+//data type. Might change to bytes per measurement in newer API versions
+enum {
+	FLOAT_32 = 0x01
+} DATA_TYPE;
+
+//structs to store an active channels details for the BLE App
+typedef struct {
+	uint8_t measurementId;
+	uint8_t measurementTypeId;
+	char *measurementName;
+	uint8_t numberOfFields;
+	uint8_t associatedChannel;
+	uint8_t dataType;
+} MEASUREMENT_INFO;
+
+
+//store all active channel information
+static MEASUREMENT_INFO *measurementInfo = NULL;
+
+//counts amount of channels active
+static uint8_t activeChannelCount = 0;
+
+//flag for streaming data
+volatile static bool bStreamFlag = 0;
+
+
+/***************************************************************
+* Function Name: Ble_HandleReqRegPacketCount
+* Description  : handle the REQ_REG_PACKET_COUNT command
+****************************************************************/
+static uint32_t Ble_HandleReqRegPacketCount( void )
+{
+	//buffer for sending BLE data
+	char bleTxBuffer[BLE_PACKET_SIZE] = {0x00};
+	//stores position in bleTxBuffer
+	uint8_t buffPos = 0;
+	
+	//clear active channel count
+	activeChannelCount = 0;
+	
+	//clear global array for aactive channels, as we are recalculating this now
+	free( measurementInfo );
+	measurementInfo = NULL;
+	
+	//check all channels
+	for( uint32_t i = 0; i < ADI_SENSE_1000_MAX_CHANNELS; i++ ) {
+		
+		//struct to contain data on measurement
+		MEASUREMENT_INFO channel_info;
+		
+		//current channel
+		ADI_SENSE_1000_CHANNEL_CONFIG channel = adi_sense_config.adisense1000.channels[i];
+		
+		//include as independant channel if enabled and not a compensation channel
+		//for now, compensation cahnnels get their own graph if publishing is enabled
+		if( channel.enableChannel && !channel.disablePublishing ) {
+			
+			//add a measurement
+			channel_info.measurementId = activeChannelCount;
+			activeChannelCount++;
+			
+			//set name and units
+			//check channel type based on ranges and assign name and type
+			if( channel.adcChannelConfig.sensor <= ADI_SENSE_1000_ADC_SENSOR_THERMISTOR_4_ADV_L2 ) {
+				channel_info.measurementTypeId = TEMPERATURE;
+				channel_info.measurementName = "Temperature";
+			}
+			
+			else if( channel.adcChannelConfig.sensor >= ADI_SENSE_1000_I2C_SENSOR_HUMIDITY_HONEYWELL_HUMIDICON && channel.adcChannelConfig.sensor <= ADI_SENSE_1000_I2C_SENSOR_HUMIDITY_SENSIRION_SHT3X ) {
+				channel_info.measurementTypeId = HUMIDITY;
+				channel_info.measurementName = "Humidity";
+			}
+			
+			else if( channel.adcChannelConfig.sensor >= ADI_SENSE_1000_ADC_SENSOR_VOLTAGE || channel.adcChannelConfig.sensor == ADI_SENSE_1000_SPI_SENSOR_PRESSURE_HONEYWELL_TRUSTABILITY ) {
+				channel_info.measurementTypeId = PRESSURE;
+				channel_info.measurementName = "Pressure";
+			}
+			
+			else {
+				channel_info.measurementTypeId = UNDEFINED;
+				channel_info.measurementName = "Undefined";
+			}
+			
+			//default to 1 field
+			channel_info.numberOfFields = 1;
+			
+			//add current channel
+			channel_info.associatedChannel = i;
+			
+			//all values are floats for now
+			channel_info.dataType = FLOAT_32;
+			
+			//add to overall array
+			measurementInfo = ( MEASUREMENT_INFO * )realloc( measurementInfo, activeChannelCount * sizeof( MEASUREMENT_INFO ) );
+			measurementInfo[activeChannelCount - 1] = channel_info;
+		}
+	}
+	
+	if( activeChannelCount == 0 ) {
+		return Ble_HandleError( ERROR_UNDEFINED );
+	}
+	
+	//command ID
+	bleTxBuffer[buffPos] = REQ_REG_PACKET_COUNT;
+	buffPos++;
+	
+	//amount of data samples
+	bleTxBuffer[buffPos] = activeChannelCount;
+	buffPos++;
+	
+	//respond to app
+	Bl652_Write( bleTxBuffer, buffPos );
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: Ble_HandleReqRegPackets
+* Description  : handle the REQ_REG_PACKETS command
+****************************************************************/
+static uint32_t Ble_HandleReqRegPackets( void )
+{
+	//buffer for sending BLE data
+	char bleTxBuffer[BLE_PACKET_SIZE] = {0x00};
+	//stores position in bleTxBuffer
+	uint8_t buffPos = 0;
+	
+	//ReqRegPacketCount has not been called, or had an error
+	if( activeChannelCount == 0 ) {
+		return Ble_HandleError( ERROR_UNDEFINED );
+	}
+	
+	//repeat for all measurements
+	for( uint32_t i = 0; i < activeChannelCount; i++ ) {
+		
+		//reset buffPos
+		buffPos = 0;
+		
+		//add command ID
+		bleTxBuffer[buffPos] = REQ_REG_PACKETS;
+		buffPos++;
+		
+		//add regPackets ID
+		bleTxBuffer[buffPos] = measurementInfo[i].measurementId;
+		buffPos++;
+		
+		//add type of measurement
+		bleTxBuffer[buffPos] = measurementInfo[i].measurementTypeId;
+		buffPos++;
+		
+		//adding measurements name to packet
+		char *measurementName = ( char* )measurementInfo[i].measurementName;
+		for( uint32_t j = 0; j < MEASUREMENT_NAME_MAX_LEN; j++ ) {
+			//populate measurement name for app
+			if( j < strlen( measurementName ) ) {
+				bleTxBuffer[buffPos] = measurementName[j];
+			}
+			//pad unused chars with 0x00
+			else {
+				bleTxBuffer[buffPos] = 0x00;
+			}
+			buffPos++;
+		}
+		
+		//add number of plots on graph. ( 1 for now )
+		bleTxBuffer[buffPos] = measurementInfo[i].numberOfFields;
+		buffPos++;
+		//add data format ( always float32_t for now )
+		bleTxBuffer[buffPos] = measurementInfo[i].dataType;
+		buffPos++;
+	
+		//transmit packet
+		Bl652_Write( bleTxBuffer, buffPos );
+	}
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: Ble_HandleReqFieldNames
+* Description  : handle the REQ_FIELD_NAMES command
+****************************************************************/
+static uint32_t Ble_HandleReqFieldNames( char *bleRxBuffer ) 
+{
+	//buffer for sending BLE data
+	char bleTxBuffer[BLE_PACKET_SIZE] = {0x00};
+	//stores position in bleTxBuffer
+	uint8_t buffPos = 0;
+	
+	//flag for reading from BLE
+	volatile bool bBleMessageReceived = 0;
+	uint8_t numberOfFields;
+	
+	//read a further byte
+	Bl652_Read( &bleRxBuffer[1], 1 );
+	
+	//if ReqRegPacketCount has not been called, or had an error
+	if( activeChannelCount == 0 ) {
+		return Ble_HandleError( ERROR_UNDEFINED );
+	}
+	
+	//dirtiest of hacks. Issue here is app seems to send same packet multiple times when sent once. 
+	//Unsure why this is for now, ignore duplicates
+	if( bleRxBuffer[1] == lastFieldNameID ) {
+		return 0;
+	}
+	lastFieldNameID = bleRxBuffer[1];
+	
+	//find units for channel
+	char unitDescriptor[UNIT_NAME_MAX_LEN];
+	switch( measurementInfo[bleRxBuffer[1]].measurementTypeId ) {
+		
+	  case TEMPERATURE:
+		strcpy( unitDescriptor, "�C" );
+		break;
+		
+	  case PRESSURE:
+		strcpy( unitDescriptor, "PSI" );
+		break;
+		
+	  case HUMIDITY:
+		strcpy( unitDescriptor, "%" );
+		break;
+		
+	  case ACCELEROMETER:
+		strcpy( unitDescriptor, "XYZ" );
+		break;
+		
+	  default:
+		strcpy( unitDescriptor, "NA" );
+		break;
+	}
+	
+	//add command ID to BLE packet
+	bleTxBuffer[buffPos] = REQ_FIELD_NAMES;
+	buffPos++;
+	
+	//add unit name to ble packet, padding with 0x00
+	for( uint32_t i = 0; i < UNIT_NAME_MAX_LEN; i++ ) {
+		//populate measurement name for app
+		if( i < strlen( unitDescriptor ) ) {
+			bleTxBuffer[buffPos] = unitDescriptor[i];
+		}
+		//pad with 0x00
+		else {
+			bleTxBuffer[buffPos] = 0x00;
+		}
+		buffPos++;
+	}
+	
+	//name of sensor fields
+	numberOfFields = measurementInfo[bleRxBuffer[1]].numberOfFields;
+	
+	//ReqRegPacketCount has not been called, or had an error
+	if( numberOfFields == 0 ) {
+		return Ble_HandleError( ERROR_UNDEFINED );
+	}
+	
+	//calculate the available space for names of each plot.
+	//This is support for multiple channels associated together.
+	uint8_t eachFieldNameMaxSize = FIELD_NAMES_MAX_SIZE / numberOfFields;
+	
+	//add field names to packet
+	for( uint32_t i = 0; i < numberOfFields; i++ ) {
+		char *fieldName = fieldNames[measurementInfo[bleRxBuffer[1]].associatedChannel];
+		
+		for( uint32_t j = 0; j < eachFieldNameMaxSize; j++ ) {
+			//populate measurement name for app
+			if( j < strlen( fieldName ) ) {
+				bleTxBuffer[buffPos] = fieldName[j];
+			}
+			//pad with 0x00
+			else {
+				bleTxBuffer[buffPos] = 0x00;
+			}
+			buffPos++;
+		}
+	}
+	
+	//return measurement count, field name
+	Bl652_Write( bleTxBuffer, buffPos );
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: ble_data_ready_callback
+* Description  : callback for when data ready state changes
+****************************************************************/
+static void ble_data_ready_callback( ADI_SENSE_GPIO_PIN ePinId, void *pArg )
+{
+	volatile bool_t *pbDataready = ( volatile bool_t * ) pArg;
+   	*pbDataready = true;
+}
+
+/***************************************************************
+* Function Name: Ble_HandleStartStream
+* Description  : handle the START_STREAM command
+****************************************************************/
+static uint32_t Ble_HandleStartStream( void )
+{
+	//buffer for sending BLE data
+	char bleTxBuffer[BLE_PACKET_SIZE] = {0x00};
+	//stores poition in bleTxBuffer
+	uint8_t buffPos = 0;
+
+	//part of the adisense1000 sampling
+	ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
+	ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
+	ADI_SENSE_1000_DATAREADY_MODE eDataPublishMode;
+	ADI_SENSE_MEASUREMENT_MODE eMeasurementMode = ADI_SENSE_MEASUREMENT_MODE_NORMAL;
+	uint32_t nSamplesPerDataready, nSamplesPerCycle;
+	volatile bool_t bDataReady = false;
+	
+	//if ReqRegPacketCount has not been called, or had an error
+	if( activeChannelCount == 0 ) {
+		return Ble_HandleError( ERROR_UNDEFINED );
+	}
+	
+	//upload new configuration and apply. 
+	//This has been used to calculate all previous steps, so ensure that this is the active configuration
+	adi_sense_SetConfig( hDevice, &adi_sense_config );
+	adi_sense_ApplyConfigUpdates( hDevice );
+	
+	//get information about the adisense data ready mode
+	adi_sense_1000_GetDataReadyModeInfo(hDevice,
+							eMeasurementMode,
+							&eOperatingMode,
+							&eDataPublishMode,
+							&nSamplesPerDataready,
+							&nSamplesPerCycle );
+	//allocate a buffer to store the samples retreived on each DATAREADY pulse
+	pSampleBuffer = new ADI_SENSE_DATA_SAMPLE[nSamplesPerDataready];
+	if( pSampleBuffer == NULL ) {
+		return 1;
+	}
+	
+	//interrupt-triggered DATAREADY notifications in this mode
+	adi_sense_RegisterGpioCallback( hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+						ble_data_ready_callback,
+						( void * )&bDataReady );
+	
+	//allow ble to send data for stream cancel command
+	ble_Cts = 0;
+	
+	//handle the single cycle device mode
+	if ( eOperatingMode == ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE ) {
+		
+		//loop single cycle until stream stop command is received
+		do {
+			//begin measurement cycles
+			adi_sense_StartMeasurement( hDevice, eMeasurementMode );
+			
+			//read in each measurement cycle
+			for ( uint32_t i = 0; i < nSamplesPerCycle / nSamplesPerDataready; i++ ) {
+				uint32_t nReturned;
+				
+				//Interrupt method: wait for DATAREADY interrupt callback
+				while ( !bDataReady );
+				
+				//reset bDataReady flag to detect the next callback
+				bDataReady = false;
+				
+				//read data into structure
+				adi_sense_GetData( hDevice, eMeasurementMode, pSampleBuffer, nSamplesPerDataready, &nReturned );
+				
+				//for all returned samples
+				for( uint32_t i = 0; i < nReturned; i++ ) {
+					
+					//to store adisense1000 channel index 
+					//and the channel number according to the BLE device
+					uint8_t channelIndex, activeChannelNumber;
+					
+					//obtain sample data in byte array form
+					uint8_t *sample = ( uint8_t* )&pSampleBuffer[i].processedValue;
+					
+					//match sample ID to active channel
+					for( uint32_t j = 0; j < activeChannelCount; j++ ) {
+						
+						//get the ID of the current active channel
+						channelIndex = measurementInfo[j].associatedChannel;
+						
+						//if the sample matches the current active channel
+						if( pSampleBuffer[i].channelId == channelIndex ) {
+							activeChannelNumber = j;
+							break;
+						}
+					}
+					
+					//clear buffPos
+					buffPos = 0;
+					
+					//tag samples with command value
+					bleTxBuffer[buffPos] = START_STREAM;
+					buffPos++;
+					
+					//Tag with ID of measurement
+					bleTxBuffer[buffPos] = measurementInfo[activeChannelNumber].measurementId;
+					buffPos++;
+						
+					//transmute sample data into bytes for transmission
+					for( uint32_t j = 0; j < sizeof( measurementInfo[activeChannelNumber].dataType ); j++ ) {
+						
+						//store bytes to buffer
+						bleTxBuffer[buffPos] = sample[j];
+						buffPos++;
+					}
+					
+					//stream measurement
+					Bl652_Write( bleTxBuffer, buffPos );
+				}
+			}
+			
+			if( bleSerialDevice.readable() ) {
+				ble_Cts = 1;
+				if( bleSerialDevice.getc() == STOP_STREAM ) {
+					//stop stream measurement
+					bleTxBuffer[0] = STOP_STREAM;
+					Bl652_Write( bleTxBuffer, 1 );
+					break;
+				}
+				else {
+					return Ble_HandleError( ERROR_UNDEFINED );
+				}
+			}			
+		} while ( 1 );
+	}
+
+	//handle continuous measurement mode
+	else {
+
+		//begin measurement cycles
+		adi_sense_StartMeasurement( hDevice, eMeasurementMode );
+	
+		do {
+			uint32_t nReturned;
+		
+			//Interrupt method: wait for DATAREADY interrupt callback
+			while ( !bDataReady );
+		
+			//reset bDataReady flag to detect the next callback
+			bDataReady = false;
+		
+			//read data into structure
+			adi_sense_GetData( hDevice, eMeasurementMode, pSampleBuffer, nSamplesPerDataready, &nReturned );
+		
+			//for all returned samples //TODO: Might need modified. Test with App
+			for( uint32_t i = 0; i < nReturned; i++ ) {
+				
+				//to store adisense1000 channel index 
+				//and the channel number according to the BLE device
+				uint8_t channelIndex, activeChannelNumber;
+				
+				//obtain sample data in byte array form
+				uint8_t *sample = ( uint8_t* )&pSampleBuffer[i].processedValue;
+				
+				//match sample ID to active channel
+				for( uint32_t j = 0; j < activeChannelCount; j++ ) {
+					
+					//get the ID of the current active channel
+					channelIndex = measurementInfo[j].associatedChannel;
+					
+					//if the sample matches the current active channel
+					if( pSampleBuffer[i].channelId == channelIndex ) {
+						activeChannelNumber = j;
+						break;
+					}
+				}
+				
+				//clear buffPos
+				buffPos = 0;
+				
+				//tag samples with command value
+				bleTxBuffer[buffPos] = START_STREAM;
+				buffPos++;
+				
+				//Tag with ID of measurement
+				bleTxBuffer[buffPos] = measurementInfo[activeChannelNumber].measurementId;
+				buffPos++;
+					
+				//transmute sample data into bytes for transmission
+				for( uint32_t j = 0; j < sizeof( measurementInfo[activeChannelNumber].dataType ); j++ ) {
+					
+					//store bytes to buffer
+					bleTxBuffer[buffPos] = sample[j];
+					buffPos++;
+				}
+				
+				//stream measurement
+				Bl652_Write( bleTxBuffer, buffPos );
+			}
+		
+			if( bleSerialDevice.readable() ) {
+				
+				//signal ble to stop sending bytes
+				ble_Cts = 1;
+				
+				//read byte buffer and determine if 
+				//the STOP_STREAM byte has been received
+				if( bleSerialDevice.getc() == STOP_STREAM ) {
+					//stop stream measurement
+					bleTxBuffer[0] = STOP_STREAM;
+					Bl652_Write( bleTxBuffer, 1 );
+					break;
+				}
+				else {
+					return Ble_HandleError( ERROR_UNDEFINED );
+				}
+			}
+		} while ( 1 );
+	
+		//stop measurement
+		adi_sense_StopMeasurement( hDevice );
+	}
+
+	//free buffer
+	delete [] pSampleBuffer;
+
+	return 0;
+}
+
+/***************************************************************
+* Function Name: Ble_HandleStopStream
+* Description  : handle the STOP_STREAM command
+****************************************************************/
+static uint32_t Ble_HandleStopStream( void )
+{
+	//buffer for sending BLE data
+	char bleTxBuffer[BLE_PACKET_SIZE] = {0x00};
+	//stores poition in bleTxBuffer
+	uint8_t buffPos = 0;
+		
+	//stop stream measurement. Already stopped but let app know
+	bleTxBuffer[buffPos] = STOP_STREAM;
+	buffPos++;
+	
+	//transmit buffer
+	Bl652_Write( bleTxBuffer, 1 );
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: handle_error
+* Description  : handle an error
+****************************************************************/
+static uint32_t Ble_HandleError( ErrorType error )
+{	
+	char status[1] = {error};
+	
+	//send response error
+	Bl652_Write( status, sizeof( status ) );
+
+	return 1;
+}
+
+/***************************************************************
+* Function Name: ble_parse_command
+* Description  : parse the ble command
+****************************************************************/
+uint32_t Ble_ParseCommand(  char *bleRxBuffer  )
+{
+	uint32_t ret = 0;
+	//here we read the next byte and use a case to decide the handler function
+	//within the handler, the remaining bytes may be read and acted on appropriately with a response
+	
+	//confirm type of command ( 1st complete byte )
+	switch( bleRxBuffer[0] ) {
+		
+	  case REQ_REG_PACKET_COUNT: {//app is requesting the amount of reg packets required
+		//call handler function, passing buffer for further use
+		ret = Ble_HandleReqRegPacketCount();
+		char bleSend1[] = "PacketCount\r\n";
+		Bl652_Write(bleSend1 , 15);
+		break;
+		}
+	  case REQ_REG_PACKETS: {//app is requesting for all reg packets
+		//call handler function, passing buffer for further use
+		ret = Ble_HandleReqRegPackets();
+		char bleSend2[] = "ReqRegister\r\n";
+		Bl652_Write(bleSend2 , 15);
+		break;
+		}
+	  case REQ_FIELD_NAMES: {//app is requesting field names
+		//call handler function, passing buffer for further use
+		ret = Ble_HandleReqFieldNames( bleRxBuffer );
+		char bleSend3[] = "FieldNames\r\n";
+		Bl652_Write(bleSend3 , 15);
+		break;
+		}
+	  case START_STREAM: {//app is requesting the start of the data stream
+		//call handler function
+		ret = Ble_HandleStartStream();
+		char bleSend4[] = "StartStream\r\n";
+		Bl652_Write(bleSend4 , 15);
+		break;
+		}
+	  case STOP_STREAM: {//app is requesting to stop the data stream
+		//call handler function
+		ret = Ble_HandleStopStream();
+		break;
+		}
+		//Template
+		//case COMMAND:  return parse_COMMAND();
+		//parse_COMMAND handles the action required
+		//COMMAND must be defined within the header file
+
+		//handle an unrecognised command/error
+	  default: {//command not recognised
+		ret = Ble_HandleError( ERROR_UNDEFINED );
+		break;
+		}
+	}
+	
+	return ret;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bootloader.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,46 @@
+/*
+ ******************************************************************************
+ * file:   bootloader.c
+ *-----------------------------------------------------------------------------
+ */
+
+#include "bootloader.h"
+#include "rcc_backup_registers.h"
+
+
+void (*SysMemBootJump)(void);
+
+ 
+// Jump through software to the system bootloader
+// This should only be called after a reset to ensure correct operation
+void Bootloader_Init( void ) {
+	
+	// Base bootloader address, found within software manual
+	volatile uint32_t bootLoaderAddr = 0x1FFF0000;
+	
+	// Clear backup register flag
+	Rcc_WriteBackupReg(BOOTLOADER_FLAG_BACKUP_REG, 0);
+	
+	// Disable RCC clock
+	HAL_RCC_DeInit();
+
+	//disable systick timer and interrupts
+	SysTick -> CTRL = 0;
+	SysTick -> LOAD = 0;
+	SysTick -> VAL = 0;
+	
+	//disable all configurable interrupts
+	__disable_irq();
+	
+	//remap sys mem to 0x0000 0000 in address space. Different for each device
+	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
+	
+	//map jump function
+	SysMemBootJump =  (void (*)(void)) (*((uint32_t *)(bootLoaderAddr + 0x04)));
+	
+	//set main stack pointer
+	__set_MSP(*(uint32_t *)bootLoaderAddr);
+	
+	//jump
+	SysMemBootJump();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/communications.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,64 @@
+/*
+ * communications.cpp - low level communications wrapper for mbed
+ *
+ * Author: Jake Greaves
+ */
+
+#include "communications.h"
+
+//spi callback flags
+static volatile int intType;
+static volatile bool spiCallbackFlag;
+static event_callback_t callbck;
+
+
+/***************************************************************
+* Function Name: uart_Init
+* Description  : init for serialHandle
+****************************************************************/
+int Uart_Init( Serial &serialHandle, uint32_t baudrate )
+{
+    //set baudrate
+    serialHandle.baud( baudrate );
+
+    return 0;
+}
+
+/***************************************************************
+* Function Name: uart_Write
+* Description  : write a string to a serial device
+****************************************************************/
+int Uart_Write( Serial &serialHandle, const char* txBuffer, unsigned int length )
+{
+
+    for(unsigned int i = 0; i < length; i++) {
+    	//print to serial device
+   	serialHandle.putc( txBuffer[i] );
+    }
+
+    return 0;
+}
+
+/***************************************************************
+* Function Name: uart_read_cb
+* Description  : Read from a serial device using a callback
+****************************************************************/
+int Uart_ReadCb( Serial &serialHandle, void ( *callback )( void ) )
+{
+    //attach callback
+    serialHandle.attach( callback );
+
+    return 0;
+}
+
+/***************************************************************
+* Function Name: uart_clear_cb
+* Description  : clear callback
+****************************************************************/
+int Uart_ClearCb( Serial &serialHandle )
+{
+    //attach callback
+    serialHandle.attach( NULL );
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eeprom_virtual/eeprom.c	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,769 @@
+/**
+  ******************************************************************************
+  * @file    EEPROM/EEPROM_Emulation/src/eeprom.c 
+  * @author  MCD Application Team
+  * @brief   This file provides all the EEPROM emulation firmware functions.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright © 2017 STMicroelectronics International N.V. 
+  * All rights reserved.</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without 
+  * modification, are permitted, provided that the following conditions are met:
+  *
+  * 1. Redistribution of source code must retain the above copyright notice, 
+  *    this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright notice,
+  *    this list of conditions and the following disclaimer in the documentation
+  *    and/or other materials provided with the distribution.
+  * 3. Neither the name of STMicroelectronics nor the names of other 
+  *    contributors to this software may be used to endorse or promote products 
+  *    derived from this software without specific written permission.
+  * 4. This software, including modifications and/or derivative works of this 
+  *    software, must execute solely and exclusively on microcontroller or
+  *    microprocessor devices manufactured by or for STMicroelectronics.
+  * 5. Redistribution and use of this software other than as permitted under 
+  *    this license is void and will automatically terminate your rights under 
+  *    this license. 
+  *
+  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 
+  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 
+  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
+  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 
+  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
+  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+/** @addtogroup EEPROM_Emulation
+  * @{
+  */ 
+
+/* Includes ------------------------------------------------------------------*/
+#include "eeprom_virtual/eeprom.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+
+/* Global variable used to store variable value in read sequence */
+uint16_t DataVar = 0;
+
+/* Virtual address defined by the user: 0xFFFF value is prohibited */
+extern uint16_t VirtAddVarTab[NB_OF_VAR];
+
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+static HAL_StatusTypeDef EE_Format(void);
+static uint16_t EE_FindValidPage(uint8_t Operation);
+static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
+static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data);
+static uint16_t EE_VerifyPageFullyErased(uint32_t Address);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	
+/**
+  * @brief  Restore the pages to a known good state in case of page's status
+  *   corruption after a power loss.
+  * @param  None.
+  * @retval - Flash error code: on write Flash error
+  *         - FLASH_COMPLETE: on success
+  */
+uint16_t EE_Init(void)
+{
+  uint16_t PageStatus0 = 6, PageStatus1 = 6;
+  uint16_t VarIdx = 0;
+  uint16_t EepromStatus = 0, ReadStatus = 0;
+  int16_t x = -1;
+  HAL_StatusTypeDef  FlashStatus;
+  uint32_t SectorError = 0;
+  FLASH_EraseInitTypeDef pEraseInit;
+
+
+  /* Get Page0 status */
+  PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
+  /* Get Page1 status */
+  PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
+
+  pEraseInit.TypeErase = TYPEERASE_SECTORS;
+  pEraseInit.Sector = PAGE0_ID;
+  pEraseInit.NbSectors = 1;
+  pEraseInit.VoltageRange = VOLTAGE_RANGE;
+  
+  /* Check for invalid header states and repair if necessary */
+  switch (PageStatus0)
+  {
+    case ERASED:
+      if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
+      {
+          /* Erase Page0 */
+        if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+        {
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
+      {
+        /* Erase Page0 */
+        if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+        /* Mark Page1 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE1_BASE_ADDRESS, VALID_PAGE);
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
+      {
+        /* Erase both Page0 and Page1 and set Page0 as valid page */
+        FlashStatus = EE_Format();
+        /* If erase/program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      break;
+
+    case RECEIVE_DATA:
+      if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
+      {
+        /* Transfer data from Page1 to Page0 */
+        for (VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)
+        {
+          if (( *(__IO uint16_t*)(PAGE0_BASE_ADDRESS + 6)) == VirtAddVarTab[VarIdx])
+          {
+            x = VarIdx;
+          }
+          if (VarIdx != x)
+          {
+            /* Read the last variables' updates */
+            ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);
+            /* In case variable corresponding to the virtual address was found */
+            if (ReadStatus != 0x1)
+            {
+              /* Transfer the variable to the Page0 */
+              EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);
+              /* If program operation was failed, a Flash error code is returned */
+              if (EepromStatus != HAL_OK)
+              {
+                return EepromStatus;
+              }
+            }
+          }
+        }
+        /* Mark Page0 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+        pEraseInit.Sector = PAGE1_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page1 */
+        if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
+      {
+        pEraseInit.Sector = PAGE1_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page1 */
+        if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+        /* Mark Page0 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      else /* Invalid state -> format eeprom */
+      {
+        /* Erase both Page0 and Page1 and set Page0 as valid page */
+        FlashStatus = EE_Format();
+        /* If erase/program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      break;
+
+    case VALID_PAGE:
+      if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
+      {
+        /* Erase both Page0 and Page1 and set Page0 as valid page */
+        FlashStatus = EE_Format();
+        /* If erase/program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
+      {
+        pEraseInit.Sector = PAGE1_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page1 */
+        if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      else /* Page0 valid, Page1 receive */
+      {
+        /* Transfer data from Page0 to Page1 */
+        for (VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)
+        {
+          if ((*(__IO uint16_t*)(PAGE1_BASE_ADDRESS + 6)) == VirtAddVarTab[VarIdx])
+          {
+            x = VarIdx;
+          }
+          if (VarIdx != x)
+          {
+            /* Read the last variables' updates */
+            ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);
+            /* In case variable corresponding to the virtual address was found */
+            if (ReadStatus != 0x1)
+            {
+              /* Transfer the variable to the Page1 */
+              EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);
+              /* If program operation was failed, a Flash error code is returned */
+              if (EepromStatus != HAL_OK)
+              {
+                return EepromStatus;
+              }
+            }
+          }
+        }
+        /* Mark Page1 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE1_BASE_ADDRESS, VALID_PAGE);        
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+        pEraseInit.Sector = PAGE0_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page0 */
+        if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      break;
+
+    default:  /* Any other state -> format eeprom */
+      /* Erase both Page0 and Page1 and set Page0 as valid page */
+      FlashStatus = EE_Format();
+      /* If erase/program operation was failed, a Flash error code is returned */
+      if (FlashStatus != HAL_OK)
+      {
+        return FlashStatus;
+      }
+      break;
+  }
+
+  return HAL_OK;
+}
+
+/**
+  * @brief  Verify if specified page is fully erased.
+  * @param  Address: page address
+  *   This parameter can be one of the following values:
+  *     @arg PAGE0_BASE_ADDRESS: Page0 base address
+  *     @arg PAGE1_BASE_ADDRESS: Page1 base address
+  * @retval page fully erased status:
+  *           - 0: if Page not erased
+  *           - 1: if Page erased
+  */
+uint16_t EE_VerifyPageFullyErased(uint32_t Address)
+{
+  uint32_t ReadStatus = 1;
+  uint16_t AddressValue = 0x5555;
+  
+  //handle page 0 check
+  if(Address < PAGE0_END_ADDRESS) {
+	  /* Check each active page address starting from end */
+	  while (Address <= PAGE0_END_ADDRESS)
+	  {
+	    /* Get the current location content to be compared with virtual address */
+	    AddressValue = (*(__IO uint16_t*)Address);
+
+	    /* Compare the read address with the virtual address */
+	    if (AddressValue != ERASED)
+	    {
+		
+		/* In case variable value is read, reset ReadStatus flag */
+		ReadStatus = 0;
+
+		break;
+	    }
+	    /* Next address location */
+	    Address = Address + 4;
+	  }
+  }
+  //handle page 0 check
+  else {
+	  /* Check each active page address starting from end */
+	  while (Address <= PAGE1_END_ADDRESS)
+	  {
+	    /* Get the current location content to be compared with virtual address */
+	    AddressValue = (*(__IO uint16_t*)Address);
+
+	    /* Compare the read address with the virtual address */
+	    if (AddressValue != ERASED)
+	    {
+		
+		/* In case variable value is read, reset ReadStatus flag */
+		ReadStatus = 0;
+
+		break;
+	    }
+	    /* Next address location */
+	    Address = Address + 4;
+	  }
+  }
+  /* Return ReadStatus value: (0: Page not erased, 1: Sector erased) */
+  return ReadStatus;
+}
+
+/**
+  * @brief  Returns the last stored variable data, if found, which correspond to
+  *   the passed virtual address
+  * @param  VirtAddress: Variable virtual address
+  * @param  Data: Global variable contains the read variable value
+  * @retval Success or error status:
+  *           - 0: if variable was found
+  *           - 1: if the variable was not found
+  *           - NO_VALID_PAGE: if no valid page was found.
+  */
+uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
+{
+  uint16_t ValidPage = PAGE0;
+  uint16_t AddressValue = 0x5555, ReadStatus = 1;
+  uint32_t Address = EEPROM_START_ADDRESS, PageStartAddress = EEPROM_START_ADDRESS;
+
+  /* Get active Page for read operation */
+  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);
+
+  /* Check if there is no valid page */
+  if (ValidPage == NO_VALID_PAGE)
+  {
+    return  NO_VALID_PAGE;
+  }
+
+  /* Get the valid Page start Address */
+  PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));
+
+  /* Get the valid Page end Address */
+  Address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));
+
+  /* Check each active page address starting from end */
+  while (Address > (PageStartAddress + 2))
+  {
+    /* Get the current location content to be compared with virtual address */
+    AddressValue = (*(__IO uint16_t*)Address);
+
+    /* Compare the read address with the virtual address */
+    if (AddressValue == VirtAddress)
+    {
+      /* Get content of Address-2 which is variable value */
+      *Data = (*(__IO uint16_t*)(Address - 2));
+
+      /* In case variable value is read, reset ReadStatus flag */
+      ReadStatus = 0;
+
+      break;
+    }
+    else
+    {
+      /* Next address location */
+      Address = Address - 4;
+    }
+  }
+
+  /* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
+  return ReadStatus;
+}
+
+/**
+  * @brief  Writes/upadtes variable data in EEPROM.
+  * @param  VirtAddress: Variable virtual address
+  * @param  Data: 16 bit data to be written
+  * @retval Success or error status:
+  *           - FLASH_COMPLETE: on success
+  *           - PAGE_FULL: if valid page is full
+  *           - NO_VALID_PAGE: if no valid page was found
+  *           - Flash error code: on write Flash error
+  */
+uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
+{
+  uint16_t Status = 0;
+
+  /* Write the variable virtual address and value in the EEPROM */
+  Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
+
+  /* In case the EEPROM active page is full */
+  if (Status == PAGE_FULL)
+  {
+    /* Perform Page transfer */
+    Status = EE_PageTransfer(VirtAddress, Data);
+  }
+
+  /* Return last operation status */
+  return Status;
+}
+
+/**
+  * @brief  Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE
+  * @param  None
+  * @retval Status of the last operation (Flash write or erase) done during
+  *         EEPROM formating
+  */
+static HAL_StatusTypeDef EE_Format(void)
+{
+  HAL_StatusTypeDef FlashStatus = HAL_OK;
+  uint32_t SectorError = 0;
+  FLASH_EraseInitTypeDef pEraseInit;
+
+  pEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;  
+  pEraseInit.Sector = PAGE0_ID;
+  pEraseInit.NbSectors = 1;
+  pEraseInit.VoltageRange = VOLTAGE_RANGE;
+  /* Erase Page0 */
+  if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+  {
+    FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError); 
+    /* If erase operation was failed, a Flash error code is returned */
+    if (FlashStatus != HAL_OK)
+    {
+      return FlashStatus;
+    }
+  }
+  /* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
+  FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE); 
+  /* If program operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+
+  pEraseInit.Sector = PAGE1_ID;
+  /* Erase Page1 */
+  if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+  {  
+    FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError); 
+    /* If erase operation was failed, a Flash error code is returned */
+    if (FlashStatus != HAL_OK)
+    {
+      return FlashStatus;
+    }
+  }
+  
+  return HAL_OK;
+}
+
+/**
+  * @brief  Find valid Page for write or read operation
+  * @param  Operation: operation to achieve on the valid page.
+  *   This parameter can be one of the following values:
+  *     @arg READ_FROM_VALID_PAGE: read operation from valid page
+  *     @arg WRITE_IN_VALID_PAGE: write operation from valid page
+  * @retval Valid page number (PAGE or PAGE1) or NO_VALID_PAGE in case
+  *   of no valid page was found
+  */
+static uint16_t EE_FindValidPage(uint8_t Operation)
+{
+  uint16_t PageStatus0 = 6, PageStatus1 = 6;
+
+  /* Get Page0 actual status */
+  PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
+
+  /* Get Page1 actual status */
+  PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
+
+  /* Write or read operation */
+  switch (Operation)
+  {
+    case WRITE_IN_VALID_PAGE:   /* ---- Write operation ---- */
+      if (PageStatus1 == VALID_PAGE)
+      {
+        /* Page0 receiving data */
+        if (PageStatus0 == RECEIVE_DATA)
+        {
+          return PAGE0;         /* Page0 valid */
+        }
+        else
+        {
+          return PAGE1;         /* Page1 valid */
+        }
+      }
+      else if (PageStatus0 == VALID_PAGE)
+      {
+        /* Page1 receiving data */
+        if (PageStatus1 == RECEIVE_DATA)
+        {
+          return PAGE1;         /* Page1 valid */
+        }
+        else
+        {
+          return PAGE0;         /* Page0 valid */
+        }
+      }
+      else
+      {
+        return NO_VALID_PAGE;   /* No valid Page */
+      }
+
+    case READ_FROM_VALID_PAGE:  /* ---- Read operation ---- */
+      if (PageStatus0 == VALID_PAGE)
+      {
+        return PAGE0;           /* Page0 valid */
+      }
+      else if (PageStatus1 == VALID_PAGE)
+      {
+        return PAGE1;           /* Page1 valid */
+      }
+      else
+      {
+        return NO_VALID_PAGE ;  /* No valid Page */
+      }
+
+    default:
+      return PAGE0;             /* Page0 valid */
+  }
+}
+
+/**
+  * @brief  Verify if active page is full and Writes variable in EEPROM.
+  * @param  VirtAddress: 16 bit virtual address of the variable
+  * @param  Data: 16 bit data to be written as variable value
+  * @retval Success or error status:
+  *           - FLASH_COMPLETE: on success
+  *           - PAGE_FULL: if valid page is full
+  *           - NO_VALID_PAGE: if no valid page was found
+  *           - Flash error code: on write Flash error
+  */
+static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data)
+{
+  HAL_StatusTypeDef FlashStatus = HAL_OK;
+  uint16_t ValidPage = PAGE0;
+  uint32_t Address = EEPROM_START_ADDRESS, PageEndAddress = EEPROM_START_ADDRESS+PAGE_SIZE;
+
+  /* Get valid Page for write operation */
+  ValidPage = EE_FindValidPage(WRITE_IN_VALID_PAGE);
+  
+  /* Check if there is no valid page */
+  if (ValidPage == NO_VALID_PAGE)
+  {
+    return  NO_VALID_PAGE;
+  }
+
+  /* Get the valid Page start Address */
+  Address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));
+
+  /* Get the valid Page end Address */
+  PageEndAddress = (uint32_t)((EEPROM_START_ADDRESS - 1) + (uint32_t)((ValidPage + 1) * PAGE_SIZE));
+
+  /* Check each active page address starting from begining */
+  while (Address < PageEndAddress)
+  {
+    /* Verify if Address and Address+2 contents are 0xFFFFFFFF */
+    if ((*(__IO uint32_t*)Address) == 0xFFFFFFFF)
+    {
+      /* Set variable data */
+      FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, Address, Data);       
+      /* If program operation was failed, a Flash error code is returned */
+      if (FlashStatus != HAL_OK)
+      {
+        return FlashStatus;
+      }
+      /* Set variable virtual address */
+      FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, Address + 2, VirtAddress);       
+      /* Return program operation status */
+      return FlashStatus;
+    }
+    else
+    {
+      /* Next address location */
+      Address = Address + 4;
+    }
+  }
+
+  /* Return PAGE_FULL in case the valid page is full */
+  return PAGE_FULL;
+}
+
+/**
+  * @brief  Transfers last updated variables data from the full Page to
+  *   an empty one.
+  * @param  VirtAddress: 16 bit virtual address of the variable
+  * @param  Data: 16 bit data to be written as variable value
+  * @retval Success or error status:
+  *           - FLASH_COMPLETE: on success
+  *           - PAGE_FULL: if valid page is full
+  *           - NO_VALID_PAGE: if no valid page was found
+  *           - Flash error code: on write Flash error
+  */
+static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)
+{
+  HAL_StatusTypeDef FlashStatus = HAL_OK;
+  uint32_t NewPageAddress = EEPROM_START_ADDRESS;
+  uint16_t OldPageId=0;
+  uint16_t ValidPage = PAGE0, VarIdx = 0;
+  uint16_t EepromStatus = 0, ReadStatus = 0;
+  uint32_t SectorError = 0;
+  FLASH_EraseInitTypeDef pEraseInit;
+
+  /* Get active Page for read operation */
+  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);
+
+  if (ValidPage == PAGE1)       /* Page1 valid */
+  {
+    /* New page address where variable will be moved to */
+    NewPageAddress = PAGE0_BASE_ADDRESS;
+
+    /* Old page ID where variable will be taken from */
+    OldPageId = PAGE1_ID;
+  }
+  else if (ValidPage == PAGE0)  /* Page0 valid */
+  {
+    /* New page address  where variable will be moved to */
+    NewPageAddress = PAGE1_BASE_ADDRESS;
+
+    /* Old page ID where variable will be taken from */
+    OldPageId = PAGE0_ID;
+  }
+  else
+  {
+    return NO_VALID_PAGE;       /* No valid Page */
+  }
+
+  /* Set the new Page status to RECEIVE_DATA status */
+  FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, NewPageAddress, RECEIVE_DATA);  
+  /* If program operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+  
+  /* Write the variable passed as parameter in the new active page */
+  EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
+  /* If program operation was failed, a Flash error code is returned */
+  if (EepromStatus != HAL_OK)
+  {
+    return EepromStatus;
+  }
+
+  /* Transfer process: transfer variables from old to the new active page */
+  for (VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)
+  {
+    if (VirtAddVarTab[VarIdx] != VirtAddress)  /* Check each variable except the one passed as parameter */
+    {
+      /* Read the other last variable updates */
+      ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);
+      /* In case variable corresponding to the virtual address was found */
+      if (ReadStatus != 0x1)
+      {
+        /* Transfer the variable to the new active page */
+        EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);
+        /* If program operation was failed, a Flash error code is returned */
+        if (EepromStatus != HAL_OK)
+        {
+          return EepromStatus;
+        }
+      }
+    }
+  }
+
+  pEraseInit.TypeErase = TYPEERASE_SECTORS;
+  pEraseInit.Sector = OldPageId;
+  pEraseInit.NbSectors = 1;
+  pEraseInit.VoltageRange = VOLTAGE_RANGE;
+  
+  /* Erase the old Page: Set old Page status to ERASED status */
+  FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);  
+  /* If erase operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+
+  /* Set new Page status to VALID_PAGE status */
+  FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, NewPageAddress, VALID_PAGE);   
+  /* If program operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+
+  /* Return last operation flash status */
+  return FlashStatus;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+  * @}
+  */ 
+
+/******************* (C) COPYRIGHT 2017 STMicroelectronics *****END OF FILE****/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/led.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,36 @@
+/*
+ * led.c - control functions for led indicator
+ *
+ * Author: Jake Greaves
+ */
+ 
+#include "led.h"
+
+extern DigitalOut status_led;
+
+Ticker led_ticker;
+
+void Led_Blink( void ) {
+	
+    Led_On(!status_led);       
+}
+
+void Led_Boot( void ) {
+	
+	// Attach interrupt to blink led
+	led_ticker.attach(Led_Blink, LED_BLINK_PERIOD);
+}
+
+void Led_Idle( void ) {
+	
+	// Set led to constantly on
+	led_ticker.detach();
+	Led_On(true);
+}
+
+void Led_On( bool_t state ) {
+	
+	// Set led state
+	status_led = state;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/myproswift_eval.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,81 @@
+
+#include "myproswift_eval.h"
+
+
+#include "mbed.h"
+#include "pc_interface.h"
+#include "ble_interface.h"
+#include "myproswift_periph.h"
+
+
+/***************************************************************
+* Function Name: MyProSwift_Command
+* Description  : read a command from either PC or BLE interfaces
+*		and handle accordingly
+****************************************************************/
+int32_t MyProSwift_Command( bool bleActive )
+{
+	uint32_t ret = 0;
+	//init buffers to 0x00
+	char msgBuffer[MSG_BUFFER_MAX_SIZE] = {0x00};
+	char bleBuffer[BLE_BUFFER_MAX_SIZE] = {0x00};
+	
+  	//setup callback routine for pc
+  	volatile bool bPcMessageFlag = 0;
+  	ret = Pc_SetupReadLineCb( msgBuffer, MSG_BUFFER_MAX_SIZE, &bPcMessageFlag );
+	if( ret != 0 ) {
+		return ret;
+	}
+  	
+	//setup callback routine for ble
+	volatile bool bBleMessageReceived = 0;
+	if( bleActive ) {
+	  //read first byte
+	  ret = Bl652_SetupReadCb( bleBuffer, 1, &bBleMessageReceived );
+	  if( ret != 0 ) {
+	  	ADI_SENSE_LOG_INFO("Ble Message Read Unsuccesful!");
+		  return ret;
+	  }
+	}
+  	
+  	//poll ble and pc flag
+  	while( !bBleMessageReceived /*&& !bPcMessageFlag */ )
+		;//add mbed abstracted sleep function
+	
+	//clear ble callbacks if needed
+	if( bleActive ) {
+	  ret = Bl652_ClearCb();
+	  if( ret != 0 ) {
+		  return ret;
+	  }
+	}
+	
+	//clear pc callbacks always
+	ret = Pc_ClearReadLineCb();
+	if( ret != 0 ) {
+		return ret;
+	}
+	
+  	//handle message based on which interface it was received from
+	if( bBleMessageReceived ) {
+		//parse and handle command
+		ADI_SENSE_LOG_INFO("Ble Message Received!");
+		ret = Ble_ParseCommand( bleBuffer );
+		ADI_SENSE_LOG_INFO("Command Parsed!");
+		if(ret != 0) {
+			//all ble side error handled within function as responses
+			return ret;
+		}
+	}
+	
+	else if(bPcMessageFlag) {
+            //parse and handle command
+		ret = Pc_ParseCommand( msgBuffer );
+		if( ret != 0 ) {
+			//all pc side error handled within function as responses
+			return ret;
+		}
+	}
+	
+	return 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/myproswift_periph.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,81 @@
+/*
+ ******************************************************************************
+ * file:   myswift_periph.cpp
+ *-----------------------------------------------------------------------------
+ */
+
+#include "myproswift_periph.h"
+
+/*
+ ******************************************************************************
+ * ADISense1000
+ *-----------------------------------------------------------------------------
+ */
+//connection information for initialising ADISense1000
+ADI_SENSE_CONNECTION connectionInfo = {
+    .type = ADI_SENSE_CONNECTION_TYPE_SPI,
+    .spi = {
+        .mosiPin    = 	SENSE_SPI_MOSI,
+        .misoPin    = 	SENSE_SPI_MISO,
+        .sckPin     = 	SENSE_SPI_SCK,
+        .csPin      = 	SENSE_SPI_CS,
+        .maxSpeedHz = 	SENSE_SPI_FREQUENCY,
+    },                  
+    .gpio = {           
+        .resetPin     = SENSE_RST_PIN,
+        .errorPin     = SENSE_ERROR_PIN,
+        .alertPin     = SENSE_ALERT_PIN,
+        .datareadyPin = SENSE_DREADY_PIN,
+    },
+};
+
+/*
+ ******************************************************************************
+ * Bluetooth Low Energy
+ *-----------------------------------------------------------------------------
+ */
+//reset pin of BLE module
+DigitalOut ble_rst(BLE_RST_PIN, 0);
+//flow control
+DigitalOut 	ble_Cts(BLE_CTS_PIN, 1);
+DigitalIn  	ble_Rts(BLE_RTS_PIN);
+
+Serial bleSerialDevice(BLE_SERIAL_TX, BLE_SERIAL_RX, BLE_BAUD_RATE);
+
+#ifdef BL652
+DigitalOut bleMode0(BLE_MODE_0_PIN, 0);
+DigitalOut bleMode1(BLE_MODE_1_PIN, 0);
+#endif
+
+
+/*
+ ******************************************************************************
+ * PC Serial
+ *-----------------------------------------------------------------------------
+ */
+
+//pointer initialised in adi_sense_Log.cpp using pins defined in this header
+Serial *gpUartDevice = new Serial(PC_UART_TX_PIN, PC_UART_RX_PIN, PC_UART_BAUDRATE);
+
+/*
+ ******************************************************************************
+ * Battery
+ *-----------------------------------------------------------------------------
+ */
+
+//pin for reading the current voltage of the battery
+//need solution to this. Battery ranges from 4.2V to 2V where the adc can only
+//read to 3.3V (VDD)
+//AnalogIn batteryV(BATTERY_V_PIN);
+
+/*
+ ******************************************************************************
+ * Status LED
+ *-----------------------------------------------------------------------------
+ */
+
+//flash when flash led is called, also iluminated when device boots successfully
+DigitalOut status_led(STATUS_LED_PIN, 0);
+//DigitalOut status_led1(PC_6, 0);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pc_interface/pc_interface.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,1458 @@
+/*
+ * pc_interface.cpp - main interface to pc application
+ *
+ * Author: Jake Greaves
+ */
+
+#include "pc_interface/pc_interface.h"
+
+#include "bootloader.h"
+
+extern DigitalOut status_led;
+	 
+extern ADI_SENSE_CONFIG adi_sense_config;
+extern ADI_SENSE_DEVICE_HANDLE hDevice;
+extern bool_t bDeviceReady;
+extern ADI_SENSE_PRODUCT_ID productId;
+
+char respBuffer[RESPONSE_BUFFER_SIZE];
+char seperatorBuf[] = {PC_SEPERATOR};
+char delimBuf[1] = {PC_DELIMITER};
+
+
+/***************************************************************
+* Function Name: pc_reset_success
+* Description  : notify that device is ready
+****************************************************************/
+int Pc_ResetSuccess(bool_t bBootLoader)
+{
+	char status[3];
+	//char hello_pc[] = "hello pc!\r\n";
+	
+	if(bBootLoader) {
+		//format error code into chars
+		//return error code indicating that we are entering bootloader mode
+		snprintf(status, sizeof(status), "%02X", NO_ERROR_BOOTLOADER);
+	}
+	
+	else {
+		//format error code into chars
+		snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	}
+	
+	//print to serial
+	Pc_Write(status, strlen(status));
+	Pc_Write(delimBuf, sizeof(delimBuf));
+	//Pc_Write(hello_pc, 11);
+	//Pc_Write(hello_pc, strlen(hello_pc));
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: pc_read_next_arg
+* Description  : read next arg, setting a flag if the delimiter is reached
+****************************************************************/
+static int pc_read_next_arg(char *command, char *arg, int size, bool *flag)
+{
+	int readPos = 0;
+	char c;
+	
+	//clear flag
+	*flag = 0;
+	
+	//read until break or buffer is used
+	for(int i = 0; i < size + 1; i++) {
+		
+		//read single char from pc
+  		c = command[0];
+		//remove c from command
+		memmove(command, command + 1, strlen(command  + 1));
+		
+		//if seperator is found, argument is in buffer, return
+		if(c == PC_SEPERATOR) {
+			arg[readPos] = '\0';
+			return 0;
+		}
+		
+		//if delimiter is found, set flag and return
+		else if(c == PC_DELIMITER) {
+			arg[readPos] = '\0';
+			*flag = 1;
+			return 0;
+		}
+		
+		//else fill buffer with char
+		else {
+			if(i < size)
+				arg[readPos] = c;
+			readPos++;
+		}
+	}
+	
+	//buffer filled, return error
+	return 1;
+}
+
+/***************************************************************
+* Function Name: pc_parse_device_info
+* Description  : get device info and return to pc
+****************************************************************/
+static int pc_parse_device_info(void) 
+{
+	//need to actually monitor this
+	char status[3];
+	char batteryVoltage[] = "3.3";
+	
+	//need to adjust hardware for this
+	//batteryV.read() * VCC;
+	
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	
+	//just a test, need to implement proper battery monitoring and firmware version control
+	Pc_Write(status, strlen(status));
+	Pc_Write(seperatorBuf, 1);
+	Pc_Write(DEVICE_NAME, strlen(DEVICE_NAME));
+	Pc_Write(seperatorBuf, 1);
+	Pc_Write(batteryVoltage, strlen(batteryVoltage));
+	Pc_Write(seperatorBuf, 1);
+	Pc_Write(FIRMWARE_VERSION, strlen(FIRMWARE_VERSION));
+	Pc_Write(delimBuf, 1);
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: pc_parse_flash_led
+* Description  : flash led to identify device
+****************************************************************/
+static int pc_parse_flash_led(void) 
+{
+	char status[3];
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	
+	//flash led
+	for(int i = 0; i < 10; i++) {
+		status_led = !status_led;
+		wait(0.05);
+	}
+	
+	//return status ok
+	Pc_Write(status, strlen(status));
+	Pc_Write(delimBuf, sizeof(delimBuf));
+	
+	return 0;
+}
+
+/***************************************************************
+* Function Name: parse_reset
+* Description  : perform a soft reset of the device
+****************************************************************/
+static int pc_parse_reset(void)
+{
+	//call CMSIS reset function
+	NVIC_SystemReset();
+	
+	//will never return as reset is called
+	return 0;
+}
+
+/***************************************************************
+* Function Name: pc_parse_configure
+* Description  : parse the configure json command
+****************************************************************/
+static int pc_parse_configure(char *commandString)
+{
+	int ret = 0;
+	bool delimiterFlag = 0;
+	char channel[32];
+	int channelIndex = (ADI_SENSE_1000_CHANNEL_ID)-2;
+	char keyword[64];
+	int keywordIndex = -1;
+	
+	//read in channel
+	pc_read_next_arg(commandString, channel, sizeof(channel), &delimiterFlag);
+	if(delimiterFlag) //if delimiter, action is complete
+		return pc_handle_error(ERROR_EXPECTED_CHANNEL);
+	
+	//read in first keyword
+	pc_read_next_arg(commandString, keyword, sizeof(keyword), &delimiterFlag);
+	if(delimiterFlag)
+		return pc_handle_error(ERROR_EXPECTED_KEYWORD);
+	
+	//find index of channel to configure
+	for(int i = -1; i < ADI_SENSE_1000_MAX_CHANNELS; i++) {
+		//cycle through conversion array, strncmp until found
+		if(!strncmp(channel, channelIdVals[i+1].stringVal, strlen(channelIdVals[i+1].stringVal))) {
+			channelIndex = i;
+			break;
+		}
+	}
+
+	//handle error, channel not found
+	if(channelIndex < -1)
+		return pc_handle_error(ERROR_EXPECTED_CHANNEL);
+
+	for(int i = 0; i < ENUM_ATTRIBUTE_SIZE; i++) {
+	//cycle through conversion array, strncmp until found
+		if(!strncmp(keyword, keywordConvert[i].stringEquiv, strlen(keywordConvert[i].stringEquiv))) {
+			keywordIndex = i;
+			break;
+		}
+	}
+	
+	//handle error, channel not found
+	if(keywordIndex < 0)
+		return pc_handle_error(ERROR_EXPECTED_KEYWORD);
+	
+	//pass channel and keyword index to configure command which parses the value and applies it to the struct
+	if(channelIndex > ADI_SENSE_1000_CHANNEL_ID_NONE)
+		ret = pc_parse_configure_channel((ADI_SENSE_1000_CHANNEL_ID)channelIndex, (CONFIG_ATTRIBUTE)keywordIndex, commandString);
+	else
+		ret = pc_parse_configure_device((CONFIG_ATTRIBUTE)keywordIndex, commandString);
+	
+	
+	if(ret != 0)
+		return pc_handle_error((ErrorType)ret);
+	
+	char status[3];
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	Pc_Write(status, strlen(status));
+	
+	//send response
+	Pc_Write(delimBuf, sizeof(delimBuf));
+
+	return ret;
+}
+
+/***************************************************************
+* Function Name: parse_configure_device
+* Description  : parse the configure_device json command
+****************************************************************/
+static int pc_parse_configure_device(CONFIG_ATTRIBUTE attribute, char *commandString)
+{
+	int valueIndex = -1;
+	char value[64];
+	bool delimiterFlag = 0;
+	char *p;
+	float32_t newRegValFloat32;
+	
+	//read in first value
+	pc_read_next_arg(commandString, value, sizeof(value), &delimiterFlag);
+	
+	for(int i = 0; i < keywordConvert[attribute].valCount; i++) {
+		if(!strncmp(value, keywordConvert[attribute].valsConvert[i].stringVal, 
+			strlen(keywordConvert[attribute].valsConvert[i].stringVal))) {
+			//value matched, store index and break
+			valueIndex = i;
+			break;
+		}
+	}
+	
+	switch(attribute) {
+	//configure global struct to reflect new configuration
+	//this struct can then be commited to write the ADISense1000 registers
+	  case PRODUCT_ID:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.productId = (ADI_SENSE_PRODUCT_ID)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+	  case POWER_MODE:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.adisense1000.power.powerMode = (ADI_SENSE_1000_POWER_MODE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+	  case OPERATIONAL_MODE:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.adisense1000.measurement.operatingMode = (ADI_SENSE_1000_OPERATING_MODE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+	  case DATA_READY_MODE:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.adisense1000.measurement.dataReadyMode = (ADI_SENSE_1000_DATAREADY_MODE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+	  case CYCLE_TIME:
+		if(valueIndex == -1) {
+			newRegValFloat32 = strtof(value, &p);
+			if(*p != '\0')
+				return (ERROR_EXPECTED_VALUE);
+		}
+		else {
+			newRegValFloat32 = (float32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		}
+		adi_sense_config.adisense1000.measurement.cycleInterval = newRegValFloat32;
+		break;
+	  case GLOBAL_DIAGNOSTICS:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.adisense1000.diagnostics.disableGlobalDiag = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+	  case MEASUREMENT_SPECIFIC_DIAGNOSTICS:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.adisense1000.diagnostics.disableMeasurementDiag = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+	  case DIAGNOSTIC_MEASUREMENT_FREQUENCY:
+		if(valueIndex == -1)
+			return (ERROR_CONVERSION_FAILED);
+		adi_sense_config.adisense1000.diagnostics.osdFrequency = (ADI_SENSE_1000_OPEN_SENSOR_DIAGNOSTICS)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+		break;
+		
+	  default:
+		return (ERROR_CONVERSION_FAILED);
+	}
+	
+	//expect command string to be fully used
+	if(delimiterFlag)
+		return 0;
+	
+	else
+		return (ERROR_EXPECTED_DELIMITER);
+}
+
+/***************************************************************
+* Function Name: parse_configure_channel
+* Description  : parse the configure_channel command
+****************************************************************/
+static int pc_parse_configure_channel(ADI_SENSE_1000_CHANNEL_ID channelIndex, CONFIG_ATTRIBUTE attribute, char *commandString)
+{
+	int valueIndex = -1;
+	char value[64];
+	bool delimiterFlag = 0;
+	char *p;
+	uint32_t newRegValUint32;
+	float32_t newRegValFloat32;
+	uint32_t sensorTimeNewVal;
+	uint32_t frontEndTimeNewVal;
+	uint32_t extraSettlingTime;
+	
+	//read in first value
+	pc_read_next_arg(commandString, value, sizeof(value), &delimiterFlag);
+	
+	//find index of value, where possible
+	for(int i = 0; i < keywordConvert[attribute].valCount; i++) {
+		if(!strncmp(value, keywordConvert[attribute].valsConvert[i].stringVal, 
+				strlen(keywordConvert[attribute].valsConvert[i].stringVal))) {
+			//value matched, store index and break
+			valueIndex = i;
+			break;
+		}
+	}
+	
+	ADI_SENSE_1000_CHANNEL_CONFIG *channel = &adi_sense_config.adisense1000.channels[channelIndex];
+	
+	//check for only analog attributes on analog channels
+	if(channelIndex < ADI_SENSE_1000_CHANNEL_ID_I2C_0) {
+	
+		switch(attribute) {
+		//configure global struct to reflect new configuration
+		//this struct can then be commited to write the ADISense1000 registers
+		  case MEASUREMENT_ENABLE:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> enableChannel = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case PUBLISH_MEASUREMENT:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> disablePublishing = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case ASSIGNED_COMPENSATION_MEASUREMENT_CHANNEL:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> compensationChannel = (ADI_SENSE_1000_CHANNEL_ID)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case DISPLAY_UNIT:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> measurementUnit = (ADI_SENSE_1000_MEASUREMENT_UNIT)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case MEASUREMENT_MIN_VALUE:
+			if(valueIndex == -1) {
+				newRegValFloat32 = strtof(value, &p);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValFloat32 = (float32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> lowThreshold = newRegValFloat32;
+			break;
+		  case MEASUREMENT_MAX_VALUE:
+			if(valueIndex == -1) {
+				newRegValFloat32 = strtof(value, &p);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValFloat32 = (float32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> highThreshold = newRegValFloat32;
+			break;
+		  case MEASUREMENTS_PER_CYCLE:
+			if(valueIndex == -1) {
+				newRegValUint32 = strtol(value, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValFloat32 = (uint32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> measurementsPerCycle = newRegValUint32;
+			break;
+		  case SETTLING_TIME:
+			if(valueIndex == -1) {
+				//check command string hasn't ended as we expect more parameters
+				if(delimiterFlag)
+					return (ERROR_EXPECTED_VALUE);
+				//parse last parameter expected to calculate extra settling time
+				char frontEndSettling[32];
+				pc_read_next_arg(commandString, frontEndSettling, sizeof(frontEndSettling), &delimiterFlag);
+				//extra settling time is equal to sensor settling - frontend. This is a check value for the ADISense1000
+				sensorTimeNewVal = strtol(value, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+				frontEndTimeNewVal = strtol(frontEndSettling, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+				
+				extraSettlingTime = sensorTimeNewVal - frontEndTimeNewVal;
+			}
+			else {
+				extraSettlingTime = (uint32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> extraSettlingTime = extraSettlingTime;
+			break;
+		  case SENSOR_TYPE:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> adcChannelConfig.sensor = (ADI_SENSE_1000_ADC_SENSOR_TYPE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case GAIN:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> adcChannelConfig.gain = (ADI_SENSE_1000_ADC_GAIN)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case EXCITATION_CURRENT:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> adcChannelConfig.current.outputLevel = (ADI_SENSE_1000_ADC_EXC_CURRENT)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case FILTER_TYPE:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> adcChannelConfig.filter.type = (ADI_SENSE_1000_ADC_FILTER_TYPE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case FILTER_FS:
+			if(valueIndex == -1) {
+				newRegValUint32 = strtol(value, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValUint32 = (uint32_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> adcChannelConfig.filter.fs = newRegValUint32;
+			break;
+		  case REFERENCE:
+			//check command string hasn't ended as we expected more parameters
+			if(delimiterFlag)
+				return (ERROR_EXPECTED_VALUE);
+			
+			//need to read in 4 args to parse this. ReferenceSelect (Value), ReferenceResistor, ReferenceResistorSelect, ReferenceVoltage.
+			char referenceResistor[32];
+			pc_read_next_arg(commandString, referenceResistor, sizeof(referenceResistor), &delimiterFlag);
+			if(delimiterFlag)
+				return (ERROR_EXPECTED_VALUE);
+			
+			char referenceResistorSelect[32];
+			pc_read_next_arg(commandString, referenceResistorSelect, sizeof(referenceResistorSelect), &delimiterFlag);
+			if(delimiterFlag)
+				return (ERROR_EXPECTED_VALUE);
+			
+			char referenceVoltage[32];
+			pc_read_next_arg(commandString, referenceVoltage, sizeof(referenceVoltage), &delimiterFlag);
+			
+			if(!strncmp(referenceResistorSelect, REF_RES_SELECT_INTERNAL, strlen(REF_RES_SELECT_INTERNAL))) {
+				if(!strncmp(value, REF_SELECT_REFIN1, strlen(REF_SELECT_REFIN1))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_RESISTOR_INTERNAL_1;
+				}
+				else if(!strncmp(value, REF_SELECT_REFIN2, strlen(REF_SELECT_REFIN2))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_RESISTOR_INTERNAL_2;
+				}
+				else
+					return (ERROR_CONVERSION_FAILED);
+			}
+			else if(!strncmp(referenceResistorSelect, REF_RES_SELECT_EXTERNAL, strlen(REF_RES_SELECT_EXTERNAL))) {
+				if(!strncmp(value, REF_SELECT_REFIN1, strlen(REF_SELECT_REFIN1))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_RESISTOR_EXTERNAL_1;
+					//strtol reference resistor to config. Not currently available
+				}
+				else if(!strncmp(value, REF_SELECT_REFIN2, strlen(REF_SELECT_REFIN2))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_RESISTOR_EXTERNAL_2;
+					//strtol reference resistor to config. Not currently available
+				}
+				else
+					return (ERROR_CONVERSION_FAILED);
+			}
+			else if(!strncmp(referenceResistorSelect, REF_RES_SELECT_NA, strlen(REF_RES_SELECT_NA))) {
+				if(!strncmp(value, REF_SELECT_REFIN1, strlen(REF_SELECT_REFIN1))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_VOLTAGE_EXTERNAL_1;
+					//strtol reference voltage to config. Not currently available
+				}
+				else if(!strncmp(value, REF_SELECT_REFIN2, strlen(REF_SELECT_REFIN2))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_VOLTAGE_EXTERNAL_2;
+					//strtol reference volatge to config. Not currently available
+				}
+				else if(!strncmp(value, REF_SELECT_INTERNAL, strlen(REF_SELECT_INTERNAL))) {
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_VOLTAGE_INTERNAL;
+				}
+				else
+					channel -> adcChannelConfig.reference.type = ADI_SENSE_1000_ADC_REFERENCE_NONE;
+			}
+			else
+				return (ERROR_CONVERSION_FAILED);
+				
+			break;
+		  case VBIAS_ENABLE:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> adcChannelConfig.enableVbias = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+			
+		  default:
+			return (ERROR_ATTR_NOT_SUPPORTED_ON_CHANNEL);
+		}
+	}
+	
+	//check for only digital attributes on digital channels
+	else if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0) {
+		
+		switch(attribute) {
+		//configure global struct to reflect new configuration
+		//this struct can then be commited to write the ADISense1000 registers
+		  case MEASUREMENT_ENABLE:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> enableChannel = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case PUBLISH_MEASUREMENT:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> disablePublishing = (bool_t)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case ASSIGNED_COMPENSATION_MEASUREMENT_CHANNEL:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> compensationChannel = (ADI_SENSE_1000_CHANNEL_ID)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case DISPLAY_UNIT:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			channel -> measurementUnit = (ADI_SENSE_1000_MEASUREMENT_UNIT)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+		  case MEASUREMENT_MIN_VALUE:
+			if(valueIndex == -1) {
+				newRegValFloat32 = strtof(value, &p);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValFloat32 = (float32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> lowThreshold = newRegValFloat32;
+			break;
+		  case MEASUREMENT_MAX_VALUE:
+			if(valueIndex == -1) {
+				newRegValFloat32 = strtof(value, &p);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValFloat32 = (float32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> highThreshold = newRegValFloat32;
+			break;
+		  case MEASUREMENTS_PER_CYCLE:
+			if(valueIndex == -1) {
+				newRegValUint32 = strtol(value, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+			}
+			else {
+				newRegValFloat32 = (uint32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> measurementsPerCycle = newRegValUint32;
+			break;
+		  case SETTLING_TIME:
+			if(valueIndex == -1) {
+				//check command string hasn't ended as we expect more parameters
+				if(delimiterFlag)
+					return (ERROR_EXPECTED_VALUE);
+				//parse last parameter expected to calculate extra settling time
+				char frontEndSettling[32];
+				pc_read_next_arg(commandString, frontEndSettling, sizeof(frontEndSettling), &delimiterFlag);
+				//extra settling time is equal to sensor settling - frontend. This is a check value for the ADISense1000
+				sensorTimeNewVal = strtol(value, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+				frontEndTimeNewVal = strtol(frontEndSettling, &p, 10);
+				if(*p != '\0')
+					return (ERROR_EXPECTED_VALUE);
+				
+				extraSettlingTime = sensorTimeNewVal - frontEndTimeNewVal;
+			}
+			else {
+				extraSettlingTime = (uint32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			channel -> extraSettlingTime = extraSettlingTime;
+			break;
+		  case SENSOR_TYPE:
+			if(valueIndex == -1)
+				return (ERROR_CONVERSION_FAILED);
+			
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0)
+				channel -> i2cChannelConfig.sensor = (ADI_SENSE_1000_I2C_SENSOR_TYPE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			else if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_SPI_0 && channelIndex < ADI_SENSE_1000_MAX_CHANNELS)
+				channel -> spiChannelConfig.sensor = (ADI_SENSE_1000_SPI_SENSOR_TYPE)keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			break;
+
+		  case DEVICE_ADDRESS:
+			if(valueIndex == -1) {
+				if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+					newRegValUint32 = strtol(value, &p, 0);
+					if(*p != '\0')
+						return (ERROR_EXPECTED_VALUE);
+					channel -> i2cChannelConfig.deviceAddress = newRegValUint32;
+				}
+				else
+					return (ERROR_CONVERSION_FAILED);
+			}
+			else {
+				channel -> i2cChannelConfig.deviceAddress = (uint32_t) keywordConvert[attribute].valsConvert[valueIndex].structVal;
+			}
+			break;
+		
+			//NOT NEEDED FOR FIRST SAMPLING
+		  /*case READ_COMMAND:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				commandBuf = strtol(value, NULL, 10);
+				memcpy(, channel -> i2cChannelConfig.dataRequestCommand.command);
+				channel -> i2cChannelConfig.dataRequestCommand.commandLength = ;
+			}
+			break;
+		  case CONFIG_COMMAND:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.configurationCommand.command = ;
+				channel -> i2cChannelConfig.configurationCommand.commandLength = ;
+			}
+			break;
+		  case NUMBER_OF_BITS:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat.numDataBits = ;
+			}
+			break;
+		  case FRAME_WIDTH:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat.frameLength = ;
+			}
+			break;
+		  case LEFT_ALIGNMENT:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat.leftJustified = ;
+			}
+			break;
+		  case DATA_ENDIANNESS:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat.littleEndian = ;
+			}
+			break;
+		  case OFFSET:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat.bitOffset = ;
+			}
+			break;
+		  case CODING:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat.coding = ;
+			}
+			break;
+		  case CPOL_CPHA:
+			if(channelIndex >= ADI_SENSE_1000_CHANNEL_ID_I2C_0 && channelIndex < ADI_SENSE_1000_CHANNEL_ID_SPI_0) {
+				channel -> i2cChannelConfig.dataFormat = ;
+			}
+			break;
+			*/
+		  default:
+			return (ERROR_ATTR_NOT_SUPPORTED_ON_CHANNEL);
+		}
+	}
+	
+	//expect that the whole command string has been used
+	if(delimiterFlag)
+		return 0;
+	
+	else
+		return (ERROR_EXPECTED_DELIMITER);
+}
+
+/***************************************************************
+* Function Name: pc_parse_apply
+* Description  : apply the config to the device
+****************************************************************/
+static int pc_parse_apply(void)
+{
+	//upload new configuration and apply
+	if(adi_sense_SetConfig(hDevice, &adi_sense_config) != ADI_SENSE_SUCCESS)
+		return pc_handle_error(ERROR_SET_CONFIG);
+	if(adi_sense_ApplyConfigUpdates(hDevice) != ADI_SENSE_SUCCESS)
+		return pc_handle_error(ERROR_UPDATE_CONFIG);
+	
+#ifdef VIRT_EEPROM
+	//Unlock the Flash Program Erase controller
+	HAL_FLASH_Unlock();
+	
+	//write adi_sense_config to eeprom
+	uint16_t *p = (uint16_t*)&adi_sense_config;
+	uint16_t temp;
+	
+	for(int i = 0; i < sizeof(adi_sense_config)/sizeof(uint16_t); i++, p++) {
+		
+		if((EE_WriteVariable(VirtAddVarTab[1] + i, *p)) != HAL_OK)
+		{
+			exit(1);
+		}
+		if((EE_WriteVariable(VirtAddVarTab[1] + i, *p)) != HAL_OK)
+		{
+			exit(1);
+		}
+		if((EE_ReadVariable(VirtAddVarTab[1] + i, &temp)) != HAL_OK)
+		{
+			exit(1);
+		}
+		if (temp != *p)
+		{
+			exit(1);
+		}
+	}
+	
+	//flag for valid configuration
+	uint16_t eepromConfigValid = 0xAF;
+	
+	//write configuration valid flag
+	if((EE_WriteVariable(VirtAddVarTab[0], eepromConfigValid)) != HAL_OK)
+	{
+		exit(1);
+	}
+	
+	//Lock the Flash Program Erase controller
+	HAL_FLASH_Lock();
+#endif
+	
+	char status[3];
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	Pc_Write(status, strlen(status));
+	
+	//send response
+	Pc_Write(delimBuf, sizeof(delimBuf));
+
+	return 0;
+}
+
+/***************************************************************
+* Function Name: data_ready_callback
+* Description  : callback for when data ready state changes
+****************************************************************/
+static void pc_data_ready_callback(
+    	ADI_SENSE_GPIO_PIN ePinId,
+    	void *pArg)
+{
+    	volatile bool_t *pbFlag = (volatile bool_t *) pArg;
+
+    	*pbFlag = true;
+}
+
+/***************************************************************
+* Function Name: pc_register_callbacks
+* Description  : callback for when data ready state changes
+****************************************************************/
+static int pc_register_callbacks(ADI_SENSE_DEVICE_HANDLE hDevice,
+    volatile bool_t *pbDataReady,
+    volatile bool_t *pbError,
+    volatile bool_t *pbAlert)
+{
+    	int res;
+
+	res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+	                                     pc_data_ready_callback, (void *)pbDataReady);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    return res;
+	}
+	
+	res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
+	                                     pc_data_ready_callback, (void *)pbError);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    return res;
+	}
+	
+	res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
+	                                     pc_data_ready_callback, (void *)pbAlert);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    return res;
+	}
+	
+	return ADI_SENSE_SUCCESS;
+}
+
+/***************************************************************
+* Function Name: pc_deregister_callbacks
+* Description  : callback for when data ready state changes
+****************************************************************/
+ADI_SENSE_RESULT pc_deregister_callbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice)
+{
+	ADI_SENSE_RESULT res;
+	
+	res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+	                                     NULL, NULL);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    return res;
+	}
+	
+	res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
+	                                     NULL, NULL);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    return res;
+	}
+	
+	res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
+	                                     NULL, NULL);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    return res;
+	}
+	
+	return ADI_SENSE_SUCCESS;
+}
+
+/***************************************************************
+* Function Name: pc_parse_sample
+* Description  : parse the sample command
+****************************************************************/
+static int pc_parse_sample(char *commandString)
+{
+	ADI_SENSE_STATUS status;
+	ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
+	ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
+	ADI_SENSE_1000_DATAREADY_MODE eDataPublishMode;
+	uint32_t nSamplesPerDataready;
+	uint32_t nSamplesPerCycle;
+	uint32_t maxMeasurementCycles;
+	ADI_SENSE_MEASUREMENT_MODE eMeasurementMode = ADI_SENSE_MEASUREMENT_MODE_NORMAL;
+	bool firstSample = true; //flag for if this is the first round of sampling, include status code
+	volatile bool_t bDataReady = false;
+	volatile bool_t bError = false;
+	volatile bool_t bAlert = false;
+
+	char *p; //check strtol has parsed correctly
+
+	char maxMeasurementCyclesString[20] = "";
+	bool delimiterFlag = 0;
+	
+	//register callbacks for status pins
+	if (pc_register_callbacks(hDevice, &bDataReady, &bError, &bAlert) != ADI_SENSE_SUCCESS)
+		return pc_handle_error(ERROR_GPIO_CALLBACK_REG);
+
+	pc_read_next_arg(commandString, maxMeasurementCyclesString, sizeof(maxMeasurementCyclesString), &delimiterFlag);
+	if(!strcmp(maxMeasurementCyclesString, "") || !strncmp(maxMeasurementCyclesString, "0", strlen("0")))
+		return pc_handle_error(ERROR_EXPECTED_VALUE);
+	if(!delimiterFlag)
+		return pc_handle_error(ERROR_EXPECTED_DELIMITER);
+
+	//convert string to integer
+	maxMeasurementCycles = strtol(maxMeasurementCyclesString, &p, 10);
+	if(*p != '\0')
+		return pc_handle_error(ERROR_EXPECTED_VALUE);
+	
+	if(maxMeasurementCycles < 1)
+		return pc_handle_error(ERROR_EXPECTED_VALUE);
+
+	//Allocate a buffer to store the samples retreived on each DATAREADY pulse
+	if(adi_sense_1000_GetDataReadyModeInfo(hDevice,
+								eMeasurementMode,
+								&eOperatingMode,
+								&eDataPublishMode,
+								&nSamplesPerDataready,
+								&nSamplesPerCycle) != ADI_SENSE_SUCCESS)
+		return pc_handle_error(ERROR_GET_DRDY_INFO);
+
+	//allocate a buffer for samples using the ADISense1000 API
+	pSampleBuffer = new ADI_SENSE_DATA_SAMPLE[nSamplesPerDataready];
+	if(pSampleBuffer == NULL)
+		return pc_handle_error(ERROR_ALLOCATE_BUFFER);
+
+	char seperatorBuf[] = {PC_SEPERATOR};
+
+	//handle the single cycle device mode
+	if (eOperatingMode == ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE) {
+		uint32_t nTotalCycles = 0;
+		
+		do {
+			//begin measurement cycles
+			if(adi_sense_StartMeasurement(hDevice, eMeasurementMode) != ADI_SENSE_SUCCESS)
+				return pc_handle_error(ERROR_START_MEASUREMENT);
+		
+			//read in each measurement cycle
+			for (unsigned i = 0; i < nSamplesPerCycle / nSamplesPerDataready; i++) {
+				uint32_t nReturned;
+			
+				//Interrupt method: wait for DATAREADY interrupt callback
+				while(!(bDataReady || bError));
+				
+				if(!bError) {
+					//reset bDataReady flag to detect the next callback
+					bDataReady = false;
+				
+					//read data into structure
+					if(adi_sense_GetData(hDevice, eMeasurementMode, pSampleBuffer, nSamplesPerDataready, &nReturned) != ADI_SENSE_SUCCESS)
+						return pc_handle_error(ERROR_GET_DATA);
+					if(nReturned != nSamplesPerDataready)
+						return pc_handle_error(ERROR_SAMPLE_COUNT_MISMATCH);
+				
+					if(firstSample) {
+						firstSample = false;
+						//begin with status byte
+						char status[3];
+						//format error code into chars
+						snprintf(status, sizeof(status), "%02X", NO_ERROR);
+						//send response
+						Pc_Write(status, sizeof(status) - 1);
+					}
+					
+					//build a response string
+					for(int i = 0; i < nReturned; i++) {
+						float32_t *sample = &pSampleBuffer[i].processedValue;
+						memcpy(respBuffer, (uint8_t*)sample, sizeof(float32_t));
+						Pc_Write(seperatorBuf, 1);
+						
+						for(int j = 0; j < sizeof(float32_t); j++) {
+							char buf[3];
+							snprintf(buf, sizeof(buf), "%02X", respBuffer[j]);
+							Pc_Write(buf, 2);
+						}
+					}
+				}
+				
+				else {
+					break;
+				}
+		
+			}
+			nTotalCycles++;
+			
+		} while (!bError && (nTotalCycles < maxMeasurementCycles));
+	}
+
+	//handle continuous measurement mode
+	else {
+		uint32_t nTotalSamples = 0;
+	
+		//begin measurement cycles
+		if(adi_sense_StartMeasurement(hDevice, eMeasurementMode) != ADI_SENSE_SUCCESS)
+			return pc_handle_error(ERROR_START_MEASUREMENT);
+	
+		do {
+			uint32_t nReturned;
+		
+			//Interrupt method: wait for DATAREADY interrupt callback
+			while(!(bDataReady || bError));
+			
+			if(!bError) {
+				//reset bDataReady flag to detect the next callback
+				bDataReady = false;
+			
+				//read data into structure
+				if(adi_sense_GetData(hDevice, eMeasurementMode, pSampleBuffer, nSamplesPerDataready, &nReturned) != ADI_SENSE_SUCCESS)
+					return pc_handle_error(ERROR_GET_DATA);
+				if(nReturned != nSamplesPerDataready)
+					return pc_handle_error(ERROR_SAMPLE_COUNT_MISMATCH);
+			
+				if(firstSample) {
+					firstSample = false;
+					//begin with status byte
+					char status[3];
+					//format error code into chars
+					snprintf(status, sizeof(status), "%02X", NO_ERROR);
+					//send response
+					Pc_Write(status, sizeof(status) - 1);
+				}
+				
+				//build a response string
+				for(int i = 0; i < nReturned; i++) {
+					float32_t *sample = &pSampleBuffer[i].processedValue;
+					memcpy(respBuffer, (uint8_t*)sample, sizeof(float32_t));
+					Pc_Write(seperatorBuf, 1);
+					for(int j = 0; j < sizeof(float32_t); j++) {
+						char buf[3];
+						snprintf(buf, sizeof(buf), "%02X", respBuffer[j]);
+						Pc_Write(buf, 2);
+					}
+				}
+				
+				//count samples
+				nTotalSamples += nReturned;
+			}
+		
+		} while (!bError && ((nTotalSamples / nSamplesPerCycle) < maxMeasurementCycles));
+	
+		if(adi_sense_StopMeasurement(hDevice) != ADI_SENSE_SUCCESS)
+			return pc_handle_error(ERROR_STOP_MEASUREMENT);
+	}
+	
+	//currently only error case is handled
+	if (bError || bAlert)
+	{
+		if(adi_sense_GetStatus(hDevice, &status) != ADI_SENSE_SUCCESS)
+			return pc_handle_error(ERROR_GET_DATA);
+
+		if (status.deviceStatus &
+		(ADI_SENSE_DEVICE_STATUS_ERROR | ADI_SENSE_DEVICE_STATUS_ALERT))
+		{
+			if (bError)
+		    		return pc_handle_error(ERROR_GET_DATA);
+		}
+	}
+
+	delete [] pSampleBuffer;
+	
+	if(pc_deregister_callbacks(hDevice) != ADI_SENSE_SUCCESS)
+	    return pc_handle_error(ERROR_GPIO_CALLBACK_REG);
+
+	Pc_Write(delimBuf, sizeof(delimBuf));
+
+	return 0;
+	
+	/*ADI_SENSE_RESULT res;
+	
+	volatile bool_t bDataReady = false;
+	volatile bool_t bError = false;
+	volatile bool_t bAlert = false;
+	res = utils_registerCallbacks(hDevice, &bDataReady, &bError, &bAlert);
+	if (res != ADI_SENSE_SUCCESS)
+	    return res;
+	
+	
+	//Retrieve the number of samples per cycle, per DATAREADY pulse, etc. for this configuration.
+	
+	ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
+	ADI_SENSE_1000_DATAREADY_MODE eDataReadyMode;
+	uint32_t nSamplesPerDataready;
+	uint32_t nSamplesPerCycle;
+	res = adi_sense_1000_GetDataReadyModeInfo(hDevice,
+	                                          eMeasurementMode,
+	                                          &eOperatingMode,
+	                                          &eDataReadyMode,
+	                                          &nSamplesPerDataready,
+	                                          &nSamplesPerCycle);
+	if (res != ADI_SENSE_SUCCESS)
+	    return res;
+
+//	 Allocate a buffer to store the samples retrieved on each DATAREADY pulse
+//	 However, if the DATAREADY pulse is per-conversion, allocate a bigger buffer
+//	 to accumulate a full cycle of samples before printing them
+//	
+	ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
+	if (eDataReadyMode == ADI_SENSE_1000_DATAREADY_PER_CONVERSION)
+	    pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) * nSamplesPerCycle);
+	else
+	    pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) * nSamplesPerDataready);
+	if (pSampleBuffer == NULL)
+	{
+	    ADI_SENSE_LOG_ERROR("Failed to allocate sample buffer");
+	    return ADI_SENSE_NO_MEM;
+	}
+	
+//	
+//	Kick off the measurement cycle(s) here
+//	
+	res = adi_sense_StartMeasurement(hDevice, eMeasurementMode);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    ADI_SENSE_LOG_ERROR("Failed to start measurement");
+	    return res;
+	}
+	
+//	
+//	Loop continuously unless operating mode is single-cycle
+//	
+	do {
+	    ADI_SENSE_STATUS status;
+	    uint32_t nCurrentSamples;
+	    uint32_t nReturned;
+	    nCurrentSamples = 0;
+	
+//	    
+//	    Accumulate the samples from a cycle and print them
+//	    NOTE: requires a sufficient idle time between cycles to allow printing to occur
+//	    
+	    do {
+//	        
+//	        Wait for the cycle to complete, continuously checking DATAREADY until it is asserted
+//	        
+	        while (! (bDataReady || bError))
+	            ;
+	
+	        if (! bError)
+	        {
+//	            
+//	            Retrieve the data samples from the measurement cycle, if no error has occurred
+//	            
+	            bDataReady = false;
+	            res = adi_sense_GetData(hDevice, eMeasurementMode, &pSampleBuffer[nCurrentSamples], nSamplesPerDataready, &nReturned);
+	            nCurrentSamples += nReturned;
+	            if (res != ADI_SENSE_SUCCESS)
+	            {
+	                if (res == ADI_SENSE_INCOMPLETE)
+	                {
+//	                     For this case, let's get the device status and print
+//	                     any samples we did get
+	                    ADI_SENSE_LOG_WARN("Failed to retrieve all requested data samples");
+	                    break;
+	                }
+	                else
+	                {
+	                    ADI_SENSE_LOG_WARN("Failed to retrieve data samples from device");
+	                    return res;
+	                }
+	            }
+	        }
+	    } while (!bError && (nCurrentSamples < nSamplesPerCycle));
+	
+//	    
+//	    Display the data samples
+//	    
+	    utils_printSamples(pSampleBuffer, nCurrentSamples);
+	
+//	    
+//	    Check and print device status if errors/alerts have been triggered
+//	    
+	    if (bError || bAlert)
+	    {
+	        res = adi_sense_GetStatus(hDevice, &status);
+	        if (res != ADI_SENSE_SUCCESS)
+	        {
+	            ADI_SENSE_LOG_ERROR("Failed to retrieve device status");
+	            return res;
+	        }
+	
+	        if (status.deviceStatus &
+	            (ADI_SENSE_DEVICE_STATUS_ERROR | ADI_SENSE_DEVICE_STATUS_ALERT))
+	        {
+	            utils_printStatus(&status);
+	
+//	             Break out of the loop if any errors are raised
+	            if (bError)
+	                break;
+	        }
+	    }
+	} while (eOperatingMode != ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE);
+	
+	res = adi_sense_StopMeasurement(hDevice);
+	if (res != ADI_SENSE_SUCCESS)
+	{
+	    ADI_SENSE_LOG_ERROR("Failed to send stop measurement");
+	    return res;
+	}
+	
+	free(pSampleBuffer);
+	
+	res = utils_deregisterCallbacks(hDevice);
+	if (res != ADI_SENSE_SUCCESS)
+	    return res;
+	
+	return ADI_SENSE_SUCCESS;*/
+}
+
+/***************************************************************
+* Function Name: pc_parse_start_stream
+* Description  : parse the stream command
+****************************************************************/
+static int pc_parse_start_stream(void) 
+{
+	ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
+	ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
+	ADI_SENSE_1000_DATAREADY_MODE eDataPublishMode;
+	uint32_t nSamplesPerDataready;
+	uint32_t nSamplesPerCycle;
+	ADI_SENSE_MEASUREMENT_MODE eMeasurementMode = ADI_SENSE_MEASUREMENT_MODE_NORMAL;
+	
+	char status[3];
+	
+	volatile bool_t bDataReady = false;
+	
+	//upload new configuration and apply
+	if(adi_sense_SetConfig(hDevice, &adi_sense_config) != ADI_SENSE_SUCCESS)
+	    return pc_handle_error(ERROR_SET_CONFIG);
+
+	if(adi_sense_ApplyConfigUpdates(hDevice) != ADI_SENSE_SUCCESS)
+	    return pc_handle_error(ERROR_UPDATE_CONFIG);
+
+	//Allocate a buffer to store the samples retreived on each DATAREADY pulse
+	if(adi_sense_1000_GetDataReadyModeInfo(hDevice,
+							  eMeasurementMode,
+							  &eOperatingMode,
+							  &eDataPublishMode,
+							  &nSamplesPerDataready,
+							  &nSamplesPerCycle) != ADI_SENSE_SUCCESS)
+	    return pc_handle_error(ERROR_GET_DRDY_INFO);
+	
+    	//allocate a buffer for samples using the ADISense1000 API
+    	pSampleBuffer = new ADI_SENSE_DATA_SAMPLE[nSamplesPerDataready];
+    	if(pSampleBuffer == NULL)
+		    return pc_handle_error(ERROR_ALLOCATE_BUFFER);
+	
+	//begin with status byte
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	//send response
+	Pc_Write(status, sizeof(status) - 1);
+	
+	//setup callback routine for pc
+  	bool bPcMessageFlag = 0;
+	char msgBuffer[1];
+  	Pc_SetupReadLineCb(msgBuffer, 1, &bPcMessageFlag);
+	  
+    	//handle the single cycle device mode
+    	if (eOperatingMode == ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE) {
+        uint32_t nTotalCycles = 0;
+
+      //interrupt-triggered DATAREADY notifications in this mode
+      if(adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+                                              pc_data_ready_callback,
+                                              (void *)&bDataReady) != ADI_SENSE_SUCCESS)
+		  return pc_handle_error(ERROR_GPIO_CALLBACK_REG);
+	  
+		do {
+			//begin measurement cycles
+			if(adi_sense_StartMeasurement(hDevice, eMeasurementMode) != ADI_SENSE_SUCCESS)
+				return pc_handle_error(ERROR_START_MEASUREMENT);
+
+			//read in each measurement cycle
+			for (unsigned i = 0; i < nSamplesPerCycle / nSamplesPerDataready; i++) {
+				uint32_t nReturned;
+
+				//Interrupt method: wait for DATAREADY interrupt callback
+				while (!bDataReady);
+
+				//reset bDataReady flag to detect the next callback
+				bDataReady = false;
+
+				//read data into structure
+				if(adi_sense_GetData(hDevice, eMeasurementMode, pSampleBuffer, nSamplesPerDataready, &nReturned) != ADI_SENSE_SUCCESS)
+				    return pc_handle_error(ERROR_GET_DATA);
+				if(nReturned != nSamplesPerDataready)
+				    return pc_handle_error(ERROR_SAMPLE_COUNT_MISMATCH);
+
+			    	//build a response string
+				for(int i = 0; i < nReturned; i++) {
+				    float32_t *sample = &pSampleBuffer[i].processedValue;
+				    memcpy(respBuffer, (uint8_t*)sample, sizeof(float32_t));
+				    Pc_Write(seperatorBuf, 1);
+				    for(int j = 0; j < sizeof(float32_t); j++) {
+					    char buf[3];
+					    snprintf(buf, sizeof(buf), "%02X", respBuffer[j]);
+					    Pc_Write(buf, 2);
+				    }
+				}
+			    
+			}
+			nTotalCycles++;
+
+			//check read byte to see if streaming should be stopped
+			if(bPcMessageFlag) {
+				if(msgBuffer[0] == COMMAND_STOP_STREAM) {
+					Pc_Write(delimBuf, sizeof(delimBuf));
+					break;
+				}
+				else
+					Pc_SetupReadLineCb(msgBuffer, 1, &bPcMessageFlag);
+			 }
+		} while (1);
+	}
+
+	//handle continuous measurement mode
+	else {
+		uint32_t nTotalSamples = 0;
+
+		//interrupt-triggered DATAREADY notifications in this mode
+		if(adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+							    pc_data_ready_callback,
+							    (void *)&bDataReady) != ADI_SENSE_SUCCESS)
+		  return pc_handle_error(ERROR_GPIO_CALLBACK_REG);
+
+		//begin measurement cycles
+		if(adi_sense_StartMeasurement(hDevice, eMeasurementMode) != ADI_SENSE_SUCCESS)
+		  return pc_handle_error(ERROR_START_MEASUREMENT);
+
+		do {
+			uint32_t nReturned;
+
+			//Interrupt method: wait for DATAREADY interrupt callback
+			while (!bDataReady);
+
+			//reset bDataReady flag to detect the next callback
+			bDataReady = false;
+			    
+			//read data into structure
+			if(adi_sense_GetData(hDevice, eMeasurementMode, pSampleBuffer, nSamplesPerDataready, &nReturned) != ADI_SENSE_SUCCESS)
+				return pc_handle_error(ERROR_GET_DATA);
+			if(nReturned != nSamplesPerDataready)
+				return pc_handle_error(ERROR_SAMPLE_COUNT_MISMATCH);
+
+			//build a response string
+			for(int i = 0; i < nReturned; i++) {
+			    float32_t *sample = &pSampleBuffer[i].processedValue;
+			    memcpy(respBuffer, (uint8_t*)sample, sizeof(float32_t));
+			    Pc_Write(seperatorBuf, 1);
+			    for(int j = 0; j < sizeof(float32_t); j++) {
+				    char buf[3];
+				    snprintf(buf, sizeof(buf), "%02X", respBuffer[j]);
+				    Pc_Write(buf, 2);
+			    }
+			}
+
+			//count samples
+			nTotalSamples += nReturned;
+
+			//check read byte to see if streaming should be stopped
+			if(bPcMessageFlag) {
+				if(msgBuffer[0] == COMMAND_STOP_STREAM) {
+					Pc_Write(delimBuf, sizeof(delimBuf));
+					break;
+				}
+				else
+					Pc_SetupReadLineCb(msgBuffer, 1, &bPcMessageFlag);
+			}
+		} while (1);
+			
+		if(adi_sense_StopMeasurement(hDevice) != ADI_SENSE_SUCCESS)
+		  return pc_handle_error(ERROR_STOP_MEASUREMENT);
+	}
+    
+	Pc_ClearReadLineCb();
+
+	delete [] pSampleBuffer;
+    
+    	//begin with status byte
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", NO_ERROR);
+	//send response
+	Pc_Write(status, sizeof(status) - 1);
+	
+   	Pc_Write(delimBuf, sizeof(delimBuf));
+    
+    	return 0;
+}
+
+/***************************************************************
+* Function Name: pc_parse_update_fw_version
+* Description  : set bootloader flag and reset device into 
+* 			mode expecting programming over serial.
+****************************************************************/
+int pc_parse_update_fw_version()
+{	
+	//set backup register flag to enter bootloader
+	Rcc_WriteBackupReg(BOOTLOADER_FLAG_BACKUP_REG, 1);
+	
+	//perform soft reset
+	return pc_parse_reset();
+}
+
+/***************************************************************
+* Function Name: handle_error
+* Description  : handle an error
+****************************************************************/
+int pc_handle_error(ErrorType error)
+{	
+	char status[3];
+	//begin with status byte
+	//format error code into chars
+	snprintf(status, sizeof(status), "%02X", error);
+	//send response
+	Pc_Write(status, sizeof(status) - 1);
+	
+	Pc_Write(delimBuf, sizeof(delimBuf));
+
+	return 1;
+}
+
+/***************************************************************
+* Function Name: Pc_ParseCommand
+* Description  : parse the configure json command
+****************************************************************/
+int Pc_ParseCommand( char *commandString )
+{
+	char c;
+	bool flag;
+	
+	pc_read_next_arg(commandString, &c, 1, &flag);
+	
+	//if no command was found, enumIndex will equal -1 and therefore execute the default case. This handles the error
+	switch(c) {	
+	
+		//pc is requesting the information packet about this device
+	  case COMMAND_DEVICE_INFO:
+	  	return pc_parse_device_info();
+
+	  	//pc is requesting this device to flash it's led to identify itself
+	  case COMMAND_FLASH_LED:
+	  	return pc_parse_flash_led();
+		
+		//soft reset the system
+	  case COMMAND_RESET:
+	  	return pc_parse_reset();
+		
+		//configure the local reg map
+	  case COMMAND_CONFIGURE:
+	  	return pc_parse_configure(commandString);
+		
+		//apply configuration to device
+	  case COMMAND_APPLY:
+	  	return pc_parse_apply();
+		
+		//return a single instance of sampling to the pc
+	  case COMMAND_SAMPLE:
+	  	return pc_parse_sample(commandString);
+
+	  	//begin streaming data to the pc, this locks out until the stopstream command is received
+	  case COMMAND_START_STREAM:
+	  	return pc_parse_start_stream();
+
+	  case COMMAND_STOP_STREAM:
+	  	return pc_handle_error(ERROR_STREAM_NOT_STARTED);
+		
+	  case COMMAND_UPDATE_FW_VERSION:
+		return pc_parse_update_fw_version();
+
+		  //Template
+		  //case COMMAND:  return parse_COMMAND();
+		  //parse_COMMAND handles the action required
+		  //COMMAND must be defined within the header file
+
+		//handle an unrecognised command/error
+		  
+	  default:
+		  return pc_handle_error(ERROR_NO_COMMAND_MATCHED);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pc_interface/pc_json_conversions.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,1 @@
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pc_interface/pc_serial.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,167 @@
+/*
+ * pc_serial.cpp - serial communcations to pc as debug
+ *                  future use for eval software
+ *
+ * Author: Jake Greaves
+ */
+
+#include "pc_interface/pc_serial.h"
+
+//init for pc comms
+extern Serial *gpUartDevice;
+
+//used by callback handler
+static char *cbSerialBuffer;
+volatile static bool *bPcMessageReceived;
+static uint32_t cbCount = 0;
+static uint32_t cbMaxSize;
+
+/***************************************************************
+* Function Name: pc_uart_callback
+* Description  : Callback for pc communications
+****************************************************************/
+static void Pc_Callback(void)
+{
+	while(gpUartDevice -> readable()) {
+		//read char and effecively clear this callback flag
+		char c = gpUartDevice -> getc();
+		
+		//check buffer is allocated
+		if(cbSerialBuffer != NULL) {
+			//store char to return buffer
+			cbSerialBuffer[cbCount] = c;
+				
+			if(c == '\n') {
+				//set flag that data has been received
+				*bPcMessageReceived = 1;
+				break;
+			}
+			else {
+				//increment count, pos in buffer
+				cbCount++;
+			}
+		}
+	}
+}
+
+/***************************************************************
+* Function Name: pc_setup_read_line_cb
+* Description  : setup callback to handle pc comms
+*		cb sets flag when full message is received
+****************************************************************/
+uint32_t Pc_SetupReadLineCb( char *rxBuffer, uint32_t maxSize, volatile bool *bMessageReadFlag ) 
+{
+  uint32_t ret = 0;
+	
+  //setup global vars for handler funtions
+  cbCount = 0;
+  cbMaxSize = maxSize;
+  
+  //assign serial callback buffer
+  if( rxBuffer != NULL ) {
+	cbSerialBuffer = rxBuffer;
+  }
+  else {
+	  return 1;
+  }
+  
+  //clear global flag
+  bPcMessageReceived = bMessageReadFlag;
+  
+  //setup callback to uart handle
+  ret = Uart_ReadCb( *gpUartDevice, Pc_Callback );
+  
+  return ret;
+}
+
+/***************************************************************
+* Function Name: pc_setup_read_line_cb
+* Description  : setup callback to handle pc comms
+*		cb sets flag when full message is received
+****************************************************************/
+uint32_t Pc_ClearReadLineCb( void )
+{
+  //clear callback to uart handle
+  return Uart_ClearCb( *gpUartDevice );
+}
+
+/***************************************************************
+* Function Name: pc_uart_callback
+* Description  : Callback for pc communications
+****************************************************************/
+uint32_t Pc_Read( char *rxBuffer, uint32_t maxSize )
+{
+    for(uint32_t i = 0; i < maxSize; i++)
+	    rxBuffer[i] = gpUartDevice -> getc();
+    
+    return 0;
+}
+
+/***************************************************************
+* Function Name: pc_write
+* Description  : write formatted string to pc terminal
+****************************************************************/
+uint32_t Pc_Write( const char* txBuffer, uint32_t size )
+{
+    //call uart functions
+    Uart_Write( *gpUartDevice, txBuffer, size );
+
+    return 0;
+}
+
+/***************************************************************
+* Function Name: pc_write_error
+* Description  : write formatted string to pc terminal
+*                   preceded by Error:
+****************************************************************/
+uint32_t Pc_WriteError( const char* txBuffer, ... )
+{
+	char buff[PC_BUFFER_SIZE];
+	
+	//precede string with error tag
+	gpUartDevice -> printf( "Error: " );
+
+	//format string to send
+	va_list args;
+	va_start( args, txBuffer );
+	vsprintf( buff, txBuffer, args );
+
+	//call uart functions
+	Uart_Write( *gpUartDevice, buff, strlen( buff ) );
+
+	//cleanup args
+	va_end( args );
+
+	return 0;
+}
+
+/***************************************************************
+* Function Name: pc_write_debug
+* Description  : write formatted string to pc terminal
+                    preceded by Debug:
+****************************************************************/
+uint32_t Pc_WriteDebug(const char* txBuffer, ...)
+{
+	char buff[PC_BUFFER_SIZE];
+
+	//precede string with debug tag
+	gpUartDevice -> printf( "Debug: " );
+
+	//format string to send
+	va_list args;
+	va_start( args, txBuffer );
+	vsprintf( buff, txBuffer, args );
+
+	//call uart functions
+	Uart_Write( *gpUartDevice, buff, strlen( buff ) );
+	gpUartDevice -> printf( "\n\r" );
+
+	//cleanup args
+	va_end(args);
+
+	return 0;
+}
+
+//EOF
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/rcc_backup_registers/rcc_backup_registers.cpp	Fri Aug 24 08:58:48 2018 +0000
@@ -0,0 +1,34 @@
+/*
+ * rcc_backup_registers.cpp - Interface functions for writing to back-up registers
+ *
+ * Author: Jake Greaves
+ */
+ 
+ 
+#include "rcc_backup_registers/rcc_backup_registers.h"
+
+
+/***************************************************************
+* Function Name: Rcc_ReadBackupReg
+* Description  : read from BackupRegister and return its value
+****************************************************************/
+uint32_t Rcc_ReadBackupReg( uint32_t BackupRegister ) 
+{
+    RTC_HandleTypeDef RtcHandle;
+    RtcHandle.Instance = RTC;
+    return HAL_RTCEx_BKUPRead(&RtcHandle, BackupRegister);
+}
+ 
+/***************************************************************
+* Function Name: Rcc_WriteBackupReg
+* Description  : write data to BackupRegister
+****************************************************************/
+void Rcc_WriteBackupReg( uint32_t BackupRegister, uint32_t data ) 
+{
+    RTC_HandleTypeDef RtcHandle;
+    RtcHandle.Instance = RTC;
+    HAL_PWR_EnableBkUpAccess();
+    HAL_RTCEx_BKUPWrite(&RtcHandle, BackupRegister, data);
+    HAL_PWR_DisableBkUpAccess();
+}
+