AT&T IoT / Mbed OS ATT_AWS_IoT_demo Featured

Dependencies:   SDFileSystem

Fork of ATT_AWS_IoT_demo by Anthony Phillips

IoT Starter Kit Powered by AWS Demo

This program demonstrates the AT&T IoT Starter Kit sending data directly into AWS IoT. It's explained and used in the Getting Started with the IoT Starter Kit Powered by AWS on starterkit.att.com.

What's required

  • AT&T IoT LTE Add-on (also known as the Cellular Shield)
  • NXP K64F - for programming
  • microSD card - used to store your AWS security credentials
  • AWS account
  • Python, locally installed

If you don't already have an IoT Starter Kit, you can purchase a kit here. The IoT Starter Kit Powered by AWS includes the LTE cellular shield, K64F, and a microSD card.

Files at this revision

API Documentation at this revision

Comitter:
ampembeng
Date:
Tue Dec 06 22:31:15 2016 +0000
Parent:
17:46780b2de3e4
Child:
19:488dad1e168e
Commit message:
Added code to support SD card access. The key/cert and MQTT information required for the demo can now be pulled from the SD card file system.

Changed in this revision

AWS_openssl/aws_iot_config.h Show annotated file Show diff for this revision Revisions of this file
AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/network_interface.h Show annotated file Show diff for this revision Revisions of this file
AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp Show annotated file Show diff for this revision Revisions of this file
AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/openssl/network.cpp Show annotated file Show diff for this revision Revisions of this file
AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_interface.h Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/SDFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/SDFileSystem.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
--- a/AWS_openssl/aws_iot_config.h	Fri Dec 02 22:49:17 2016 +0000
+++ b/AWS_openssl/aws_iot_config.h	Tue Dec 06 22:31:15 2016 +0000
@@ -21,17 +21,36 @@
 #ifndef SRC_SHADOW_IOT_SHADOW_CONFIG_H_
 #define SRC_SHADOW_IOT_SHADOW_CONFIG_H_
 
-// Get from console
+//=====================================================================================================================
+//
+// NOTE: This defines where we pull our cert/config information from.  The options are:  
+// a) Hard code MQTT defines below and in certs.cpp
+// b) Pull certs and MQTT information from SD card.
+//
+// Pull information from SD card
+#define USING_SD_CARD
+//=====================================================================================================================
+
 // =================================================
+// USER ENTERED VALUES (only used when not using SD card)
 #define AWS_IOT_MQTT_HOST              "TODO" ///< Customer specific MQTT HOST. The same will be used for Thing Shadow
-#define AWS_IOT_MQTT_PORT              8883 ///< default port for MQTT/S
+#define AWS_IOT_MQTT_PORT              8883   ///< default port for MQTT/S
 #define AWS_IOT_MQTT_CLIENT_ID         "TODO" ///< MQTT client ID should be unique for every device
 #define AWS_IOT_MY_THING_NAME 		   "TODO" ///< Thing Name of the Shadow this device is associated with
 
-// NOTE: Since the mbed-os does not use a file system these are unused (see certs.pp)
-#define AWS_IOT_ROOT_CA_FILENAME       "rootCA-certificate.crt" ///< Root CA file name
-#define AWS_IOT_CERTIFICATE_FILENAME   "certificate.pem.crt" ///< device signed certificate file name
-#define AWS_IOT_PRIVATE_KEY_FILENAME   "private.pem.key" ///< Device private key filename
+#ifdef USING_SD_CARD // These files are only valid when SD card is being used
+// Example format for mqtt_config.txt:
+/*
+AWS_IOT_MQTT_HOST=1234asdf.iot.us-west-2.amazonaws.com
+AWS_IOT_MQTT_PORT=8883
+AWS_IOT_MQTT_CLIENT_ID=MyThingName
+WS_IOT_MY_THING_NAME=MyThingName
+*/
+#define AWS_MQTT_CONFIG_FILENAME       "/sd/certs/mqtt_config.txt"        ///< Contains the info for the four defines above
+#define AWS_IOT_ROOT_CA_FILENAME       "/sd/certs/rootCA-certificate.crt" ///< Root CA file name
+#define AWS_IOT_CERTIFICATE_FILENAME   "/sd/certs/certificate.pem.crt"    ///< device signed certificate file name
+#define AWS_IOT_PRIVATE_KEY_FILENAME   "/sd/certs/private.pem.key"        ///< Device private key filename
+#endif
 // =================================================
 
 // MQTT PubSub
--- a/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/network_interface.h	Fri Dec 02 22:49:17 2016 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/network_interface.h	Tue Dec 06 22:31:15 2016 +0000
@@ -24,16 +24,18 @@
 #ifndef __NETWORK_INTERFACE_H_
 #define __NETWORK_INTERFACE_H_
 
+#include "aws_iot_shadow_interface.h"
+
 //=====================================================================================================================
 //
 // NOTE: This defines our Network Connection.  Only comment in ONE of these defines.  This setup allows us to to build
 // in multiple network targets in the future that operate off of mbed-os.
 //
 // The Avnet M14A2A Cellular Shield (uses the AT&T LTE network)
-#define USING_AVNET_SHIELD
+//#define USING_AVNET_SHIELD
 //
 // The FRDM-K64F wired Ethernet lwip
-//#define USING_FRDM_K64F_LWIP
+#define USING_FRDM_K64F_LWIP
 //=====================================================================================================================
 
 #ifdef USING_AVNET_SHIELD
@@ -96,6 +98,8 @@
  */
 int net_modem_boot(void);
 
+int mbedtls_mqtt_config_parse_file(ShadowParameters_t *sp, const char *path );
+
 /**
  * @brief Initialize the TLS implementation
  *
--- a/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp	Fri Dec 02 22:49:17 2016 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp	Tue Dec 06 22:31:15 2016 +0000
@@ -16,7 +16,6 @@
 #include <stdbool.h>
 #include <string.h>
 
-
 #include "aws_iot_config.h"
 #include "aws_iot_error.h"
 #include "aws_iot_log.h"
@@ -43,6 +42,22 @@
 extern WNCTCPSocketConnection* _tcpsocket;
 #endif
 
+// SD File System
+#include "SDFileSystem.h"
+
+// SD defines
+#define CERT_MAX_SIZE 4096
+
+// SD file pointer/buffer
+FILE *fp;
+char fp_buffer[CERT_MAX_SIZE];
+
+// From main.cpp
+extern char HostAddress[255];
+extern char MqttClientID[32];
+extern char ThingName[32];
+extern char PortString[4];
+
 /*
  * This is a function to do further verification if needed on the cert received
  */
@@ -74,119 +89,145 @@
 static mbedtls_pk_context pkey;
 static mbedtls_net_context server_fd;
 
-// TODO: We can modify these functions to pull certs from an SD card
-int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n )
+// Used to zero the given buffer
+static void mbedtls_zeroize( char *v, size_t n ) {
+	volatile char *p = v; while( n-- ) *p++ = 0;
+}
+
+// Parser sub function
+int mqtt_parse_sub(std::string *search_str, char *param, const char *str_to_find)
 {
-	//FILE *f;
-    //long size;
+	int index_start, index_end;
+	mbedtls_zeroize(param, strlen(param));
+	
+	index_start = search_str->find(str_to_find);
+	if (index_start < 0)
+	    return -1;
+	
+    index_end = search_str->find("\n", index_start); 
+    if (index_end < 0)
+	    index_end = search_str->find("\0", index_start);
+	    
+	if (index_end < 0)
+	    return -1;
+    
+    index_start += strlen(str_to_find);
+    strcpy(param, search_str->substr(index_start, index_end-index_start-1).c_str());
+    
+    return 0;
+} 
+
+// Read MQTT config info
+int mbedtls_mqtt_config_parse_file(ShadowParameters_t *sp, const char *path )
+{
+	int ret, size;
+    mbedtls_zeroize(fp_buffer, CERT_MAX_SIZE);
     
-    // Assign cert/key based on 'path'
-    /*
-    switch (path[0])
-    {
-    	case 'r':
-    	    *n = (size_t)(sizeof(AWS_IOT_ROOT_CA)/sizeof(AWS_IOT_ROOT_CA[0]));
-    	    *buf = AWS_IOT_ROOT_CA;
-    	    break;
-	    case 'c':
-	        *n = (size_t)(sizeof(AWS_IOT_CERTIFICATE)/sizeof(AWS_IOT_CERTIFICATE[0]));
-    	    *buf = AWS_IOT_CERTIFICATE;  
-	        break;
-	    case 'p':
-	        *n = (size_t)sizeof (AWS_IOT_PRIVATE_KEY);
-    	    *buf = (unsigned char *) AWS_IOT_PRIVATE_KEY; 
-    	    
-    	    //ret = mbedtls_pk_parse_key(&pkey, (unsigned char *) AWS_IOT_PRIVATE_KEY, sizeof (AWS_IOT_PRIVATE_KEY), NULL, 0 ); 
-	        break;
-	    default:
-	        ERROR(" failed\n  !  Unknown option for cert/key\n\r");
-    }*/
-
-    /*
-    if( ( f = fopen( path, "rb" ) ) == NULL )
-        return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
-
-    fseek( f, 0, SEEK_END );
-    if( ( size = ftell( f ) ) == -1 )
-    {
-        fclose( f );
-        return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
+    INFO("...Reading MQTT data from SD");
+    fp = fopen(path, "r");   
+    if (fp != NULL) {
+        size = fread(fp_buffer, sizeof(char), CERT_MAX_SIZE, fp);
+        DEBUG("...Number of data read: %d, text from file: %s", size, fp_buffer);
+        fclose(fp);
+    }
+    else {
+        ERROR("Could not open file: %s", path);
+        return -1;
+    }
+    
+    std::string filestr(fp_buffer);
+        
+    ret = mqtt_parse_sub(&filestr, HostAddress, "AWS_IOT_MQTT_HOST=");
+    sp->pHost = HostAddress;
+    INFO("...Host=%s", sp->pHost);
+    if (ret < 0) {
+        ERROR("Could not parse AWS_IOT_MQTT_HOST string.");
+        return ret;
     }
-    fseek( f, 0, SEEK_SET );
     
-    *n = (size_t) size;
+    ret = mqtt_parse_sub(&filestr, PortString, "AWS_IOT_MQTT_PORT=");
+    sp->port = atoi(PortString);
+    INFO("...Port=%d", sp->port);
+    if (ret < 0) {
+        ERROR("Could not parse AWS_IOT_MQTT_PORT string.");
+        return ret;
+    }
     
-    if( *n + 1 == 0 ||
-        ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL )
-    {
-        //fclose( f );
-        return( MBEDTLS_ERR_PK_ALLOC_FAILED );
+    ret = mqtt_parse_sub(&filestr, MqttClientID, "AWS_IOT_MQTT_CLIENT_ID=");
+    sp->pMqttClientId = MqttClientID;
+    INFO("...pMqttClientId=%s", sp->pMqttClientId);
+    if (ret < 0) {
+        ERROR("Could not parse AWS_IOT_MQTT_CLIENT_ID string.");
+        return ret;
+    }
+    
+    ret = mqtt_parse_sub(&filestr, ThingName, "AWS_IOT_MY_THING_NAME=");
+    sp->pMyThingName = ThingName;
+    INFO("...pMyThingName=%s", sp->pMyThingName);
+    if (ret < 0) {
+        ERROR("Could not parse AWS_IOT_MY_THING_NAME string.");
+        return ret;
     }
 
-    if( fread( *buf, 1, *n, f ) != *n )
-    {
-        fclose( f );
-        mbedtls_free( *buf );
-        return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
-    }
-
-    fclose( f );
-
-    (*buf)[*n] = '\0';
+    return( ret );
+}
 
-    if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
-        ++*n;
-    */
-
-    return( 0 );
-}
-// Implementation that should never be optimized out by the compiler
-static void mbedtls_zeroize( unsigned char *v, size_t n ) {
-	volatile unsigned char *p = v; while( n-- ) *p++ = 0;
-}
+// Override function: Parses CRT from SD
 int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path )
 {
-    int ret;   
-    size_t n;
-    unsigned char *buf;
-
-    if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
-        return( ret );
+    int ret, size;
+    mbedtls_zeroize(fp_buffer, CERT_MAX_SIZE);
+    
+    INFO("...Reading CERT data from SD");
+    fp = fopen(path, "r");
+    if (fp != NULL) {
+        size = fread(fp_buffer, sizeof(char), CERT_MAX_SIZE, fp);
+        DEBUG("...Number of data read: %d, text from file: %s", size, fp_buffer);
+        fclose(fp);
+    }
+    else {
+        ERROR("Could not open file: %s", path);
+        return -1;
+    }
 
     DEBUG("...CRT Parse");
-    ret = mbedtls_x509_crt_parse( chain, buf, n );
-
-    //mbedtls_zeroize( buf, n );
-    //mbedtls_free( buf );
-    
+    ret = mbedtls_x509_crt_parse( chain, (unsigned char *)fp_buffer, size+2);
+  
     return( ret );
 }
+
+// Override function: Parses KEY from SD
 int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
-                      const char *path, const char *pwd )
+                              const char *path, const char *pwd )
 {
-    int ret;  
-    size_t n;
-    unsigned char *buf;
+    int ret, size;  
+    mbedtls_zeroize(fp_buffer, CERT_MAX_SIZE);
 
-    if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
-        return( ret );
+    INFO("...Reading KEY data from SD");
+    fp = fopen(path, "r");
+    if (fp != NULL) {
+        size = fread(fp_buffer, sizeof(char), CERT_MAX_SIZE, fp);
+        DEBUG("...Number of data read: %d, text from file: %s", size, fp_buffer);
+        fclose(fp);
+    }
+    else {
+        ERROR("Could not open file: %s", path);
+        return -1;
+    }
 
     DEBUG("...Key Parse");
     if( pwd == NULL ) {
         DEBUG("...Using PWD");
-        ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 );
+        ret = mbedtls_pk_parse_key( ctx, (unsigned char *)fp_buffer, size+1, NULL, 0 );
     }
     else {
         DEBUG("...No PWD");
-        ret = mbedtls_pk_parse_key( ctx, buf, n, (const unsigned char *) pwd, strlen( pwd ) );
+        ret = mbedtls_pk_parse_key( ctx, (unsigned char *)fp_buffer, size+1, (const unsigned char *) pwd, strlen( pwd ) );
     }
-
-    //mbedtls_zeroize( buf, n );
-    //mbedtls_free( buf );
-    
+  
     return( ret );
 }
-// TODO: File system functions end
+
 
 /* personalization string for the drbg */
 const char *DRBG_PERS = "mbed TLS helloword client";
@@ -232,10 +273,11 @@
 	const char *pers = "aws_iot_tls_wrapper";
 
 	DEBUG("...Loading the CA root certificate");	
-	// TODO: We can pull the cert from an SD card
-	//ret = mbedtls_x509_crt_parse_file(&cacert, params.pRootCALocation);
+#ifdef USING_SD_CARD
+	ret = mbedtls_x509_crt_parse_file(&cacert, AWS_IOT_ROOT_CA_FILENAME);
+#else
 	ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *)AWS_IOT_ROOT_CA, strlen ((const char *)AWS_IOT_ROOT_CA)+1);
-	
+#endif
 	if (ret < 0) {
 		ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
 		return ret;
@@ -244,26 +286,28 @@
     
     
 	DEBUG("...Loading the client cert");
-	// TODO: We can pull the cert from an SD card
-	//ret = mbedtls_x509_crt_parse_file(&clicert, params.pDeviceCertLocation);
+#ifdef USING_SD_CARD
+	ret = mbedtls_x509_crt_parse_file(&clicert, AWS_IOT_CERTIFICATE_FILENAME);
+#else
 	ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *)AWS_IOT_CERTIFICATE, strlen ((const char *)AWS_IOT_CERTIFICATE)+1);
+#endif
 	if (ret != 0) {
 		ERROR(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
 		return ret;
 	}
 	DEBUG(" ok");
 	
-	
 	DEBUG("...Loading the client key");
-    // TODO: We can pull the cert from an SD card
-	//ret = mbedtls_pk_parse_keyfile(&pkey, params.pDevicePrivateKeyLocation, "");
+#ifdef USING_SD_CARD
+	ret = mbedtls_pk_parse_keyfile(&pkey, AWS_IOT_PRIVATE_KEY_FILENAME, "");
+#else
 	ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *)AWS_IOT_PRIVATE_KEY, strlen ((const char *)AWS_IOT_PRIVATE_KEY)+1, NULL, 0 );	
+#endif	
 	if (ret != 0) {
 		ERROR(" failed\n  !  mbedtls_pk_parse_key returned -0x%x\n\n", -ret);
 		return ret;
 	} 
 	DEBUG(" ok");
-	
 
 	char portBuffer[6];
 	sprintf(portBuffer, "%d", params.DestinationPort); 
--- a/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/openssl/network.cpp	Fri Dec 02 22:49:17 2016 +0000
+++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/openssl/network.cpp	Tue Dec 06 22:31:15 2016 +0000
@@ -2,6 +2,7 @@
  * @file timer.c
  * @brief mbed-os implementation of the network interface needed for AWS.
  */
+#include <stdlib.h>     /* atoi */
 #include "network_interface.h"
 #include "EthernetInterface.h"
 
@@ -60,7 +61,7 @@
     
     /* Connect to the server */
     INFO("Connecting with %s\r\n", host);
-    ret = _tcpsocket->connect(host, AWS_IOT_MQTT_PORT);
+    ret = _tcpsocket->connect(host, atoi(port));
      
     return ret;
 }
@@ -129,8 +130,7 @@
     int ret;
     
     INFO("...Connecting with %s", host);
-    ret = _tcpsocket->connect(host, AWS_IOT_MQTT_PORT);
-    _tcpsocket->bind(host, AWS_IOT_MQTT_PORT);
+    ret = _tcpsocket->connect(host, atoi(port));
     if (ret != NSAPI_ERROR_OK) {
         ERROR("Failed to connect");
         return ret;
--- a/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_interface.h	Fri Dec 02 22:49:17 2016 +0000
+++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_interface.h	Tue Dec 06 22:31:15 2016 +0000
@@ -1,243 +1,243 @@
-/*
- * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- *  http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-#ifndef AWS_IOT_SDK_SRC_IOT_SHADOW_H_
-#define AWS_IOT_SDK_SRC_IOT_SHADOW_H_
-
-
-/**
- * @file aws_iot_shadow_interface.h
- * @brief Interface for thing shadow
- *
- * These are the functions and structs to manage/interact the Thing Shadow(in the cloud).
- * This SDK will let you interact with your own thing shadow or any other shadow using its Thing Name.
- * There are totally 3 actions a device can perform on the shadow - Get, Update and Delete.
- *
- * Currently the device should use MQTT/S underneath. In the future this will also support other protocols. As it supports MQTT, the shadow needs to connect and disconnect.
- * It will also work on the pub/sub model. On performing any action, the acknowledgment will be received in either accepted or rejected. For Example:
- * If we want to perform a GET on the thing shadow the following messages will be sent and received:
- * 1. A MQTT Publish on the topic - $aws/things/{thingName}/shadow/get
- * 2. Subscribe to MQTT topics - $aws/things/{thingName}/shadow/get/accepted and $aws/things/{thingName}/shadow/get/rejected.
- * If the request was successful we will receive the things json document in the accepted topic.
- *
- *
- */
-#include "aws_iot_mqtt_interface.h"
-#include "aws_iot_shadow_json_data.h"
-
-/*!
- * @brief Shadow Connect parameters
- *
- * As the Shadow SDK uses MQTT underneath, it could be connected and disconnected on events to save some battery.
- * @note Always use the \c ShadowParametersDefault to initialize this struct
- *
- *
- *
- */
-typedef struct {
-	char *pMyThingName; ///< Every device has a Thing Shadow and this is the placeholder for name
-	char *pMqttClientId; ///< Currently the Shadow uses MQTT to connect and it is important to ensure we have unique client id
-	char *pHost; ///< This will be unique to a customer and can be retrieved from the console
-	int port; ///< By default the port is 8883
-	char *pRootCA; ///< Location with the Filename of the Root CA
-	char *pClientCRT; ///< Location of Device certs signed by AWS IoT service
-	char *pClientKey; ///< Location of Device private key
-} ShadowParameters_t;
-
-/*!
- * @brief This is set to defaults from the configuration file
- * The certs are set to NULL because they need the path to the file. shadow_sample.c file demonstrates on how to get the relative path
- *
- * \relates ShadowParameters_t
- */
-extern const ShadowParameters_t ShadowParametersDefault;
-
-
-/**
- * @brief Initialize the Thing Shadow before use
- *
- * This function takes care of initializing the internal book-keeping data structures
- *
- * @param pClient	MQTT Client used as the protocol layer
- * @return An IoT Error Type defining successful/failed Initialization
- */
-IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient);
-/**
- * @brief Connect to the AWS IoT Thing Shadow service over MQTT
- *
- * This function does the TLSv1.2 handshake and establishes the MQTT connection
- *
- * @param pClient	MQTT Client used as the protocol layer
- * @param pParams	Shadow Conenction parameters like TLS cert location
- * @return An IoT Error Type defining successful/failed Connection
- */
-IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pParams);
-/**
- * @brief Yield function to let the background tasks of MQTT and Shadow
- *
- * This function could be use in a separate thread waiting for the incoming messages, ensuring the connection is kept alive with the AWS Service.
- * It also ensures the expired requests of Shadow actions are cleared and Timeout callback is executed.
- * @note All callbacks ever used in the SDK will be executed in the context of this function.
- *
- * @param pClient	MQTT Client used as the protocol layer
- * @param timeout	in milliseconds, This is the maximum time the yield function will wait for a message and/or read the messages from the TLS buffer
- * @return An IoT Error Type defining successful/failed Yield
- */
-IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout);
-/**
- * @brief Disconnect from the AWS IoT Thing Shadow service over MQTT
- *
- * This will close the underlying TCP connection, MQTT connection will also be closed
- *
- * @param pClient	MQTT Client used as the protocol layer
- * @return An IoT Error Type defining successful/failed disconnect status
- */
-IoT_Error_t aws_iot_shadow_disconnect(MQTTClient_t *pClient);
-
-/**
- * @brief Thing Shadow Acknowledgment enum
- *
- * This enum type is use in the callback for the action response
- *
- */
-typedef enum {
-	SHADOW_ACK_TIMEOUT, SHADOW_ACK_REJECTED, SHADOW_ACK_ACCEPTED
-} Shadow_Ack_Status_t;
-
-/**
- * @brief Thing Shadow Action type enum
- *
- * This enum type is use in the callback for the action response
- *
- */
-typedef enum {
-	SHADOW_GET, SHADOW_UPDATE, SHADOW_DELETE
-} ShadowActions_t;
-
-
-/**
- * @brief Function Pointer typedef used as the callback for every action
- *
- * This function will be called from the context of \c aws_iot_shadow_yield() context
- *
- * @param pThingName Thing Name of the response received
- * @param action The response of the action
- * @param status Informs if the action was Accepted/Rejected or Timed out
- * @param pReceivedJsonDocument Received JSON document
- * @param pContextData the void* data passed in during the action call(update, get or delete)
- *
- */
-typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
-		const char *pReceivedJsonDocument, void *pContextData);
-
-/**
- * @brief This function is the one used to perform an Update action to a Thing Name's Shadow.
- *
- * update is one of the most frequently used functionality by a device. In most cases the device may be just reporting few params to update the thing shadow in the cloud
- * Update Action if no callback or if the JSON document does not have a client token then will just publish the update and not track it.
- *
- * @note The update has to subscribe to two topics update/accepted and update/rejected. This function waits 2 seconds to ensure the subscriptions are registered before publishing the update message.
- * The following steps are performed on using this function:
- * 1. Subscribe to Shadow topics - $aws/things/{thingName}/shadow/update/accepted and $aws/things/{thingName}/shadow/update/rejected
- * 2. wait for 2 seconds for the subscription to take effect
- * 3. Publish on the update topic - $aws/things/{thingName}/shadow/update
- * 4. In the \c aws_iot_shadow_yield() function the response will be handled. In case of timeout or if the response is received, the subscription to shadow response topics are un-subscribed from.
- *    On the contrary if the persistent subscription is set to true then the un-subscribe will not be done. The topics will always be listened to.
- *
- * @param pClient	MQTT Client used as the protocol layer
- * @param pThingName Thing Name of the shadow that needs to be Updated
- * @param pJsonString The update action expects a JSON document to send. The JSO String should be a null terminated string. This JSON document should adhere to the AWS IoT Thing Shadow specification. To help in the process of creating this document- SDK provides apis in \c aws_iot_shadow_json_data.h
- * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
- * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
- * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
- * @param isPersistentSubscribe As mentioned above, every  time if a device updates the same shadow then this should be set to true to avoid repeated subscription and unsubscription. If the Thing Name is one off update then this should be set to false
- * @return An IoT Error Type defining successful/failed update action
- */
-IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName, char *pJsonString,
-		fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
-
-/**
- * @brief This function is the one used to perform an Get action to a Thing Name's Shadow.
- *
- * One use of this function is usually to get the config of a device at boot up.
- * It is similar to the Update function internally except it does not take a JSON document as the input. The entire JSON document will be sent over the accepted topic
- *
- * @param pClient	MQTT Client used as the protocol layer
- * @param pThingName Thing Name of the JSON document that is needed
- * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
- * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
- * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
- * @param isPersistentSubscribe As mentioned above, every  time if a device gets the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off get then this should be set to false
- * @return An IoT Error Type defining successful/failed get action
- */
-IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
-		void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
-/**
- * @brief This function is the one used to perform an Delete action to a Thing Name's Shadow.
- *
- * This is not a very common use case for  device. It is generally the responsibility of the accompanying app to do the delete.
- * It is similar to the Update function internally except it does not take a JSON document as the input. The Thing Shadow referred by the ThingName will be deleted.
- *
- * @param pClient MQTT Client used as the protocol layer
- * @param pThingName Thing Name of the Shadow that should be deleted
- * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
- * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
- * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
- * @param isPersistentSubscribe As mentioned above, every  time if a device deletes the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off delete then this should be set to false
- * @return An IoT Error Type defining successful/failed delete action
- */
-IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
-		void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscriptions);
-
-/**
- * @brief This function is used to listen on the delta topic of #AWS_IOT_MY_THING_NAME mentioned in the aws_iot_config.h file.
- *
- * Any time a delta is published the Json document will be delivered to the pStruct->cb. If you don't want the parsing done by the SDK then use the jsonStruct_t key set to "state". A good example of this is displayed in the sample_apps/shadow_console_echo.c
- *
- * @param pClient MQTT Client used as the protocol layer
- * @param pStruct The struct used to parse JSON value
- * @return An IoT Error Type defining successful/failed delta registering
- */
-IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *pStruct);
-
-/**
- * @brief Reset the last received version number to zero.
- * This will be useful if the Thing Shadow is deleted and would like to to reset the local version
- * @return no return values
- *
- */
-void aws_iot_shadow_reset_last_received_version(void);
-/**
- * @brief Version of a document is received with every accepted/rejected and the SDK keeps track of the last received version of the JSON document of #AWS_IOT_MY_THING_NAME shadow
- *
- * One exception to this version tracking is that, the SDK will ignore the version from update/accepted topic. Rest of the responses will be scanned to update the version number.
- * Accepting version change for update/accepted may cause version conflicts for delta message if the update message is received before the delta.
- *
- * @return version number of the last received response
- *
- */
-uint32_t aws_iot_shadow_get_last_received_version(void);
-/**
- * @brief Enable the ignoring of delta messages with old version number
- *
- * As we use MQTT underneath, there could be more than 1 of the same message if we use QoS 0. To avoid getting called for the same message, this functionality should be enabled. All the old message will be ignored
- */
-void aws_iot_shadow_enable_discard_old_delta_msgs(void);
-/**
- * @brief Disable the ignoring of delta messages with old version number
- */
-void aws_iot_shadow_disable_discard_old_delta_msgs(void);
-
-#endif //AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+/*
+ * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ *  http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+#ifndef AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+#define AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+
+
+/**
+ * @file aws_iot_shadow_interface.h
+ * @brief Interface for thing shadow
+ *
+ * These are the functions and structs to manage/interact the Thing Shadow(in the cloud).
+ * This SDK will let you interact with your own thing shadow or any other shadow using its Thing Name.
+ * There are totally 3 actions a device can perform on the shadow - Get, Update and Delete.
+ *
+ * Currently the device should use MQTT/S underneath. In the future this will also support other protocols. As it supports MQTT, the shadow needs to connect and disconnect.
+ * It will also work on the pub/sub model. On performing any action, the acknowledgment will be received in either accepted or rejected. For Example:
+ * If we want to perform a GET on the thing shadow the following messages will be sent and received:
+ * 1. A MQTT Publish on the topic - $aws/things/{thingName}/shadow/get
+ * 2. Subscribe to MQTT topics - $aws/things/{thingName}/shadow/get/accepted and $aws/things/{thingName}/shadow/get/rejected.
+ * If the request was successful we will receive the things json document in the accepted topic.
+ *
+ *
+ */
+#include "aws_iot_mqtt_interface.h"
+#include "aws_iot_shadow_json_data.h"
+
+/*!
+ * @brief Shadow Connect parameters
+ *
+ * As the Shadow SDK uses MQTT underneath, it could be connected and disconnected on events to save some battery.
+ * @note Always use the \c ShadowParametersDefault to initialize this struct
+ *
+ *
+ *
+ */
+typedef struct {
+	char *pMyThingName; ///< Every device has a Thing Shadow and this is the placeholder for name
+	char *pMqttClientId; ///< Currently the Shadow uses MQTT to connect and it is important to ensure we have unique client id
+	char *pHost; ///< This will be unique to a customer and can be retrieved from the console
+	int port; ///< By default the port is 8883
+	char *pRootCA; ///< Location with the Filename of the Root CA
+	char *pClientCRT; ///< Location of Device certs signed by AWS IoT service
+	char *pClientKey; ///< Location of Device private key
+} ShadowParameters_t;
+
+/*!
+ * @brief This is set to defaults from the configuration file
+ * The certs are set to NULL because they need the path to the file. shadow_sample.c file demonstrates on how to get the relative path
+ *
+ * \relates ShadowParameters_t
+ */
+extern const ShadowParameters_t ShadowParametersDefault;
+
+
+/**
+ * @brief Initialize the Thing Shadow before use
+ *
+ * This function takes care of initializing the internal book-keeping data structures
+ *
+ * @param pClient	MQTT Client used as the protocol layer
+ * @return An IoT Error Type defining successful/failed Initialization
+ */
+IoT_Error_t aws_iot_shadow_init(MQTTClient_t *pClient);
+/**
+ * @brief Connect to the AWS IoT Thing Shadow service over MQTT
+ *
+ * This function does the TLSv1.2 handshake and establishes the MQTT connection
+ *
+ * @param pClient	MQTT Client used as the protocol layer
+ * @param pParams	Shadow Conenction parameters like TLS cert location
+ * @return An IoT Error Type defining successful/failed Connection
+ */
+IoT_Error_t aws_iot_shadow_connect(MQTTClient_t *pClient, ShadowParameters_t *pParams);
+/**
+ * @brief Yield function to let the background tasks of MQTT and Shadow
+ *
+ * This function could be use in a separate thread waiting for the incoming messages, ensuring the connection is kept alive with the AWS Service.
+ * It also ensures the expired requests of Shadow actions are cleared and Timeout callback is executed.
+ * @note All callbacks ever used in the SDK will be executed in the context of this function.
+ *
+ * @param pClient	MQTT Client used as the protocol layer
+ * @param timeout	in milliseconds, This is the maximum time the yield function will wait for a message and/or read the messages from the TLS buffer
+ * @return An IoT Error Type defining successful/failed Yield
+ */
+IoT_Error_t aws_iot_shadow_yield(MQTTClient_t *pClient, int timeout);
+/**
+ * @brief Disconnect from the AWS IoT Thing Shadow service over MQTT
+ *
+ * This will close the underlying TCP connection, MQTT connection will also be closed
+ *
+ * @param pClient	MQTT Client used as the protocol layer
+ * @return An IoT Error Type defining successful/failed disconnect status
+ */
+IoT_Error_t aws_iot_shadow_disconnect(MQTTClient_t *pClient);
+
+/**
+ * @brief Thing Shadow Acknowledgment enum
+ *
+ * This enum type is use in the callback for the action response
+ *
+ */
+typedef enum {
+	SHADOW_ACK_TIMEOUT, SHADOW_ACK_REJECTED, SHADOW_ACK_ACCEPTED
+} Shadow_Ack_Status_t;
 
+/**
+ * @brief Thing Shadow Action type enum
+ *
+ * This enum type is use in the callback for the action response
+ *
+ */
+typedef enum {
+	SHADOW_GET, SHADOW_UPDATE, SHADOW_DELETE
+} ShadowActions_t;
+
+
+/**
+ * @brief Function Pointer typedef used as the callback for every action
+ *
+ * This function will be called from the context of \c aws_iot_shadow_yield() context
+ *
+ * @param pThingName Thing Name of the response received
+ * @param action The response of the action
+ * @param status Informs if the action was Accepted/Rejected or Timed out
+ * @param pReceivedJsonDocument Received JSON document
+ * @param pContextData the void* data passed in during the action call(update, get or delete)
+ *
+ */
+typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
+		const char *pReceivedJsonDocument, void *pContextData);
+
+/**
+ * @brief This function is the one used to perform an Update action to a Thing Name's Shadow.
+ *
+ * update is one of the most frequently used functionality by a device. In most cases the device may be just reporting few params to update the thing shadow in the cloud
+ * Update Action if no callback or if the JSON document does not have a client token then will just publish the update and not track it.
+ *
+ * @note The update has to subscribe to two topics update/accepted and update/rejected. This function waits 2 seconds to ensure the subscriptions are registered before publishing the update message.
+ * The following steps are performed on using this function:
+ * 1. Subscribe to Shadow topics - $aws/things/{thingName}/shadow/update/accepted and $aws/things/{thingName}/shadow/update/rejected
+ * 2. wait for 2 seconds for the subscription to take effect
+ * 3. Publish on the update topic - $aws/things/{thingName}/shadow/update
+ * 4. In the \c aws_iot_shadow_yield() function the response will be handled. In case of timeout or if the response is received, the subscription to shadow response topics are un-subscribed from.
+ *    On the contrary if the persistent subscription is set to true then the un-subscribe will not be done. The topics will always be listened to.
+ *
+ * @param pClient	MQTT Client used as the protocol layer
+ * @param pThingName Thing Name of the shadow that needs to be Updated
+ * @param pJsonString The update action expects a JSON document to send. The JSO String should be a null terminated string. This JSON document should adhere to the AWS IoT Thing Shadow specification. To help in the process of creating this document- SDK provides apis in \c aws_iot_shadow_json_data.h
+ * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
+ * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
+ * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
+ * @param isPersistentSubscribe As mentioned above, every  time if a device updates the same shadow then this should be set to true to avoid repeated subscription and unsubscription. If the Thing Name is one off update then this should be set to false
+ * @return An IoT Error Type defining successful/failed update action
+ */
+IoT_Error_t aws_iot_shadow_update(MQTTClient_t *pClient, const char *pThingName, char *pJsonString,
+		fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
+
+/**
+ * @brief This function is the one used to perform an Get action to a Thing Name's Shadow.
+ *
+ * One use of this function is usually to get the config of a device at boot up.
+ * It is similar to the Update function internally except it does not take a JSON document as the input. The entire JSON document will be sent over the accepted topic
+ *
+ * @param pClient	MQTT Client used as the protocol layer
+ * @param pThingName Thing Name of the JSON document that is needed
+ * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
+ * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
+ * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
+ * @param isPersistentSubscribe As mentioned above, every  time if a device gets the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off get then this should be set to false
+ * @return An IoT Error Type defining successful/failed get action
+ */
+IoT_Error_t aws_iot_shadow_get(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
+		void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe);
+/**
+ * @brief This function is the one used to perform an Delete action to a Thing Name's Shadow.
+ *
+ * This is not a very common use case for  device. It is generally the responsibility of the accompanying app to do the delete.
+ * It is similar to the Update function internally except it does not take a JSON document as the input. The Thing Shadow referred by the ThingName will be deleted.
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pThingName Thing Name of the Shadow that should be deleted
+ * @param callback This is the callback that will be used to inform the caller of the response from the AWS IoT Shadow service.Callback could be set to NULL if response is not important
+ * @param pContextData This is an extra parameter that could be passed along with the callback. It should be set to NULL if not used
+ * @param timeout_seconds It is the time the SDK will wait for the response on either accepted/rejected before declaring timeout on the action
+ * @param isPersistentSubscribe As mentioned above, every  time if a device deletes the same Sahdow (JSON document) then this should be set to true to avoid repeated subscription and un-subscription. If the Thing Name is one off delete then this should be set to false
+ * @return An IoT Error Type defining successful/failed delete action
+ */
+IoT_Error_t aws_iot_shadow_delete(MQTTClient_t *pClient, const char *pThingName, fpActionCallback_t callback,
+		void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscriptions);
+
+/**
+ * @brief This function is used to listen on the delta topic of #AWS_IOT_MY_THING_NAME mentioned in the aws_iot_config.h file.
+ *
+ * Any time a delta is published the Json document will be delivered to the pStruct->cb. If you don't want the parsing done by the SDK then use the jsonStruct_t key set to "state". A good example of this is displayed in the sample_apps/shadow_console_echo.c
+ *
+ * @param pClient MQTT Client used as the protocol layer
+ * @param pStruct The struct used to parse JSON value
+ * @return An IoT Error Type defining successful/failed delta registering
+ */
+IoT_Error_t aws_iot_shadow_register_delta(MQTTClient_t *pClient, jsonStruct_t *pStruct);
+
+/**
+ * @brief Reset the last received version number to zero.
+ * This will be useful if the Thing Shadow is deleted and would like to to reset the local version
+ * @return no return values
+ *
+ */
+void aws_iot_shadow_reset_last_received_version(void);
+/**
+ * @brief Version of a document is received with every accepted/rejected and the SDK keeps track of the last received version of the JSON document of #AWS_IOT_MY_THING_NAME shadow
+ *
+ * One exception to this version tracking is that, the SDK will ignore the version from update/accepted topic. Rest of the responses will be scanned to update the version number.
+ * Accepting version change for update/accepted may cause version conflicts for delta message if the update message is received before the delta.
+ *
+ * @return version number of the last received response
+ *
+ */
+uint32_t aws_iot_shadow_get_last_received_version(void);
+/**
+ * @brief Enable the ignoring of delta messages with old version number
+ *
+ * As we use MQTT underneath, there could be more than 1 of the same message if we use QoS 0. To avoid getting called for the same message, this functionality should be enabled. All the old message will be ignored
+ */
+void aws_iot_shadow_enable_discard_old_delta_msgs(void);
+/**
+ * @brief Disable the ignoring of delta messages with old version number
+ */
+void aws_iot_shadow_disable_discard_old_delta_msgs(void);
+
+#endif //AWS_IOT_SDK_SRC_IOT_SHADOW_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/FATFileSystem.lib	Tue Dec 06 22:31:15 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#1cd59248f8bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/SDFileSystem.cpp	Tue Dec 06 22:31:15 2016 +0000
@@ -0,0 +1,462 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of:
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and
+ * indirectly determine whether it is a version 1.x SD/non-SD card or
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ *
+ * The protocol supports a CRC, but by default it is off (except for the
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think!
+ *
+ * Standard capacity cards have variable data block sizes, whereas High
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then
+ * a data token or an error.
+ *
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] |
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+#include "SDFileSystem.h"
+#include "mbed_debug.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+#define SD_DBG             0
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+    FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+    _cs = 1;
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+#define SDCARD_FAIL 0 //!< v1.x Standard Capacity
+#define SDCARD_V1   1 //!< v2.x Standard Capacity
+#define SDCARD_V2   2 //!< v2.x High Capacity
+#define SDCARD_V2HC 3 //!< Not recognised as an SD Card
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000);
+    _cs = 1;
+    for (int i = 0; i < 16; i++) {
+        _spi.write(0xFF);
+    }
+    
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if (_cmd(0, 0) != R1_IDLE_STATE) {
+        debug("No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+    
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if (r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        debug("Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0);
+        if (_cmd(41, 0) == 0) {
+            cdv = 512;
+            debug_if(SD_DBG, "\n\rInit: SEDCARD_V1\n\r");
+            return SDCARD_V1;
+        }
+    }
+    
+    debug("Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        wait_ms(50);
+        _cmd58();
+        _cmd(55, 0);
+        if (_cmd(41, 0x40000000) == 0) {
+            _cmd58();
+            debug_if(SD_DBG, "\n\rInit: SDCARD_V2\n\r");
+            cdv = 1;
+            return SDCARD_V2;
+        }
+    }
+    
+    debug("Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+    int i = initialise_card();
+    debug_if(SD_DBG, "init card = %d\n", i);
+    _sectors = _sd_sectors();
+    
+    // Set block length to 512 (CMD16)
+    if (_cmd(16, 512) != 0) {
+        debug("Set 512-byte block timed out\n");
+        return 1;
+    }
+    
+    _spi.frequency(1000000); // Set to 1MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const uint8_t *buffer, uint64_t block_number) {
+    // set write address for single block (CMD24)
+    if (_cmd(24, block_number * cdv) != 0) {
+        return 1;
+    }
+    
+    // send the data block
+    _write(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_read(uint8_t *buffer, uint64_t block_number) {
+    // set read address for single block (CMD17)
+    if (_cmd(17, block_number * cdv) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+uint64_t SDFileSystem::disk_sectors() { return _sectors; }
+
+
+// PRIVATE FUNCTIONS
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0;
+    
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if (!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0;
+    
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if (!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0;
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if (!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0;
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if (!(response[0] & 0x80)) {
+            for (int j = 1; j < 5; j++) {
+                response[i] = _spi.write(0xFF);
+            }
+            _cs = 1;
+            _spi.write(0xFF);
+            return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
+    _cs = 0;
+    
+    // read until start byte (0xFF)
+    while (_spi.write(0xFF) != 0xFE);
+    
+    // read data
+    for (int i = 0; i < length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+    
+    _cs = 1;
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for (int i = 0; i < length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    
+    // check the response token
+    if ((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);
+        return 1;
+    }
+    
+    // wait for write to finish
+    while (_spi.write(0xFF) == 0);
+    
+    _cs = 1;
+    _spi.write(0xFF);
+    return 0;
+}
+
+static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
+    uint32_t bits = 0;
+    uint32_t size = 1 + msb - lsb;
+    for (int i = 0; i < size; i++) {
+        uint32_t position = lsb + i;
+        uint32_t byte = 15 - (position >> 3);
+        uint32_t bit = position & 0x7;
+        uint32_t value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+uint64_t SDFileSystem::_sd_sectors() {
+    uint32_t c_size, c_size_mult, read_bl_len;
+    uint32_t block_len, mult, blocknr, capacity;
+    uint32_t hc_c_size;
+    uint64_t blocks;
+    
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if (_cmdx(9, 0) != 0) {
+        debug("Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    uint8_t csd[16];
+    if (_read(csd, 16) != 0) {
+        debug("Couldn't read csd response from disk\n");
+        return 0;
+    }
+    
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+    
+    int csd_structure = ext_bits(csd, 127, 126);
+    
+    switch (csd_structure) {
+        case 0:
+            cdv = 512;
+            c_size = ext_bits(csd, 73, 62);
+            c_size_mult = ext_bits(csd, 49, 47);
+            read_bl_len = ext_bits(csd, 83, 80);
+            
+            block_len = 1 << read_bl_len;
+            mult = 1 << (c_size_mult + 2);
+            blocknr = (c_size + 1) * mult;
+            capacity = blocknr * block_len;
+            blocks = capacity / 512;
+            debug_if(SD_DBG, "\n\rSDCard\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks);
+            break;
+        
+        case 1:
+            cdv = 1;
+            hc_c_size = ext_bits(csd, 63, 48);
+            blocks = (hc_c_size+1)*1024;
+            debug_if(SD_DBG, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks);
+            break;
+        
+        default:
+            debug("CSD struct unsupported\r\n");
+            return 0;
+    };
+    return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/SDFileSystem.h	Tue Dec 06 22:31:15 2016 +0000
@@ -0,0 +1,84 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MBED_SDFILESYSTEM_H
+#define MBED_SDFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+#include <stdint.h>
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // MOSI, MISO, SCLK, SSEL
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/mbed.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ * @endcode
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    
+    virtual int disk_initialize();
+    virtual int disk_status();
+    virtual int disk_read(uint8_t * buffer, uint64_t block_number);
+    virtual int disk_write(const uint8_t * buffer, uint64_t block_number);
+    virtual int disk_sync();
+    virtual uint64_t disk_sectors();
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(uint8_t * buffer, uint32_t length);
+    int _write(const uint8_t *buffer, uint32_t length);
+    uint64_t _sd_sectors();
+    uint64_t _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs;
+    int cdv;
+};
+
+#endif
--- a/main.cpp	Fri Dec 02 22:49:17 2016 +0000
+++ b/main.cpp	Tue Dec 06 22:31:15 2016 +0000
@@ -3,6 +3,9 @@
  */
 #include "mbed.h"
 
+// SD File System
+#include "SDFileSystem.h"
+
 // Serial extension
 #include "MODSERIAL.h"
 
@@ -36,7 +39,7 @@
 #define NUM_COLORS   5
 
 // AWS defines
-#define PATH_MAX    4096
+#define PATH_MAX    1024
 #define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200 // NOTE: Be wary of this if your JSON doc grows
 #define SHADOW_SYNC_INTERVAL 3.0             // How often we sync with AWS Shadow (in seconds)
 
@@ -79,13 +82,11 @@
 bool buttonOverride = false;
 InterruptIn Interrupt(SW3);
 
-// Default cert location
-//char certDirectory[PATH_MAX + 1] = "../../../certs";
-
-// Default MQTT HOST URL is pulled from the aws_iot_config.h
+// These defines are pulled from aws_iot_config.h
 char HostAddress[255] = AWS_IOT_MQTT_HOST;
-
-// Default MQTT port is pulled from the aws_iot_config.h
+char MqttClientID[32] = AWS_IOT_MQTT_CLIENT_ID;
+char ThingName[32] = AWS_IOT_MY_THING_NAME;
+char PortString[5] = "8883";
 uint32_t port = AWS_IOT_MQTT_PORT;
 
 //=====================================================================================================================
@@ -101,6 +102,9 @@
 // USB Serial port (to PC)
 MODSERIAL pc(USBTX,USBRX,256,256);
 
+// SD card access (MOSI, MISO, SCK, CS)
+SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd");
+
 //=====================================================================================================================
 //
 // Functions
@@ -122,7 +126,7 @@
 //* LED Color 0=Off to 7=White.  3 bits represent BGR (bit0=Red, bit1=Green, bit2=Blue) 
 //*********************************************************************************************************************
 void SetLedColor(unsigned char ucColor)
-{
+{    
     //Note that when an LED is on, you write a 0 to it:
     led_red = !(ucColor & 0x1); //bit 0
     led_green = !(ucColor & 0x2); //bit 1
@@ -236,25 +240,16 @@
     
     INFO("AWS IoT SDK Version(dev) %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
 
-    // TODO: We could try to pull the certs from an SD card
-    /*
-    char rootCA[PATH_MAX + 1];
-    char clientCRT[PATH_MAX + 1];
-    char clientKey[PATH_MAX + 1];
-    char CurrentWD[PATH_MAX + 1];
-    char cafileName[] = AWS_IOT_ROOT_CA_FILENAME;
-    char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME;
-    char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME;
-  
-    getcwd(CurrentWD, sizeof(CurrentWD));
-    sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName);
-    sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName);
-    sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName);
-
-    DEBUG("Using rootCA %s", rootCA);
-    DEBUG("Using clientCRT %s", clientCRT);
-    DEBUG("Using clientKey %s", clientKey);
-    */
+#ifdef USING_SD_CARD
+    // Paths for certs from SD card
+    INFO("Using SD card files for AWS config.");  
+    DEBUG("- mqtt config path: %s", AWS_MQTT_CONFIG_FILENAME);
+    DEBUG("- rootCA path: %s", AWS_IOT_ROOT_CA_FILENAME);
+    DEBUG("- clientCRT path: %s", AWS_IOT_CERTIFICATE_FILENAME);
+    DEBUG("- clientKey path: %s", AWS_IOT_PRIVATE_KEY_FILENAME);
+#else
+    INFO("Using #defines in aws_iot_config.h and certs from certs.cpp for AWS config.");      
+#endif
     
     // Startup signal - blinks through RGBW then turns off
     SetLedColor(COLOR_RED);
@@ -266,28 +261,34 @@
     SetLedColor(COLOR_WHITE);
     wait(.5);
     SetLedColor(COLOR_OFF);
-    
+      
     // Setup SW3 button to falling edge interrupt
     Interrupt.fall(&sw3ButtonHandler);
       
     // Boot the Avnet Shield before any other operations
     net_modem_boot();
       
-    INFO("Initialize the MQTT client...");
-    MQTTClient_t mqttClient;
-    aws_iot_mqtt_init(&mqttClient);
-
+    // Intialize MQTT/Cert parameters
     ShadowParameters_t sp = ShadowParametersDefault;
+#ifdef USING_SD_CARD
+    rc = (IoT_Error_t)mbedtls_mqtt_config_parse_file(&sp, AWS_MQTT_CONFIG_FILENAME);
+    if (NONE_ERROR != rc) {
+        ERROR("Failed to initialize mqtt parameters %d", rc);
+        return rc;
+    }   
+    sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME;
+    sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME;
+    sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME;
+#else
     sp.pMyThingName = AWS_IOT_MY_THING_NAME;
     sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
     sp.pHost = HostAddress;
     sp.port = port;
-    //sp.pClientCRT = clientCRT;
-    //sp.pClientKey = clientKey;
-    //sp.pRootCA = rootCA;
-    sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME;
-    sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME;
-    sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME;
+#endif
+
+    INFO("Initialize the MQTT client...");
+    MQTTClient_t mqttClient;
+    aws_iot_mqtt_init(&mqttClient);
 
     INFO("Shadow Init...");
     rc = aws_iot_shadow_init(&mqttClient);
@@ -357,14 +358,32 @@
                             
                 if (rc == NONE_ERROR) {
                     INFO("Update Shadow: %s", JsonDocumentBuffer);
-                    rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, JsonDocumentBuffer,
+                    rc = aws_iot_shadow_update(&mqttClient, sp.pMyThingName, JsonDocumentBuffer,
                             ShadowUpdateStatusCallback, NULL, 8, true);
                 }
             }
         }      
-        INFO("*****************************************************************************************\n");
-         
-        // Set LED color then wait an loop again     
+                
+        // Set LED color then wait an loop again
+        switch (ledColor) {
+             case COLOR_OFF:
+                 INFO("LED: OFF");
+                 break;
+             case COLOR_RED:
+                 INFO("LED: RED");
+                 break;
+             case COLOR_GREEN:
+                 INFO("LED: GREEN");
+                 break;
+             case COLOR_BLUE:
+                 INFO("LED: BLUE");
+                 break;
+             case COLOR_WHITE:
+                 INFO("LED: WHITE");
+                 break;
+        }
+        INFO("*****************************************************************************************");
+             
         SetLedColor(ledColor);
         wait(SHADOW_SYNC_INTERVAL);
     }