A modelling and serializer library for Microsoft Azure IoTHub client applications

Dependents:   sht15_remote_monitoring f767zi_mqtt remote_monitoring simplesample_amqp ... more

This library implements a serializer library to be used in projects involving Microsoft Azure IoT Hub connectivity. The code is replicated from https://github.com/Azure/azure-iot-sdks

Revision:
18:58b667752399
Parent:
17:fa1bba4c6053
Child:
22:422d94bd3c18
--- a/serializer_devicetwin.h	Wed Nov 16 21:38:26 2016 -0800
+++ b/serializer_devicetwin.h	Wed Dec 14 16:00:39 2016 -0800
@@ -11,6 +11,7 @@
 #include "iothub_client_ll.h"
 #include "parson.h"
 #include "vector.h"
+#include "methodreturn.h"
 
 static void serializer_ingest(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
 {
@@ -126,6 +127,74 @@
     }
 }
 
+/*both LL and convenience layer can be served by the same callback*/
+static int deviceMethodCallback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* userContextCallback)
+{
+    int result;
+    /*Codes_SRS_SERIALIZERDEVICETWIN_02_021: [ deviceMethodCallback shall transform payload and size into a null terminated string. ]*/
+    char* payloadZeroTerminated = (char*)malloc(size + 1);
+    if (payloadZeroTerminated == NULL)
+    {
+        LogError("failure in malloc");
+        /*Codes_SRS_SERIALIZERDEVICETWIN_02_026: [ If any failure occurs in the above operations, then deviceMethodCallback shall fail, return 500, set *response to NULL and '*resp_size` to 0. ]*/
+        *response = NULL;
+        *resp_size = 0;
+        result = 500;
+    }
+    else
+    {
+        memcpy(payloadZeroTerminated, payload, size);
+        payloadZeroTerminated[size] = '\0';
+
+        /*Codes_SRS_SERIALIZERDEVICETWIN_02_022: [ deviceMethodCallback shall call EXECUTE_METHOD passing the userContextCallback, method_name and the null terminated string build before. ]*/
+        METHODRETURN_HANDLE mr = EXECUTE_METHOD(userContextCallback, method_name, payloadZeroTerminated);
+        
+        if (mr == NULL)
+        {
+            LogError("failure in EXECUTE_METHOD");
+            /*Codes_SRS_SERIALIZERDEVICETWIN_02_026: [ If any failure occurs in the above operations, then deviceMethodCallback shall fail, return 500, set *response to NULL and '*resp_size` to 0. ]*/
+            *response = NULL;
+            *resp_size = 0;
+            result = 500;
+        }
+        else
+        {
+            /*Codes_SRS_SERIALIZERDEVICETWIN_02_023: [ deviceMethodCallback shall get the MethodReturn_Data and shall copy the response JSON value into a new byte array. ]*/
+            const METHODRETURN_DATA* data = MethodReturn_GetReturn(mr);
+
+            /*Codes_SRS_SERIALIZERDEVICETWIN_02_025: [ deviceMethodCallback returns the statusCode from the user. ]*/
+            result = data->statusCode;
+
+            if (data->jsonValue == NULL)
+            {
+                *resp_size = 0;
+                *response = NULL;
+            }
+            else
+            {
+                *resp_size = strlen(data->jsonValue);
+                *response = (unsigned char*)malloc(*resp_size);
+                if (*response == NULL)
+                {
+                    LogError("failure in malloc");
+                    /*Codes_SRS_SERIALIZERDEVICETWIN_02_026: [ If any failure occurs in the above operations, then deviceMethodCallback shall fail, return 500, set *response to NULL and '*resp_size` to 0. ]*/
+                    *response = NULL;
+                    *resp_size = 0;
+                    result = 500;
+                }
+                else
+                {
+                    /*Codes_SRS_SERIALIZERDEVICETWIN_02_024: [ deviceMethodCallback shall set *response to this new byte array, *resp_size to the size of the array. ]*/
+                    memcpy(*response, data->jsonValue, *resp_size);
+                }
+            }
+            MethodReturn_Destroy(mr);
+        }
+        free(payloadZeroTerminated);
+    }
+    return result;
+}
+
 /*an enum that sets the type of the handle used to record IoTHubDeviceTwin_Create was called*/
 #define IOTHUB_CLIENT_HANDLE_TYPE_VALUES \
     IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE, \
@@ -184,7 +253,7 @@
     return result;
 }
 
-static IOTHUB_CLIENT_RESULT Generic_IoTHubClient_SetDeviceTwinCallback(const SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
+static IOTHUB_CLIENT_RESULT Generic_IoTHubClient_SetCallbacks(const SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
 {
     IOTHUB_CLIENT_RESULT result;
     /*Codes_SRS_SERIALIZERDEVICETWIN_02_011: [ IoTHubDeviceTwinCreate_Impl shall set the device twin callback. ]*/
@@ -196,6 +265,15 @@
         {
             LogError("failure in IoTHubClient_SetDeviceTwinCallback");
         }
+        else
+        {
+            /*Codes_SRS_SERIALIZERDEVICETWIN_02_027: [ IoTHubDeviceTwinCreate_Impl shall set the device method callback ]*/
+            if ((result = IoTHubClient_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, deviceMethodCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
+            {
+                (void)IoTHubClient_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, NULL, NULL);
+                LogError("failure in IoTHubClient_SetDeviceMethodCallback");
+            }
+        }
         break;
     }
     case IOTHUB_CLIENT_LL_HANDLE_TYPE:
@@ -204,6 +282,15 @@
         {
             LogError("failure in IoTHubClient_LL_SetDeviceTwinCallback");
         }
+        else
+        {
+            /*Codes_SRS_SERIALIZERDEVICETWIN_02_027: [ IoTHubDeviceTwinCreate_Impl shall set the device method callback ]*/
+            if ((result = IoTHubClient_LL_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, deviceMethodCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
+            {
+                (void)IoTHubClient_LL_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, NULL, NULL);
+                LogError("failure in IoTHubClient_SetDeviceMethodCallback");
+            }
+        }
         break;
     }
     default:
@@ -249,10 +336,10 @@
             else
             {
                 protoHandle->deviceAssigned = result;
-                if (Generic_IoTHubClient_SetDeviceTwinCallback(protoHandle, serializer_ingest, result) != IOTHUB_CLIENT_OK)
+                if (Generic_IoTHubClient_SetCallbacks(protoHandle, serializer_ingest, result) != IOTHUB_CLIENT_OK)
                 {
                     /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
-                    LogError("failure in Generic_IoTHubClient_SetDeviceTwinCallback");
+                    LogError("failure in Generic_IoTHubClient_SetCallbacks");
                     CodeFirst_DestroyDevice(result);
                     result = NULL;
                 }
@@ -266,10 +353,10 @@
                         /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
                         LogError("unable to add the protohandle to the collection of handles");
                         /*unsubscribe*/
-                        if (Generic_IoTHubClient_SetDeviceTwinCallback(protoHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
+                        if (Generic_IoTHubClient_SetCallbacks(protoHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
                         {
                             /*just log the error*/
-                            LogError("failure in Generic_IoTHubClient_SetDeviceTwinCallback");
+                            LogError("failure in Generic_IoTHubClient_SetCallbacks");
                         }
                         CodeFirst_DestroyDevice(result);
                         result = NULL;
@@ -318,6 +405,11 @@
                 {
                     LogError("failure in IoTHubClient_SetDeviceTwinCallback");
                 }
+                /*Codes_SRS_SERIALIZERDEVICETWIN_02_028: [ IoTHubDeviceTwin_Destroy_Impl shall set the method callback to NULL. ]*/
+                if (IoTHubClient_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
+                {
+                    LogError("failure in IoTHubClient_SetDeviceMethodCallback");
+                }
                 break;
             }
             case IOTHUB_CLIENT_LL_HANDLE_TYPE:
@@ -326,6 +418,11 @@
                 {
                     LogError("failure in IoTHubClient_LL_SetDeviceTwinCallback");
                 }
+                /*Codes_SRS_SERIALIZERDEVICETWIN_02_028: [ IoTHubDeviceTwin_Destroy_Impl shall set the method callback to NULL. ]*/
+                if (IoTHubClient_LL_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
+                {
+                    LogError("failure in IoTHubClient_LL_SetDeviceMethodCallback");
+                }
                 break;
             }
             default:
@@ -350,6 +447,71 @@
     }
 }
 
+/*the below function sends the reported state of a model previously created by IoTHubDeviceTwin_Create*/
+/*this function serves both the _LL and the convenience layer because of protohandles*/
+static IOTHUB_CLIENT_RESULT IoTHubDeviceTwin_SendReportedState_Impl(void* model, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK deviceTwinCallback, void* context)
+{
+    unsigned char*buffer;
+    size_t bufferSize;
+
+    IOTHUB_CLIENT_RESULT result;
+
+    if (SERIALIZE_REPORTED_PROPERTIES_FROM_POINTERS(&buffer, &bufferSize, model) != CODEFIRST_OK)
+    {
+        LogError("Failed serializing reported state");
+        result = IOTHUB_CLIENT_ERROR;
+    }
+    else
+    {
+        SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle = (SERIALIZER_DEVICETWIN_PROTOHANDLE*)VECTOR_find_if(g_allProtoHandles, protoHandleHasDeviceStartAddress, model);
+        if (protoHandle == NULL)
+        {
+            LogError("failure in VECTOR_find_if [not found]");
+            result = IOTHUB_CLIENT_ERROR;
+        }
+        else
+        {
+            switch (protoHandle->iothubClientHandleVariant.iothubClientHandleType)
+            {
+                case IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE:
+                {
+                    if (IoTHubClient_SendReportedState(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, buffer, bufferSize, deviceTwinCallback, context) != IOTHUB_CLIENT_OK)
+                    {
+                        LogError("Failure sending data");
+                        result = IOTHUB_CLIENT_ERROR;
+                    }
+                    else
+                    {
+                        result = IOTHUB_CLIENT_OK;
+                    }
+                    break;
+                }
+                case IOTHUB_CLIENT_LL_HANDLE_TYPE:
+                {
+                    if (IoTHubClient_LL_SendReportedState(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, buffer, bufferSize, deviceTwinCallback, context) != IOTHUB_CLIENT_OK)
+                    {
+                        LogError("Failure sending data");
+                        result = IOTHUB_CLIENT_ERROR;
+                    }
+                    else
+                    {
+                        result = IOTHUB_CLIENT_OK;
+                    }
+                    break;
+                }
+                default:
+                {
+                    LogError("INTERNAL ERROR: unexpected value for enum (%d)", (int)protoHandle->iothubClientHandleVariant.iothubClientHandleType);
+                    result = IOTHUB_CLIENT_ERROR;
+                    break;
+                }
+            }
+        }
+        free(buffer);
+    }
+    return result;
+}
+
 #define DECLARE_DEVICETWIN_MODEL(name, ...)    \
     DECLARE_MODEL(name, __VA_ARGS__)           \
     static name* C2(IoTHubDeviceTwin_Create, name)(IOTHUB_CLIENT_HANDLE iotHubClientHandle)                                                                                         \
@@ -377,6 +539,14 @@
     {                                                                                                                                                                               \
         IoTHubDeviceTwin_Destroy_Impl(model);                                                                                                                                       \
     }                                                                                                                                                                               \
+    static IOTHUB_CLIENT_RESULT C2(IoTHubDeviceTwin_LL_SendReportedState, name) (name* model, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK deviceTwinCallback, void* context)              \
+    {                                                                                                                                                                               \
+        return IoTHubDeviceTwin_SendReportedState_Impl(model, deviceTwinCallback, context);                                                                                         \
+    }                                                                                                                                                                               \
+    static IOTHUB_CLIENT_RESULT C2(IoTHubDeviceTwin_SendReportedState, name) (name* model, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK deviceTwinCallback, void* context)                 \
+    {                                                                                                                                                                               \
+        return IoTHubDeviceTwin_SendReportedState_Impl(model, deviceTwinCallback, context);                                                                                         \
+    }                                                                                                                                                                               \
 
 #endif /*SERIALIZER_DEVICE_TWIN_H*/