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:
21:6d3dea1abd9c
--- a/serializer.h	Wed Nov 16 21:38:26 2016 -0800
+++ b/serializer.h	Wed Dec 14 16:00:39 2016 -0800
@@ -56,12 +56,14 @@
 #include "iotdevice.h"
 #include "azure_c_shared_utility/crt_abstractions.h"
 #include "azure_c_shared_utility/xlogging.h"
+#include "methodreturn.h"
 #include "schemalib.h"
 #include "codefirst.h"
 #include "agenttypesystem.h"
 #include "schema.h"
 
 
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -162,6 +164,7 @@
  /* Codes_SRS_SERIALIZER_99_133:[a model type introduced previously by DECLARE_MODEL] */
 
 #define CREATE_DESIRED_PROPERTY_CALLBACK_MODEL_ACTION(...)
+#define CREATE_DESIRED_PROPERTY_CALLBACK_MODEL_METHOD(...)
 #define CREATE_DESIRED_PROPERTY_CALLBACK_MODEL_DESIRED_PROPERTY(type, name, ...) IF(COUNT_ARG(__VA_ARGS__), void __VA_ARGS__ (void*);, )
 #define CREATE_DESIRED_PROPERTY_CALLBACK_MODEL_PROPERTY(...)
 #define CREATE_DESIRED_PROPERTY_CALLBACK_MODEL_REPORTED_PROPERTY(...) 
@@ -241,6 +244,19 @@
 
 
 /**
+* @def   WITH_METHOD(name, ...)
+* The ::WITH_METHOD macro allows declaring a model method.
+*
+* @param   name                    Specifies the method name.
+* @param   argXtype, argXName...   Defines the type and name for the X<sup>th</sup>
+*                                  argument of the method. The type can be any of
+*                                  the primitive types or a struct type.
+*/
+/*Codes_SRS_SERIALIZER_H_02_029: [ WITH_METHOD shall declare a function with the signature 'METHODRETURN_HANDLE name(param1Type param1Name, ...)', which the developer can define to receive corresponding commands from the IoT service. ]*/
+#define WITH_METHOD(name, ...)  MODEL_METHOD(name, __VA_ARGS__)
+
+
+/**
  * @def   GET_MODEL_HANDLE(schemaNamespace, modelName)
  * The ::GET_MODEL_HANDLE macro returns a model handle that can be used in
  * subsequent operations like generating the CSDL schema for the model,
@@ -296,6 +312,10 @@
 
 #define SERIALIZE_REPORTED_PROPERTIES(destination, destinationSize,...) CodeFirst_SendAsyncReported(destination, destinationSize, COUNT_ARG(__VA_ARGS__) FOR_EACH_1(ADDRESS_MACRO, __VA_ARGS__))
 
+
+#define IDENTITY_MACRO(x) ,x
+#define SERIALIZE_REPORTED_PROPERTIES_FROM_POINTERS(destination, destinationSize, ...) CodeFirst_SendAsyncReported(destination, destinationSize, COUNT_ARG(__VA_ARGS__) FOR_EACH_1(IDENTITY_MACRO, __VA_ARGS__))
+
 /**
  * @def   EXECUTE_COMMAND(device, command)
  * Any action that is declared in a model must also have an implementation as
@@ -309,6 +329,17 @@
 #define EXECUTE_COMMAND(device, command) (CodeFirst_ExecuteCommand(device, command))
 
 /**
+* @def   EXECUTE_METHOD(device, methodName, methodPayload)
+* Any method that is declared in a model must also have an implementation as
+* a C function.
+*
+* @param   device      Pointer to device data.
+* @param   methodName       The method name.
+* @param   methodPayload    The method payload.
+*/
+#define EXECUTE_METHOD(device, methodName, methodPayload) CodeFirst_ExecuteMethod(device, methodName, methodPayload)
+
+/**
 * @def   INGEST_DESIRED_PROPERTIES(device, desiredProperties)
 *
 * @param   device                return of CodeFirst_CreateDevice.
@@ -362,6 +393,8 @@
 
 #define TO_AGENT_DT_EXPAND_MODEL_ACTION(...) 
 
+#define TO_AGENT_DT_EXPAND_MODEL_METHOD(...) 
+
 #define TO_AGENT_DT_EXPAND_ELEMENT_ARGS(N, ...) TO_AGENT_DT_EXPAND_##__VA_ARGS__
 
 #define EXPAND_MODEL_ARGS(...) \
@@ -408,19 +441,19 @@
 #define REFLECTED_LIST_HEAD(name) \
     static const REFLECTED_DATA_FROM_DATAPROVIDER ALL_REFLECTED(name) = { &C2(REFLECTED_, C1(DEC(__COUNTER__))) };
 #define REFLECTED_STRUCT(name) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_STRUCT_TYPE,               &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {TOSTRING(name)}, {0}, {0}, {0}, {0}} };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_STRUCT_TYPE,               &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {TOSTRING(name)}, {0}, {0}, {0}, {0}} };
 #define REFLECTED_FIELD(XstructName, XfieldType, XfieldName) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_FIELD_TYPE,                &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {TOSTRING(XfieldName), TOSTRING(XfieldType), TOSTRING(XstructName)}, {0}, {0}, {0} } };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_FIELD_TYPE,                &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {TOSTRING(XfieldName), TOSTRING(XfieldType), TOSTRING(XstructName)}, {0}, {0}, {0} } };
 #define REFLECTED_MODEL(name) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_MODEL_TYPE,                &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {0}, {0}, {TOSTRING(name)} } };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_MODEL_TYPE,                &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {0}, {0}, {0}, {TOSTRING(name)} } };
 #define REFLECTED_PROPERTY(type, name, modelName) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_PROPERTY_TYPE,             &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {TOSTRING(name), TOSTRING(type), Create_AGENT_DATA_TYPE_From_Ptr_##modelName##name, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0} } };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_PROPERTY_TYPE,             &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {0}, {TOSTRING(name), TOSTRING(type), Create_AGENT_DATA_TYPE_From_Ptr_##modelName##name, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0} } };
 #define REFLECTED_REPORTED_PROPERTY(type, name, modelName) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_REPORTED_PROPERTY_TYPE,    &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {TOSTRING(name), TOSTRING(type), Create_AGENT_DATA_TYPE_From_Ptr_##modelName##name, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0}, {0}, {0}, {0} } };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_REPORTED_PROPERTY_TYPE,    &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {TOSTRING(name), TOSTRING(type), Create_AGENT_DATA_TYPE_From_Ptr_##modelName##name, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0}, {0}, {0}, {0} } };
 
 
 #define REFLECTED_DESIRED_PROPERTY_WITH_ON_DESIRED_PROPERTY_CHANGE(type, name, modelName, COUNTER, onDesiredPropertyChange) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(COUNTER))) =      { REFLECTION_DESIRED_PROPERTY_TYPE,     &C2(REFLECTED_, C1(DEC(COUNTER))),         { {onDesiredPropertyChange, DesiredPropertyInitialize_##modelName##name, DesiredPropertyDeinitialize_##modelName##name, TOSTRING(name), TOSTRING(type), (int(*)(const AGENT_DATA_TYPE*, void*))FromAGENT_DATA_TYPE_##type, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0}, {0}, {0}, {0}, {0}} };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(COUNTER))) =      { REFLECTION_DESIRED_PROPERTY_TYPE,     &C2(REFLECTED_, C1(DEC(COUNTER))),         { {0}, {onDesiredPropertyChange, DesiredPropertyInitialize_##modelName##name, DesiredPropertyDeinitialize_##modelName##name, TOSTRING(name), TOSTRING(type), (int(*)(const AGENT_DATA_TYPE*, void*))FromAGENT_DATA_TYPE_##type, offsetof(modelName, name), sizeof(type), TOSTRING(modelName)}, {0}, {0}, {0}, {0}, {0}, {0}} };
 
 #define REFLECTED_DESIRED_PROPERTY(type, name, modelName, ...)                                                              \
     IF(COUNT_ARG(__VA_ARGS__),                                                                                              \
@@ -429,9 +462,14 @@
     )                                                                                                                       \
 
 #define REFLECTED_ACTION(name, argc, argv, fn, modelName) \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_ACTION_TYPE,               &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {0}, {TOSTRING(name), (0 ? (uintptr_t)("", "") : argc), argv, fn, TOSTRING(modelName)}, {0}} };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_ACTION_TYPE,               &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {0}, {0}, {0}, {0}, {0}, {0}, {TOSTRING(name), (0 ? (uintptr_t)("", "") : argc), argv, fn, TOSTRING(modelName)}, {0}} };
+
+#define REFLECTED_METHOD(name, argc, argv, fn, modelName) \
+    static const REFLECTED_SOMETHING C2(REFLECTED_, C1(INC(__COUNTER__))) = { REFLECTION_METHOD_TYPE,               &C2(REFLECTED_, C1(DEC(DEC(__COUNTER__)))), { {TOSTRING(name), (0 ? (uintptr_t)("", "") : argc), argv, fn, TOSTRING(modelName)}, {0}, {0}, {0}, {0}, {0}, {0}, {0}} };
+
+
 #define REFLECTED_END_OF_LIST \
-    static const REFLECTED_SOMETHING C2(REFLECTED_, __COUNTER__) = {          REFLECTION_NOTHING,                   NULL,                                       { {0}, {0}, {0}, {0}, {0}, {0}, {0}} };
+    static const REFLECTED_SOMETHING C2(REFLECTED_, __COUNTER__) = {          REFLECTION_NOTHING,                   NULL,                                       { {0},{0}, {0}, {0}, {0}, {0}, {0}, {0}} };
 
 #define EXPAND_MODEL_PROPERTY(type, name) EXPAND_ARGS(MODEL_PROPERTY, type, name)
 
@@ -441,6 +479,8 @@
 
 #define EXPAND_MODEL_ACTION(...) EXPAND_ARGS(MODEL_ACTION, __VA_ARGS__)
 
+#define EXPAND_MODEL_METHOD(...) EXPAND_ARGS(MODEL_METHOD, __VA_ARGS__)
+
 #define BUILD_MODEL_STRUCT(elem) INSERT_FIELD_FOR_##elem
 
 #define CREATE_MODEL_ENTITY(modelName, callType, ...) EXPAND_ARGS(CREATE_##callType(modelName, __VA_ARGS__))
@@ -478,9 +518,14 @@
 #define CREATE_GLOBAL_DEINITIALIZE_MODEL_DESIRED_PROPERTY(modelName, type, name, ...) /*do nothing*/
 
 #define INSERT_FIELD_FOR_MODEL_ACTION(name, ...) /* action isn't a part of the model struct */
+#define INSERT_FIELD_FOR_MODEL_METHOD(name, ...) /* method isn't a part of the model struct */
+
 #define CREATE_GLOBAL_INITIALIZE_MODEL_ACTION(...) /*do nothing*/
 #define CREATE_GLOBAL_DEINITIALIZE_MODEL_ACTION(...) /*do nothing*/
 
+#define CREATE_GLOBAL_INITIALIZE_MODEL_METHOD(...) /*do nothing*/
+#define CREATE_GLOBAL_DEINITIALIZE_MODEL_METHOD(...) /*do nothing*/
+
 #define CREATE_MODEL_PROPERTY(modelName, type, name) \
     IMPL_PROPERTY(type, name, modelName)
 
@@ -547,7 +592,7 @@
             DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(actionName, 6); \
             IF(DIV2(COUNT_ARG(__VA_ARGS__)), , (void)values;) \
             INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
-            FOR_EACH_2(START_BUILD_LOCAL_PARAMETER, __VA_ARGS__) \
+            FOR_EACH_2_KEEP_1(START_BUILD_LOCAL_PARAMETER, EXECUTE_COMMAND_ERROR, __VA_ARGS__) \
             INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
             result = actionName((modelName*)device FOR_EACH_2(PUSH_LOCAL_PARAMETER, __VA_ARGS__)); \
             FOR_EACH_2_REVERSE(END_BUILD_LOCAL_PARAMETER, __VA_ARGS__) \
@@ -555,6 +600,47 @@
         return result; \
     }
 
+#define CREATE_MODEL_METHOD(modelName, methodName, ...) \
+    DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(modelName##methodName, 1); \
+    METHODRETURN_HANDLE methodName (modelName* device FOR_EACH_2(DEFINE_FUNCTION_PARAMETER, __VA_ARGS__)); \
+    static METHODRETURN_HANDLE C2(methodName, WRAPPER)(void* device, size_t ParameterCount, const AGENT_DATA_TYPE* values); \
+    /*for macro purposes, this array always has at least 1 element*/ \
+    /*Codes_SRS_SERIALIZER_H_02_030: [ It is valid for a method function not to have any parameters. ]*/ \
+    DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(methodName, 1); \
+    static const WRAPPER_ARGUMENT C2(methodName, WRAPPERARGUMENTS)[DIV2(INC(INC(COUNT_ARG(__VA_ARGS__))))] = { FOR_EACH_2_COUNTED(MAKE_WRAPPER_ARGUMENT, __VA_ARGS__) IFCOMMA(INC(INC(COUNT_ARG(__VA_ARGS__)))) {0} }; \
+    REFLECTED_METHOD(methodName, DIV2(COUNT_ARG(__VA_ARGS__)), C2(methodName, WRAPPERARGUMENTS), C2(methodName, WRAPPER), modelName) \
+    /*Codes_SRS_SERIALIZER_H_02_034: [ WITH_METHOD shall result in the declaration of a conversion function with the prototype METHODRETURN_HANDLE nameWRAPPER(size_t ParameterCount, const AGENT_DATA_TYPE* values)' ]*/ \
+    /*Codes_SRS_SERIALIZER_H_02_031: [ The function shall convert the input arguments to the types declared in the method parameter list and then call the user-defined method function. ]*/ \
+    static METHODRETURN_HANDLE C2(methodName, WRAPPER)(void* device, size_t ParameterCount, const AGENT_DATA_TYPE* values) \
+    { \
+        METHODRETURN_HANDLE result; \
+        DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(methodName, 2); \
+        /*Codes_SRS_SERIALIZER_H_02_032: [ If the number of arguments passed to the conversion function does not match the expected count, the function shall return DATAPROVIDER_INVALID_ARG. ]*/ \
+        if(ParameterCount != DIV2(COUNT_ARG(__VA_ARGS__))) \
+        { \
+            LogError("expected parameter count (%zu) does not match the actual parameter count (%zu)", ParameterCount, COUNT_ARG(__VA_ARGS__)); \
+            result = NULL; \
+        } \
+        else \
+        { \
+            /*the below line takes care of initialized but not referenced parameter warning*/ \
+            DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(methodName, 3); \
+            IF(DIV2(COUNT_ARG(__VA_ARGS__)), size_t iParameter = 0;, ) \
+            DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(methodName, 4); \
+            /*the below line takes care of an unused parameter when values is really never questioned*/ \
+            DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(methodName, 5); \
+            FOR_EACH_2(DEFINE_LOCAL_PARAMETER, __VA_ARGS__) \
+            DEFINITION_THAT_CAN_SUSTAIN_A_COMMA_STEAL(methodName, 6); \
+            IF(DIV2(COUNT_ARG(__VA_ARGS__)), , (void)values;) \
+            INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
+            FOR_EACH_2_KEEP_1(START_BUILD_LOCAL_PARAMETER, NULL,__VA_ARGS__) \
+            INSTRUCTION_THAT_CAN_SUSTAIN_A_COMMA_STEAL; \
+            result = methodName((modelName*)device FOR_EACH_2(PUSH_LOCAL_PARAMETER, __VA_ARGS__)); \
+            FOR_EACH_2_REVERSE(END_BUILD_LOCAL_PARAMETER, __VA_ARGS__) \
+        } \
+        return result; \
+    }
+
 #define CREATE_AGENT_DATA_TYPE(type, name) \
     result = (( result==AGENT_DATA_TYPES_OK) && (ToAGENT_DATA_TYPE_##type( &(members[iMember]), value.name) == AGENT_DATA_TYPES_OK))?AGENT_DATA_TYPES_OK:AGENT_DATA_TYPES_ERROR; \
     iMember+= ((result==AGENT_DATA_TYPES_OK)?1:0);
@@ -696,11 +782,11 @@
 
 #define DEFINE_LOCAL_PARAMETER(type, name) type C2(name,_local); GlobalInitialize_##type(& C2(name, _local));
 
-#define START_BUILD_LOCAL_PARAMETER(type, name) \
+#define START_BUILD_LOCAL_PARAMETER(errorWhenItFails, type, name) \
     if (C2(FromAGENT_DATA_TYPE_, type)(&values[iParameter], &C2(name, _local)) != AGENT_DATA_TYPES_OK) \
     { \
         /*Codes_SRS_SERIALIZER_99_046:[ If the types of the parameters do not match the declared types, DATAPROVIDER_INVALID_ARG shall be returned.]*/ \
-        result = EXECUTE_COMMAND_ERROR; \
+        result = errorWhenItFails; \
     }\
     else \
     { \