source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/serializer/inc/serializer_devicetwin.h@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-chdr;charset=UTF-8
File size: 24.8 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4
5#ifndef SERIALIZER_DEVICE_TWIN_H
6#define SERIALIZER_DEVICE_TWIN_H
7
8#include "serializer.h"
9
10#include "iothub_client.h"
11#include "iothub_client_ll.h"
12#include "parson.h"
13#include "azure_c_shared_utility/optimize_size.h"
14#include "azure_c_shared_utility/vector.h"
15#include "methodreturn.h"
16
17static void serializer_ingest(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
18{
19 /*by convention, userContextCallback is a pointer to a model instance created with CodeFirst_CreateDevice*/
20
21 /*Codes_SRS_SERIALIZERDEVICETWIN_02_001: [ serializer_ingest shall clone the payload into a null terminated string. ]*/
22 char* copyOfPayload = (char*)malloc(size + 1);
23 if (copyOfPayload == NULL)
24 {
25 /*Codes_SRS_SERIALIZERDEVICETWIN_02_008: [ If any of the above operations fail, then serializer_ingest shall return. ]*/
26 LogError("unable to malloc\n");
27 }
28 else
29 {
30 (void)memcpy(copyOfPayload, payLoad, size);
31 copyOfPayload[size] = '\0';
32
33 bool parseDesiredNode = (update_state == DEVICE_TWIN_UPDATE_COMPLETE);
34
35 if (CodeFirst_IngestDesiredProperties(userContextCallback, copyOfPayload, parseDesiredNode) != CODEFIRST_OK)
36 {
37 /*Codes_SRS_SERIALIZERDEVICETWIN_02_008: [ If any of the above operations fail, then serializer_ingest shall return. ]*/
38 LogError("failure ingesting desired properties\n");
39 }
40 else
41 {
42 /*all is fine*/
43 }
44
45 free(copyOfPayload);
46 }
47}
48
49/*both LL and convenience layer can be served by the same callback*/
50static int deviceMethodCallback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* userContextCallback)
51{
52 int result;
53 /*Codes_SRS_SERIALIZERDEVICETWIN_02_021: [ deviceMethodCallback shall transform payload and size into a null terminated string. ]*/
54 char* payloadZeroTerminated = (char*)malloc(size + 1);
55 if (payloadZeroTerminated == NULL)
56 {
57 LogError("failure in malloc");
58 /*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. ]*/
59 *response = NULL;
60 *resp_size = 0;
61 result = 500;
62 }
63 else
64 {
65 (void)memcpy(payloadZeroTerminated, payload, size);
66 payloadZeroTerminated[size] = '\0';
67
68 /*Codes_SRS_SERIALIZERDEVICETWIN_02_022: [ deviceMethodCallback shall call EXECUTE_METHOD passing the userContextCallback, method_name and the null terminated string build before. ]*/
69 METHODRETURN_HANDLE mr = EXECUTE_METHOD(userContextCallback, method_name, payloadZeroTerminated);
70
71 if (mr == NULL)
72 {
73 LogError("failure in EXECUTE_METHOD");
74 /*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. ]*/
75 *response = NULL;
76 *resp_size = 0;
77 result = 500;
78 }
79 else
80 {
81 /*Codes_SRS_SERIALIZERDEVICETWIN_02_023: [ deviceMethodCallback shall get the MethodReturn_Data and shall copy the response JSON value into a new byte array. ]*/
82 const METHODRETURN_DATA* data = MethodReturn_GetReturn(mr);
83
84 /*Codes_SRS_SERIALIZERDEVICETWIN_02_025: [ deviceMethodCallback returns the statusCode from the user. ]*/
85 result = data->statusCode;
86
87 if (data->jsonValue == NULL)
88 {
89 *resp_size = 0;
90 *response = NULL;
91 }
92 else
93 {
94 *resp_size = strlen(data->jsonValue);
95 *response = (unsigned char*)malloc(*resp_size);
96 if (*response == NULL)
97 {
98 LogError("failure in malloc");
99 /*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. ]*/
100 *response = NULL;
101 *resp_size = 0;
102 result = 500;
103 }
104 else
105 {
106 /*Codes_SRS_SERIALIZERDEVICETWIN_02_024: [ deviceMethodCallback shall set *response to this new byte array, *resp_size to the size of the array. ]*/
107 (void)memcpy(*response, data->jsonValue, *resp_size);
108 }
109 }
110 MethodReturn_Destroy(mr);
111 }
112 free(payloadZeroTerminated);
113 }
114 return result;
115}
116
117/*an enum that sets the type of the handle used to record IoTHubDeviceTwin_Create was called*/
118#define IOTHUB_CLIENT_HANDLE_TYPE_VALUES \
119 IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE, \
120 IOTHUB_CLIENT_LL_HANDLE_TYPE
121
122MU_DEFINE_ENUM_WITHOUT_INVALID(IOTHUB_CLIENT_HANDLE_TYPE, IOTHUB_CLIENT_HANDLE_TYPE_VALUES)
123
124typedef union IOTHUB_CLIENT_HANDLE_VALUE_TAG
125{
126 IOTHUB_CLIENT_HANDLE iothubClientHandle;
127 IOTHUB_CLIENT_LL_HANDLE iothubClientLLHandle;
128} IOTHUB_CLIENT_HANDLE_VALUE;
129
130typedef struct IOTHUB_CLIENT_HANDLE_VARIANT_TAG
131{
132 IOTHUB_CLIENT_HANDLE_TYPE iothubClientHandleType;
133 IOTHUB_CLIENT_HANDLE_VALUE iothubClientHandleValue;
134} IOTHUB_CLIENT_HANDLE_VARIANT;
135
136typedef struct SERIALIZER_DEVICETWIN_PROTOHANDLE_TAG /*it is called "PROTOHANDLE" because it is a primitive type of handle*/
137{
138 IOTHUB_CLIENT_HANDLE_VARIANT iothubClientHandleVariant;
139 void* deviceAssigned;
140} SERIALIZER_DEVICETWIN_PROTOHANDLE;
141
142static VECTOR_HANDLE g_allProtoHandles=NULL; /*contains SERIALIZER_DEVICETWIN_PROTOHANDLE*/
143
144static int lazilyAddProtohandle(const SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle)
145{
146 int result;
147 if ((g_allProtoHandles == NULL) && ((g_allProtoHandles = VECTOR_create(sizeof(SERIALIZER_DEVICETWIN_PROTOHANDLE))) == NULL))
148 {
149 LogError("failure in VECTOR_create");
150 result = MU_FAILURE;
151 }
152 else
153 {
154 if (VECTOR_push_back(g_allProtoHandles, protoHandle, 1) != 0)
155 {
156 LogError("failure in VECTOR_push_back");
157 result = MU_FAILURE;
158
159 /*leave it as it was*/
160
161 if (VECTOR_size(g_allProtoHandles) == 0)
162 {
163 VECTOR_destroy(g_allProtoHandles);
164 g_allProtoHandles = NULL;
165 }
166 }
167 else
168 {
169 result = 0;
170 }
171 }
172 return result;
173}
174
175static IOTHUB_CLIENT_RESULT Generic_IoTHubClient_SetCallbacks(const SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
176{
177 IOTHUB_CLIENT_RESULT result;
178 /*Codes_SRS_SERIALIZERDEVICETWIN_02_011: [ IoTHubDeviceTwinCreate_Impl shall set the device twin callback. ]*/
179 switch (protoHandle->iothubClientHandleVariant.iothubClientHandleType)
180 {
181 case IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE:
182 {
183 if ((result = IoTHubClient_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, deviceTwinCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
184 {
185 LogError("failure in IoTHubClient_SetDeviceTwinCallback");
186 }
187 else
188 {
189 /*Codes_SRS_SERIALIZERDEVICETWIN_02_027: [ IoTHubDeviceTwinCreate_Impl shall set the device method callback ]*/
190 if ((result = IoTHubClient_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, deviceMethodCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
191 {
192 (void)IoTHubClient_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, NULL, NULL);
193 LogError("failure in IoTHubClient_SetDeviceMethodCallback");
194 }
195 }
196 break;
197 }
198 case IOTHUB_CLIENT_LL_HANDLE_TYPE:
199 {
200 if ((result =IoTHubClient_LL_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, deviceTwinCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
201 {
202 LogError("failure in IoTHubClient_LL_SetDeviceTwinCallback");
203 }
204 else
205 {
206 /*Codes_SRS_SERIALIZERDEVICETWIN_02_027: [ IoTHubDeviceTwinCreate_Impl shall set the device method callback ]*/
207 if ((result = IoTHubClient_LL_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, deviceMethodCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
208 {
209 (void)IoTHubClient_LL_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, NULL, NULL);
210 LogError("failure in IoTHubClient_SetDeviceMethodCallback");
211 }
212 }
213 break;
214 }
215 default:
216 {
217 result = IOTHUB_CLIENT_ERROR;
218 LogError("INTERNAL ERROR");
219 }
220 }/*switch*/
221 return result;
222}
223
224static void* IoTHubDeviceTwinCreate_Impl(const char* name, size_t sizeOfName, SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle)
225{
226 void* result;
227 /*Codes_SRS_SERIALIZERDEVICETWIN_02_009: [ IoTHubDeviceTwinCreate_Impl shall locate the model and the metadata for name by calling Schema_GetSchemaForModel/Schema_GetMetadata/Schema_GetModelByName. ]*/
228 SCHEMA_HANDLE h = Schema_GetSchemaForModel(name);
229 if (h == NULL)
230 {
231 /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
232 LogError("failure in Schema_GetSchemaForModel.");
233 result = NULL;
234 }
235 else
236 {
237 void* metadata = Schema_GetMetadata(h);
238 SCHEMA_MODEL_TYPE_HANDLE modelType = Schema_GetModelByName(h, name);
239 if (modelType == NULL)
240 {
241 /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
242 LogError("failure in Schema_GetModelByName");
243 result = NULL;
244 }
245 else
246 {
247 /*Codes_SRS_SERIALIZERDEVICETWIN_02_010: [ IoTHubDeviceTwinCreate_Impl shall call CodeFirst_CreateDevice. ]*/
248 result = CodeFirst_CreateDevice(modelType, (REFLECTED_DATA_FROM_DATAPROVIDER *)metadata, sizeOfName, true);
249 if (result == NULL)
250 {
251 /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
252 LogError("failure in CodeFirst_CreateDevice");
253 /*return as is*/
254 }
255 else
256 {
257 protoHandle->deviceAssigned = result;
258 if (Generic_IoTHubClient_SetCallbacks(protoHandle, serializer_ingest, result) != IOTHUB_CLIENT_OK)
259 {
260 /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
261 LogError("failure in Generic_IoTHubClient_SetCallbacks");
262 CodeFirst_DestroyDevice(result);
263 result = NULL;
264 }
265 else
266 {
267 /*lazily add the protohandle to the array of tracking handles*/
268
269 /*Codes_SRS_SERIALIZERDEVICETWIN_02_012: [ IoTHubDeviceTwinCreate_Impl shall record the pair of (device, IoTHubClient(_LL)). ]*/
270 if (lazilyAddProtohandle(protoHandle) != 0)
271 {
272 /*Codes_SRS_SERIALIZERDEVICETWIN_02_014: [ Otherwise, IoTHubDeviceTwinCreate_Impl shall fail and return NULL. ]*/
273 LogError("unable to add the protohandle to the collection of handles");
274 /*unsubscribe*/
275 if (Generic_IoTHubClient_SetCallbacks(protoHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
276 {
277 /*just log the error*/
278 LogError("failure in Generic_IoTHubClient_SetCallbacks");
279 }
280 CodeFirst_DestroyDevice(result);
281 result = NULL;
282 }
283 else
284 {
285 /*Codes_SRS_SERIALIZERDEVICETWIN_02_013: [ If all operations complete successfully then IoTHubDeviceTwinCreate_Impl shall succeeds and return a non-NULL value. ]*/
286 /*return as is*/
287 }
288 }
289 }
290 }
291 }
292 return result;
293}
294
295static bool protoHandleHasDeviceStartAddress(const void* element, const void* value)
296{
297 const SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle = (const SERIALIZER_DEVICETWIN_PROTOHANDLE*)element;
298 return protoHandle->deviceAssigned == value;
299}
300
301static void IoTHubDeviceTwin_Destroy_Impl(void* model)
302{
303 /*Codes_SRS_SERIALIZERDEVICETWIN_02_020: [ If model is NULL then IoTHubDeviceTwin_Destroy_Impl shall return. ]*/
304 if (model == NULL)
305 {
306 LogError("invalid argument void* model=%p", model);
307 }
308 else
309 {
310 /*Codes_SRS_SERIALIZERDEVICETWIN_02_015: [ IoTHubDeviceTwin_Destroy_Impl shall locate the saved handle belonging to model. ]*/
311 SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle = (SERIALIZER_DEVICETWIN_PROTOHANDLE*)VECTOR_find_if(g_allProtoHandles, protoHandleHasDeviceStartAddress, model);
312 if (protoHandle == NULL)
313 {
314 LogError("failure in VECTOR_find_if [not found]");
315 }
316 else
317 {
318 /*Codes_SRS_SERIALIZERDEVICETWIN_02_016: [ IoTHubDeviceTwin_Destroy_Impl shall set the devicetwin callback to NULL. ]*/
319 switch (protoHandle->iothubClientHandleVariant.iothubClientHandleType)
320 {
321 case IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE:
322 {
323 if (IoTHubClient_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
324 {
325 LogError("failure in IoTHubClient_SetDeviceTwinCallback");
326 }
327 /*Codes_SRS_SERIALIZERDEVICETWIN_02_028: [ IoTHubDeviceTwin_Destroy_Impl shall set the method callback to NULL. ]*/
328 if (IoTHubClient_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
329 {
330 LogError("failure in IoTHubClient_SetDeviceMethodCallback");
331 }
332 break;
333 }
334 case IOTHUB_CLIENT_LL_HANDLE_TYPE:
335 {
336 if (IoTHubClient_LL_SetDeviceTwinCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
337 {
338 LogError("failure in IoTHubClient_LL_SetDeviceTwinCallback");
339 }
340 /*Codes_SRS_SERIALIZERDEVICETWIN_02_028: [ IoTHubDeviceTwin_Destroy_Impl shall set the method callback to NULL. ]*/
341 if (IoTHubClient_LL_SetDeviceMethodCallback(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
342 {
343 LogError("failure in IoTHubClient_LL_SetDeviceMethodCallback");
344 }
345 break;
346 }
347 default:
348 {
349 LogError("INTERNAL ERROR");
350 }
351 }/*switch*/
352
353 /*Codes_SRS_SERIALIZERDEVICETWIN_02_017: [ IoTHubDeviceTwin_Destroy_Impl shall call CodeFirst_DestroyDevice. ]*/
354 CodeFirst_DestroyDevice(protoHandle->deviceAssigned);
355
356 /*Codes_SRS_SERIALIZERDEVICETWIN_02_018: [ IoTHubDeviceTwin_Destroy_Impl shall remove the IoTHubClient_Handle and the device handle from the recorded set. ]*/
357 VECTOR_erase(g_allProtoHandles, protoHandle, 1);
358 }
359
360 /*Codes_SRS_SERIALIZERDEVICETWIN_02_019: [ If the recorded set of IoTHubClient handles is zero size, then the set shall be destroyed. ]*/
361 if (VECTOR_size(g_allProtoHandles) == 0) /*lazy init means more work @ destroy time*/
362 {
363 VECTOR_destroy(g_allProtoHandles);
364 g_allProtoHandles = NULL;
365 }
366 }
367}
368
369/*the below function sends the reported state of a model previously created by IoTHubDeviceTwin_Create*/
370/*this function serves both the _LL and the convenience layer because of protohandles*/
371static IOTHUB_CLIENT_RESULT IoTHubDeviceTwin_SendReportedState_Impl(void* model, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK deviceTwinCallback, void* context)
372{
373 unsigned char*buffer;
374 size_t bufferSize;
375
376 IOTHUB_CLIENT_RESULT result;
377
378 if (SERIALIZE_REPORTED_PROPERTIES_FROM_POINTERS(&buffer, &bufferSize, model) != CODEFIRST_OK)
379 {
380 LogError("Failed serializing reported state");
381 result = IOTHUB_CLIENT_ERROR;
382 }
383 else
384 {
385 SERIALIZER_DEVICETWIN_PROTOHANDLE* protoHandle = (SERIALIZER_DEVICETWIN_PROTOHANDLE*)VECTOR_find_if(g_allProtoHandles, protoHandleHasDeviceStartAddress, model);
386 if (protoHandle == NULL)
387 {
388 LogError("failure in VECTOR_find_if [not found]");
389 result = IOTHUB_CLIENT_ERROR;
390 }
391 else
392 {
393 switch (protoHandle->iothubClientHandleVariant.iothubClientHandleType)
394 {
395 case IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE:
396 {
397 if (IoTHubClient_SendReportedState(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle, buffer, bufferSize, deviceTwinCallback, context) != IOTHUB_CLIENT_OK)
398 {
399 LogError("Failure sending data");
400 result = IOTHUB_CLIENT_ERROR;
401 }
402 else
403 {
404 result = IOTHUB_CLIENT_OK;
405 }
406 break;
407 }
408 case IOTHUB_CLIENT_LL_HANDLE_TYPE:
409 {
410 if (IoTHubClient_LL_SendReportedState(protoHandle->iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle, buffer, bufferSize, deviceTwinCallback, context) != IOTHUB_CLIENT_OK)
411 {
412 LogError("Failure sending data");
413 result = IOTHUB_CLIENT_ERROR;
414 }
415 else
416 {
417 result = IOTHUB_CLIENT_OK;
418 }
419 break;
420 }
421 default:
422 {
423 LogError("INTERNAL ERROR: unexpected value for enum (%d)", (int)protoHandle->iothubClientHandleVariant.iothubClientHandleType);
424 result = IOTHUB_CLIENT_ERROR;
425 break;
426 }
427 }
428 }
429 free(buffer);
430 }
431 return result;
432}
433
434#define DECLARE_DEVICETWIN_MODEL(name, ...) \
435 DECLARE_MODEL(name, __VA_ARGS__) \
436 static name* MU_C2(IoTHubDeviceTwin_Create, name)(IOTHUB_CLIENT_HANDLE iotHubClientHandle) \
437 { \
438 SERIALIZER_DEVICETWIN_PROTOHANDLE protoHandle; \
439 protoHandle.iothubClientHandleVariant.iothubClientHandleType = IOTHUB_CLIENT_CONVENIENCE_HANDLE_TYPE; \
440 protoHandle.iothubClientHandleVariant.iothubClientHandleValue.iothubClientHandle = iotHubClientHandle; \
441 return (name*)IoTHubDeviceTwinCreate_Impl(#name, sizeof(name), &protoHandle); \
442 } \
443 \
444 static void MU_C2(IoTHubDeviceTwin_Destroy, name) (name* model) \
445 { \
446 IoTHubDeviceTwin_Destroy_Impl(model); \
447 } \
448 \
449 static name* MU_C2(IoTHubDeviceTwin_LL_Create, name)(IOTHUB_CLIENT_LL_HANDLE iotHubClientLLHandle) \
450 { \
451 SERIALIZER_DEVICETWIN_PROTOHANDLE protoHandle; \
452 protoHandle.iothubClientHandleVariant.iothubClientHandleType = IOTHUB_CLIENT_LL_HANDLE_TYPE; \
453 protoHandle.iothubClientHandleVariant.iothubClientHandleValue.iothubClientLLHandle = iotHubClientLLHandle; \
454 return (name*)IoTHubDeviceTwinCreate_Impl(#name, sizeof(name), &protoHandle); \
455 } \
456 \
457 static void MU_C2(IoTHubDeviceTwin_LL_Destroy, name) (name* model) \
458 { \
459 IoTHubDeviceTwin_Destroy_Impl(model); \
460 } \
461 static IOTHUB_CLIENT_RESULT MU_C2(IoTHubDeviceTwin_LL_SendReportedState, name) (name* model, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK deviceTwinCallback, void* context) \
462 { \
463 return IoTHubDeviceTwin_SendReportedState_Impl(model, deviceTwinCallback, context); \
464 } \
465 static IOTHUB_CLIENT_RESULT MU_C2(IoTHubDeviceTwin_SendReportedState, name) (name* model, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK deviceTwinCallback, void* context) \
466 { \
467 return IoTHubDeviceTwin_SendReportedState_Impl(model, deviceTwinCallback, context); \
468 } \
469
470#endif /*SERIALIZER_DEVICE_TWIN_H*/
471
472
Note: See TracBrowser for help on using the repository browser.