source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/serializer/src/codefirst.c@ 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-csrc;charset=UTF-8
File size: 71.3 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#include <stdlib.h>
5#include <stdarg.h>
6#include "azure_c_shared_utility/gballoc.h"
7
8#include "codefirst.h"
9#include "azure_macro_utils/macro_utils.h"
10#include "azure_c_shared_utility/crt_abstractions.h"
11#include "azure_c_shared_utility/xlogging.h"
12#include <stddef.h>
13#include "azure_c_shared_utility/crt_abstractions.h"
14#include "iotdevice.h"
15
16MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(CODEFIRST_RESULT, CODEFIRST_RESULT_VALUES)
17MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(EXECUTE_COMMAND_RESULT, EXECUTE_COMMAND_RESULT_VALUES)
18
19#define LOG_CODEFIRST_ERROR \
20 LogError("(result = %s)", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result))
21
22typedef struct DEVICE_HEADER_DATA_TAG
23{
24 DEVICE_HANDLE DeviceHandle;
25 const REFLECTED_DATA_FROM_DATAPROVIDER* ReflectedData;
26 SCHEMA_MODEL_TYPE_HANDLE ModelHandle;
27 size_t DataSize;
28 unsigned char* data;
29} DEVICE_HEADER_DATA;
30
31#define COUNT_OF(A) (sizeof(A) / sizeof((A)[0]))
32
33/*design considerations for lazy init of CodeFirst:
34 There are 2 main states: either CodeFirst is in an initialized state, or it is not initialized.
35 The initialized state means there's a g_OverrideSchemaNamespace set (even when it is set to NULL).
36 The uninitialized state means g_OverrideSchemaNamespace is not set.
37
38 To switch to Init state, either call CodeFirst_Init (that sets g_OverrideSchemaNamespace to something)
39 or call directly an API (that will set automatically g_OverrideSchemaNamespace to NULL).
40
41 To switch to NOT INIT state, depending on the method used to initialize:
42 - if CodeFirst_Init was called, then only by a call to CodeFirst_Deinit the switch will take place
43 (note how in this case g_OverrideSchemaNamespace survives destruction of all devices).
44 - if the init has been done "lazily" by an API call then the module returns to uninitialized state
45 when the number of devices reaches zero.
46
47 +-----------------------------+
48 Start +---------------->| |
49 | NOT INIT |
50 +---------------->| |
51 | +------------+----------------+
52 | |
53 | |
54 | | _Init | APIs
55 | |
56 | v
57 | +---------------------------------------------------+
58 | | Init State |
59 | | +-----------------+ +-----------------+ |
60 | | | | | | |
61 | | | init by _Init | | init by API | |
62 | | +------+----------+ +---------+-------+ |
63 | | | | |
64 | | |_DeInit | nDevices==0 |
65 | | | | |
66 | +--------v----------------+-----------v-------------+
67 | |
68 +-------------------------------+
69
70*/
71
72
73#define CODEFIRST_STATE_VALUES \
74 CODEFIRST_STATE_NOT_INIT, \
75 CODEFIRST_STATE_INIT_BY_INIT, \
76 CODEFIRST_STATE_INIT_BY_API
77
78MU_DEFINE_ENUM(CODEFIRST_STATE, CODEFIRST_STATE_VALUES)
79
80static CODEFIRST_STATE g_state = CODEFIRST_STATE_NOT_INIT;
81static const char* g_OverrideSchemaNamespace;
82static size_t g_DeviceCount = 0;
83static DEVICE_HEADER_DATA** g_Devices = NULL;
84
85static void deinitializeDesiredProperties(SCHEMA_MODEL_TYPE_HANDLE model, void* destination)
86{
87 size_t nDesiredProperties;
88 if (Schema_GetModelDesiredPropertyCount(model, &nDesiredProperties) != SCHEMA_OK)
89 {
90 LogError("unexpected error in Schema_GetModelDesiredPropertyCount");
91 }
92 else
93 {
94 size_t nProcessedDesiredProperties = 0;
95 for (size_t i = 0;i < nDesiredProperties;i++)
96 {
97 SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle = Schema_GetModelDesiredPropertyByIndex(model, i);
98 if (desiredPropertyHandle == NULL)
99 {
100 LogError("unexpected error in Schema_GetModelDesiredPropertyByIndex");
101 i = nDesiredProperties;
102 }
103 else
104 {
105 pfDesiredPropertyDeinitialize desiredPropertyDeinitialize = Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize(desiredPropertyHandle);
106 if (desiredPropertyDeinitialize == NULL)
107 {
108 LogError("unexpected error in Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize");
109 i = nDesiredProperties;
110 }
111 else
112 {
113 size_t offset = Schema_GetModelDesiredProperty_offset(desiredPropertyHandle);
114 desiredPropertyDeinitialize((char*)destination + offset);
115 nProcessedDesiredProperties++;
116 }
117 }
118 }
119
120 if (nDesiredProperties == nProcessedDesiredProperties)
121 {
122 /*recursively go in the model and initialize the other fields*/
123 size_t nModelInModel;
124 if (Schema_GetModelModelCount(model, &nModelInModel) != SCHEMA_OK)
125 {
126 LogError("unexpected error in Schema_GetModelModelCount");
127 }
128 else
129 {
130 size_t nProcessedModelInModel = 0;
131 for (size_t i = 0; i < nModelInModel;i++)
132 {
133 SCHEMA_MODEL_TYPE_HANDLE modelInModel = Schema_GetModelModelyByIndex(model, i);
134 if (modelInModel == NULL)
135 {
136 LogError("unexpected failure in Schema_GetModelModelyByIndex");
137 i = nModelInModel;
138 }
139 else
140 {
141 size_t offset = Schema_GetModelModelByIndex_Offset(model, i);
142 deinitializeDesiredProperties(modelInModel, (char*)destination + offset);
143 nProcessedModelInModel++;
144 }
145 }
146
147 if (nProcessedModelInModel == nModelInModel)
148 {
149 /*all is fine... */
150 }
151 }
152 }
153 }
154}
155
156static void DestroyDevice(DEVICE_HEADER_DATA* deviceHeader)
157{
158 /* Codes_SRS_CODEFIRST_99_085:[CodeFirst_DestroyDevice shall free all resources associated with a device.] */
159 /* Codes_SRS_CODEFIRST_99_087:[In order to release the device handle, CodeFirst_DestroyDevice shall call Device_Destroy.] */
160
161 Device_Destroy(deviceHeader->DeviceHandle);
162 free(deviceHeader->data);
163 free(deviceHeader);
164}
165
166static CODEFIRST_RESULT buildStructTypes(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData)
167{
168 CODEFIRST_RESULT result = CODEFIRST_OK;
169
170 const REFLECTED_SOMETHING* something;
171 for (something = reflectedData->reflectedData; something != NULL; something = something->next)
172 {
173 if (something->type == REFLECTION_STRUCT_TYPE)
174 {
175 SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle;
176 structTypeHandle = Schema_CreateStructType(schemaHandle, something->what.structure.name);
177
178 if (structTypeHandle == NULL)
179 {
180 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
181 result = CODEFIRST_SCHEMA_ERROR;
182 LogError("create struct failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
183 break;
184 }
185 else
186 {
187 const REFLECTED_SOMETHING* maybeField;
188 /*look for the field... */
189 for (maybeField = reflectedData->reflectedData; maybeField != NULL; maybeField = maybeField->next)
190 {
191 if (maybeField->type == REFLECTION_FIELD_TYPE)
192 {
193 if (strcmp(maybeField->what.field.structName, something->what.structure.name) == 0)
194 {
195 if (Schema_AddStructTypeProperty(structTypeHandle, maybeField->what.field.fieldName, maybeField->what.field.fieldType) != SCHEMA_OK)
196 {
197 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
198 result = CODEFIRST_SCHEMA_ERROR;
199 LogError("add struct property failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
200 break;
201 }
202 }
203 }
204 }
205 }
206 }
207 }
208
209 return result;
210}
211
212static CODEFIRST_RESULT buildModel(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData, const REFLECTED_SOMETHING* modelReflectedData)
213{
214 CODEFIRST_RESULT result = CODEFIRST_OK;
215 const REFLECTED_SOMETHING* something;
216 SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle;
217
218 modelTypeHandle = Schema_GetModelByName(schemaHandle, modelReflectedData->what.model.name);
219 if (modelTypeHandle == NULL)
220 {
221 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
222 result = CODEFIRST_SCHEMA_ERROR;
223 LogError("cannot get model %s %s", modelReflectedData->what.model.name, MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
224 goto out;
225 }
226
227 for (something = reflectedData->reflectedData; something != NULL; something = something->next)
228 {
229 /* looking for all elements that belong to a model: properties and actions */
230 if ((something->type == REFLECTION_PROPERTY_TYPE) &&
231 (strcmp(something->what.property.modelName, modelReflectedData->what.model.name) == 0))
232 {
233 SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.property.type);
234
235 /* if this is a model type use the appropriate APIs for it */
236 if (childModelHande != NULL)
237 {
238 if (Schema_AddModelModel(modelTypeHandle, something->what.property.name, childModelHande, something->what.property.offset, NULL) != SCHEMA_OK)
239 {
240 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
241 result = CODEFIRST_SCHEMA_ERROR;
242 LogError("add model failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
243 goto out;
244 }
245 }
246 else
247 {
248 if (Schema_AddModelProperty(modelTypeHandle, something->what.property.name, something->what.property.type) != SCHEMA_OK)
249 {
250 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
251 result = CODEFIRST_SCHEMA_ERROR;
252 LogError("add property failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
253 goto out;
254 }
255 }
256 }
257
258 if ((something->type == REFLECTION_REPORTED_PROPERTY_TYPE) &&
259 (strcmp(something->what.reportedProperty.modelName, modelReflectedData->what.model.name) == 0))
260 {
261 SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.reportedProperty.type);
262
263 /* if this is a model type use the appropriate APIs for it */
264 if (childModelHande != NULL)
265 {
266 if (Schema_AddModelModel(modelTypeHandle, something->what.reportedProperty.name, childModelHande, something->what.reportedProperty.offset, NULL) != SCHEMA_OK)
267 {
268 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
269 result = CODEFIRST_SCHEMA_ERROR;
270 LogError("add model failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
271 goto out;
272 }
273 }
274 else
275 {
276 if (Schema_AddModelReportedProperty(modelTypeHandle, something->what.reportedProperty.name, something->what.reportedProperty.type) != SCHEMA_OK)
277 {
278 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
279 result = CODEFIRST_SCHEMA_ERROR;
280 LogError("add reported property failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
281 goto out;
282 }
283 }
284 }
285
286 if ((something->type == REFLECTION_DESIRED_PROPERTY_TYPE) &&
287 (strcmp(something->what.desiredProperty.modelName, modelReflectedData->what.model.name) == 0))
288 {
289 SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.desiredProperty.type);
290
291 /* if this is a model type use the appropriate APIs for it */
292 if (childModelHande != NULL)
293 {
294 if (Schema_AddModelModel(modelTypeHandle, something->what.desiredProperty.name, childModelHande, something->what.desiredProperty.offset, something->what.desiredProperty.onDesiredProperty) != SCHEMA_OK)
295 {
296 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
297 result = CODEFIRST_SCHEMA_ERROR;
298 LogError("add model failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
299 goto out;
300 }
301 }
302 else
303 {
304 if (Schema_AddModelDesiredProperty(modelTypeHandle,
305 something->what.desiredProperty.name,
306 something->what.desiredProperty.type,
307 something->what.desiredProperty.FromAGENT_DATA_TYPE,
308 something->what.desiredProperty.desiredPropertInitialize,
309 something->what.desiredProperty.desiredPropertDeinitialize,
310 something->what.desiredProperty.offset,
311 something->what.desiredProperty.onDesiredProperty) != SCHEMA_OK)
312 {
313 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
314 result = CODEFIRST_SCHEMA_ERROR;
315 LogError("add desired property failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
316 goto out;
317 }
318 }
319 }
320
321 if ((something->type == REFLECTION_ACTION_TYPE) &&
322 (strcmp(something->what.action.modelName, modelReflectedData->what.model.name) == 0))
323 {
324 SCHEMA_ACTION_HANDLE actionHandle;
325 size_t i;
326
327 if ((actionHandle = Schema_CreateModelAction(modelTypeHandle, something->what.action.name)) == NULL)
328 {
329 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
330 result = CODEFIRST_SCHEMA_ERROR;
331 LogError("add model action failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
332 goto out;
333 }
334
335 for (i = 0; i < something->what.action.nArguments; i++)
336 {
337 if (Schema_AddModelActionArgument(actionHandle, something->what.action.arguments[i].name, something->what.action.arguments[i].type) != SCHEMA_OK)
338 {
339 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
340 result = CODEFIRST_SCHEMA_ERROR;
341 LogError("add model action argument failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
342 goto out;
343 }
344 }
345 }
346
347 if ((something->type == REFLECTION_METHOD_TYPE) &&
348 (strcmp(something->what.method.modelName, modelReflectedData->what.model.name) == 0))
349 {
350 SCHEMA_METHOD_HANDLE methodHandle;
351 size_t i;
352
353 if ((methodHandle = Schema_CreateModelMethod(modelTypeHandle, something->what.method.name)) == NULL)
354 {
355 /*Codes_SRS_CODEFIRST_99_076: [ If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL. ]*/
356 result = CODEFIRST_SCHEMA_ERROR;
357 LogError("add model method failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
358 goto out;
359 }
360
361 for (i = 0; i < something->what.method.nArguments; i++)
362 {
363 if (Schema_AddModelMethodArgument(methodHandle, something->what.method.arguments[i].name, something->what.method.arguments[i].type) != SCHEMA_OK)
364 {
365 /*Codes_SRS_CODEFIRST_99_076: [ If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL. ]*/
366 result = CODEFIRST_SCHEMA_ERROR;
367 LogError("add model method argument failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
368 goto out;
369 }
370 }
371 }
372 }
373
374out:
375 return result;
376}
377
378static CODEFIRST_RESULT buildModelTypes(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData)
379{
380 CODEFIRST_RESULT result = CODEFIRST_OK;
381 const REFLECTED_SOMETHING* something;
382
383 /* first have a pass and add all the model types */
384 for (something = reflectedData->reflectedData; something != NULL; something = something->next)
385 {
386 if (something->type == REFLECTION_MODEL_TYPE)
387 {
388 if (Schema_CreateModelType(schemaHandle, something->what.model.name) == NULL)
389 {
390 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/
391 result = CODEFIRST_SCHEMA_ERROR;
392 LogError("create model failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
393 goto out;
394 }
395 }
396 }
397
398 for (something = reflectedData->reflectedData; something != NULL; something = something->next)
399 {
400 if (something->type == REFLECTION_MODEL_TYPE)
401 {
402 result = buildModel(schemaHandle, reflectedData, something);
403 if (result != CODEFIRST_OK)
404 {
405 break;
406 }
407 }
408 }
409
410out:
411 return result;
412}
413
414static CODEFIRST_RESULT CodeFirst_Init_impl(const char* overrideSchemaNamespace, bool calledFromCodeFirst_Init)
415{
416 /*shall build the default EntityContainer*/
417 CODEFIRST_RESULT result;
418
419 if (g_state != CODEFIRST_STATE_NOT_INIT)
420 {
421 /*Codes_SRS_CODEFIRST_99_003:[ If the module is already initialized, the initialization shall fail and the return value shall be CODEFIRST_ALREADY_INIT.]*/
422 result = CODEFIRST_ALREADY_INIT;
423 if(calledFromCodeFirst_Init) /*do not log this error when APIs attempt lazy init*/
424 {
425 LogError("CodeFirst was already init %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, result));
426 }
427 }
428 else
429 {
430 g_DeviceCount = 0;
431 g_OverrideSchemaNamespace = overrideSchemaNamespace;
432 g_Devices = NULL;
433
434 /*Codes_SRS_CODEFIRST_99_002:[ CodeFirst_Init shall initialize the CodeFirst module. If initialization is successful, it shall return CODEFIRST_OK.]*/
435 g_state = calledFromCodeFirst_Init? CODEFIRST_STATE_INIT_BY_INIT: CODEFIRST_STATE_INIT_BY_API;
436 result = CODEFIRST_OK;
437 }
438 return result;
439}
440
441/*Codes_SRS_CODEFIRST_99_002:[ CodeFirst_Init shall initialize the CodeFirst module. If initialization is successful, it shall return CODEFIRST_OK.]*/
442CODEFIRST_RESULT CodeFirst_Init(const char* overrideSchemaNamespace)
443{
444 return CodeFirst_Init_impl(overrideSchemaNamespace, true);
445}
446
447void CodeFirst_Deinit(void)
448{
449 /*Codes_SRS_CODEFIRST_99_006:[If the module is not previously initialed, CodeFirst_Deinit shall do nothing.]*/
450 if (g_state != CODEFIRST_STATE_INIT_BY_INIT)
451 {
452 LogError("CodeFirst_Deinit called when CodeFirst was not initialized by CodeFirst_Init");
453 }
454 else
455 {
456 size_t i;
457
458 /*Codes_SRS_CODEFIRST_99_005:[ CodeFirst_Deinit shall deinitialize the module, freeing all the resources and placing the module in an uninitialized state.]*/
459 for (i = 0; i < g_DeviceCount; i++)
460 {
461 DestroyDevice(g_Devices[i]);
462 }
463
464 free(g_Devices);
465 g_Devices = NULL;
466 g_DeviceCount = 0;
467
468 g_state = CODEFIRST_STATE_NOT_INIT;
469 }
470}
471
472static const REFLECTED_SOMETHING* FindModelInCodeFirstMetadata(const REFLECTED_SOMETHING* reflectedData, const char* modelName)
473{
474 const REFLECTED_SOMETHING* result;
475
476 for (result = reflectedData; result != NULL; result = result->next)
477 {
478 if ((result->type == REFLECTION_MODEL_TYPE) &&
479 (strcmp(result->what.model.name, modelName) == 0))
480 {
481 /* found model type */
482 break;
483 }
484 }
485
486 return result;
487}
488
489static const REFLECTED_SOMETHING* FindChildModelInCodeFirstMetadata(const REFLECTED_SOMETHING* reflectedData, const REFLECTED_SOMETHING* startModel, const char* relativePath, size_t* offset)
490{
491 const REFLECTED_SOMETHING* result = startModel;
492 *offset = 0;
493
494 /* Codes_SRS_CODEFIRST_99_139:[If the relativeActionPath is empty then the action shall be looked up in the device model.] */
495 while ((*relativePath != 0) && (result != NULL))
496 {
497 /* Codes_SRS_CODEFIRST_99_142:[The relativeActionPath argument shall be in the format "childModel1/childModel2/.../childModelN".] */
498 const REFLECTED_SOMETHING* childModelProperty;
499 size_t propertyNameLength;
500 const char* slashPos = strchr(relativePath, '/');
501 if (slashPos == NULL)
502 {
503 slashPos = &relativePath[strlen(relativePath)];
504 }
505
506 propertyNameLength = slashPos - relativePath;
507
508 for (childModelProperty = reflectedData; childModelProperty != NULL; childModelProperty = childModelProperty->next)
509 {
510 if ((childModelProperty->type == REFLECTION_PROPERTY_TYPE) &&
511 (strcmp(childModelProperty->what.property.modelName, result->what.model.name) == 0) &&
512 (strncmp(childModelProperty->what.property.name, relativePath, propertyNameLength) == 0) &&
513 (strlen(childModelProperty->what.property.name) == propertyNameLength))
514 {
515 /* property found, now let's find the model */
516 /* Codes_SRS_CODEFIRST_99_140:[CodeFirst_InvokeAction shall pass to the action wrapper that it calls a pointer to the model where the action is defined.] */
517 *offset += childModelProperty->what.property.offset;
518 break;
519 }
520 }
521
522 if (childModelProperty == NULL)
523 {
524 /* not found */
525 result = NULL;
526 }
527 else
528 {
529 result = FindModelInCodeFirstMetadata(reflectedData, childModelProperty->what.property.type);
530 }
531
532 relativePath = slashPos;
533 }
534
535 return result;
536}
537
538EXECUTE_COMMAND_RESULT CodeFirst_InvokeAction(DEVICE_HANDLE deviceHandle, void* callbackUserContext, const char* relativeActionPath, const char* actionName, size_t parameterCount, const AGENT_DATA_TYPE* parameterValues)
539{
540 EXECUTE_COMMAND_RESULT result;
541 DEVICE_HEADER_DATA* deviceHeader = (DEVICE_HEADER_DATA*)callbackUserContext;
542
543 /*Codes_SRS_CODEFIRST_99_068:[ If the function is called before CodeFirst is initialized then EXECUTE_COMMAND_ERROR shall be returned.] */
544 if (g_state == CODEFIRST_STATE_NOT_INIT)
545 {
546 result = EXECUTE_COMMAND_ERROR;
547 LogError("CodeFirst_InvokeAction called before init has an error %s ", MU_ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
548 }
549 /*Codes_SRS_CODEFIRST_99_066:[ If actionName, relativeActionPath or deviceHandle is NULL then EXECUTE_COMMAND_ERROR shall be returned*/
550 else if ((actionName == NULL) ||
551 (deviceHandle == NULL) ||
552 (relativeActionPath == NULL))
553 {
554 result = EXECUTE_COMMAND_ERROR;
555 LogError("action Name is NULL %s ", MU_ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
556 }
557 /*Codes_SRS_CODEFIRST_99_067:[ If parameterCount is greater than zero and parameterValues is NULL then EXECUTE_COMMAND_ERROR shall be returned.]*/
558 else if ((parameterCount > 0) && (parameterValues == NULL))
559 {
560 result = EXECUTE_COMMAND_ERROR;
561 LogError("parameterValues error %s ", MU_ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
562 }
563 /*Codes_SRS_CODEFIRST_99_200:[ If deviceHeader (callbackUserContext) is NULL then EXECUTE_COMMAND_ERROR shall be returned.]*/
564 else if (deviceHeader == NULL)
565 {
566 result = EXECUTE_COMMAND_ERROR;
567 LogError("callback User Context error %s ", MU_ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
568 }
569 else
570 {
571 const REFLECTED_SOMETHING* something;
572 const REFLECTED_SOMETHING* childModel;
573 const char* modelName;
574 size_t offset;
575
576 modelName = Schema_GetModelName(deviceHeader->ModelHandle);
577
578 if (((childModel = FindModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, modelName)) == NULL) ||
579 /* Codes_SRS_CODEFIRST_99_138:[The relativeActionPath argument shall be used by CodeFirst_InvokeAction to find the child model where the action is declared.] */
580 ((childModel = FindChildModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, childModel, relativeActionPath, &offset)) == NULL))
581 {
582 /*Codes_SRS_CODEFIRST_99_141:[If a child model specified in the relativeActionPath argument cannot be found by CodeFirst_InvokeAction, it shall return EXECUTE_COMMAND_ERROR.] */
583 result = EXECUTE_COMMAND_ERROR;
584 LogError("action %s was not found %s ", actionName, MU_ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
585 }
586 else
587 {
588 /* Codes_SRS_CODEFIRST_99_062:[ When CodeFirst_InvokeAction is called it shall look through the codefirst metadata associated with a specific device for a previously declared action (function) named actionName.]*/
589 /* Codes_SRS_CODEFIRST_99_078:[If such a function is not found then the function shall return EXECUTE_COMMAND_ERROR.]*/
590 result = EXECUTE_COMMAND_ERROR;
591 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next)
592 {
593 if ((something->type == REFLECTION_ACTION_TYPE) &&
594 (strcmp(actionName, something->what.action.name) == 0) &&
595 (strcmp(childModel->what.model.name, something->what.action.modelName) == 0))
596 {
597 /*Codes_SRS_CODEFIRST_99_063:[ If the function is found, then CodeFirst shall call the wrapper of the found function inside the data provider. The wrapper is linked in the reflected data to the function name. The wrapper shall be called with the same arguments as CodeFirst_InvokeAction has been called.]*/
598 /*Codes_SRS_CODEFIRST_99_064:[ If the wrapper call succeeds then CODEFIRST_OK shall be returned. ]*/
599 /*Codes_SRS_CODEFIRST_99_065:[ For all the other return values CODEFIRST_ACTION_EXECUTION_ERROR shall be returned.]*/
600 /* Codes_SRS_CODEFIRST_99_140:[CodeFirst_InvokeAction shall pass to the action wrapper that it calls a pointer to the model where the action is defined.] */
601 /*Codes_SRS_CODEFIRST_02_013: [The wrapper's return value shall be returned.]*/
602 result = something->what.action.wrapper(deviceHeader->data + offset, parameterCount, parameterValues);
603 break;
604 }
605 }
606 }
607 }
608
609 if (result == EXECUTE_COMMAND_ERROR)
610 {
611 LogError(" %s ", MU_ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result));
612 }
613 return result;
614}
615
616METHODRETURN_HANDLE CodeFirst_InvokeMethod(DEVICE_HANDLE deviceHandle, void* callbackUserContext, const char* relativeMethodPath, const char* methodName, size_t parameterCount, const AGENT_DATA_TYPE* parameterValues)
617{
618 METHODRETURN_HANDLE result;
619 DEVICE_HEADER_DATA* deviceHeader = (DEVICE_HEADER_DATA*)callbackUserContext;
620
621 if (g_state == CODEFIRST_STATE_NOT_INIT)
622 {
623 result = NULL;
624 LogError("CodeFirst_InvokeMethod called before CodeFirst_Init");
625 }
626 else if ((methodName == NULL) ||
627 (deviceHandle == NULL) ||
628 (relativeMethodPath == NULL))
629 {
630 result = NULL;
631 LogError("invalid args: DEVICE_HANDLE deviceHandle=%p, void* callbackUserContext=%p, const char* relativeMethodPath=%p, const char* methodName=%p, size_t parameterCount=%lu, const AGENT_DATA_TYPE* parameterValues=%p",
632 deviceHandle, callbackUserContext, relativeMethodPath, methodName, (unsigned long)parameterCount, parameterValues);
633 }
634 else if ((parameterCount > 0) && (parameterValues == NULL))
635 {
636 result = NULL;
637 LogError("parameterValues error ");
638 }
639 else if (deviceHeader == NULL)
640 {
641 result = NULL;
642 LogError("callback User Context error ");
643 }
644 else
645 {
646 const REFLECTED_SOMETHING* something;
647 const REFLECTED_SOMETHING* childModel;
648 const char* modelName;
649 size_t offset;
650
651 modelName = Schema_GetModelName(deviceHeader->ModelHandle);
652
653 if (((childModel = FindModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, modelName)) == NULL) ||
654 ((childModel = FindChildModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, childModel, relativeMethodPath, &offset)) == NULL))
655 {
656 result = NULL;
657 LogError("method %s was not found", methodName);
658 }
659 else
660 {
661 result = NULL;
662 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next)
663 {
664 if ((something->type == REFLECTION_METHOD_TYPE) &&
665 (strcmp(methodName, something->what.method.name) == 0) &&
666 (strcmp(childModel->what.model.name, something->what.method.modelName) == 0))
667 {
668 break; /*found...*/
669 }
670 }
671
672 if (something == NULL)
673 {
674 LogError("method \"%s\" not found", methodName);
675 result = NULL;
676 }
677 else
678 {
679 result = something->what.method.wrapper(deviceHeader->data + offset, parameterCount, parameterValues);
680 if (result == NULL)
681 {
682 LogError("method \"%s\" execution error (returned NULL)", methodName);
683 }
684 }
685 }
686 }
687 return result;
688}
689
690
691/* Codes_SRS_CODEFIRST_99_002:[ CodeFirst_RegisterSchema shall create the schema information and give it to the Schema module for one schema, identified by the metadata argument. On success, it shall return a handle to the schema.] */
692SCHEMA_HANDLE CodeFirst_RegisterSchema(const char* schemaNamespace, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata)
693{
694 SCHEMA_HANDLE result;
695 /*Codes_SRS_CODEFIRST_02_048: [ If schemaNamespace is NULL then CodeFirst_RegisterSchema shall fail and return NULL. ]*/
696 /*Codes_SRS_CODEFIRST_02_049: [ If metadata is NULL then CodeFirst_RegisterSchema shall fail and return NULL. ]*/
697 if (
698 (schemaNamespace == NULL) ||
699 (metadata == NULL)
700 )
701 {
702 LogError("invalid arg const char* schemaNamespace=%p, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata=%p", schemaNamespace, metadata);
703 result = NULL;
704 }
705 else
706 {
707 if (g_OverrideSchemaNamespace != NULL)
708 {
709 schemaNamespace = g_OverrideSchemaNamespace;
710 }
711
712 /* Codes_SRS_CODEFIRST_99_121:[If the schema has already been registered, CodeFirst_RegisterSchema shall return its handle.] */
713 result = Schema_GetSchemaByNamespace(schemaNamespace);
714 if (result == NULL)
715 {
716 if ((result = Schema_Create(schemaNamespace, (void*)metadata)) == NULL)
717 {
718 /* Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL.] */
719 result = NULL;
720 LogError("schema init failed %s", MU_ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_SCHEMA_ERROR));
721 }
722 else
723 {
724 if ((buildStructTypes(result, metadata) != CODEFIRST_OK) ||
725 (buildModelTypes(result, metadata) != CODEFIRST_OK))
726 {
727 Schema_Destroy(result);
728 result = NULL;
729 }
730 else
731 {
732 /* do nothing, everything is OK */
733 }
734 }
735 }
736 }
737
738 return result;
739}
740
741AGENT_DATA_TYPE_TYPE CodeFirst_GetPrimitiveType(const char* typeName)
742{
743#ifndef NO_FLOATS
744 if (strcmp(typeName, "double") == 0)
745 {
746 return EDM_DOUBLE_TYPE;
747 }
748 else if (strcmp(typeName, "float") == 0)
749 {
750 return EDM_SINGLE_TYPE;
751 }
752 else
753#endif
754 if (strcmp(typeName, "int") == 0)
755 {
756 return EDM_INT32_TYPE;
757 }
758 else if (strcmp(typeName, "long") == 0)
759 {
760 return EDM_INT64_TYPE;
761 }
762 else if (strcmp(typeName, "int8_t") == 0)
763 {
764 return EDM_SBYTE_TYPE;
765 }
766 else if (strcmp(typeName, "uint8_t") == 0)
767 {
768 return EDM_BYTE_TYPE;
769 }
770 else if (strcmp(typeName, "int16_t") == 0)
771 {
772 return EDM_INT16_TYPE;
773 }
774 else if (strcmp(typeName, "int32_t") == 0)
775 {
776 return EDM_INT32_TYPE;
777 }
778 else if (strcmp(typeName, "int64_t") == 0)
779 {
780 return EDM_INT64_TYPE;
781 }
782 else if (
783 (strcmp(typeName, "_Bool") == 0) ||
784 (strcmp(typeName, "bool") == 0)
785 )
786 {
787 return EDM_BOOLEAN_TYPE;
788 }
789 else if (strcmp(typeName, "ascii_char_ptr") == 0)
790 {
791 return EDM_STRING_TYPE;
792 }
793 else if (strcmp(typeName, "ascii_char_ptr_no_quotes") == 0)
794 {
795 return EDM_STRING_NO_QUOTES_TYPE;
796 }
797 else if (strcmp(typeName, "EDM_DATE_TIME_OFFSET") == 0)
798 {
799 return EDM_DATE_TIME_OFFSET_TYPE;
800 }
801 else if (strcmp(typeName, "EDM_GUID") == 0)
802 {
803 return EDM_GUID_TYPE;
804 }
805 else if (strcmp(typeName, "EDM_BINARY") == 0)
806 {
807 return EDM_BINARY_TYPE;
808 }
809 else
810 {
811 return EDM_NO_TYPE;
812 }
813}
814
815static void initializeDesiredProperties(SCHEMA_MODEL_TYPE_HANDLE model, void* destination)
816{
817 /*this function assumes that at the address given by destination there is an instance of a model*/
818 /*some constituents of the model need to be initialized - ascii_char_ptr for example should be set to NULL*/
819
820 size_t nDesiredProperties;
821 if (Schema_GetModelDesiredPropertyCount(model, &nDesiredProperties) != SCHEMA_OK)
822 {
823 LogError("unexpected error in Schema_GetModelDesiredPropertyCount");
824 }
825 else
826 {
827 size_t nProcessedDesiredProperties = 0;
828 for (size_t i = 0;i < nDesiredProperties;i++)
829 {
830 SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle = Schema_GetModelDesiredPropertyByIndex(model, i);
831 if (desiredPropertyHandle == NULL)
832 {
833 LogError("unexpected error in Schema_GetModelDesiredPropertyByIndex");
834 i = nDesiredProperties;
835 }
836 else
837 {
838 pfDesiredPropertyInitialize desiredPropertyInitialize = Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize(desiredPropertyHandle);
839 if (desiredPropertyInitialize == NULL)
840 {
841 LogError("unexpected error in Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize");
842 i = nDesiredProperties;
843 }
844 else
845 {
846 /*Codes_SRS_CODEFIRST_02_036: [ CodeFirst_CreateDevice shall initialize all the desired properties to their default values. ]*/
847 size_t offset = Schema_GetModelDesiredProperty_offset(desiredPropertyHandle);
848 desiredPropertyInitialize((char*)destination + offset);
849 nProcessedDesiredProperties++;
850 }
851 }
852 }
853
854 if (nDesiredProperties == nProcessedDesiredProperties)
855 {
856 /*recursively go in the model and initialize the other fields*/
857 size_t nModelInModel;
858 if (Schema_GetModelModelCount(model, &nModelInModel) != SCHEMA_OK)
859 {
860 LogError("unexpected error in Schema_GetModelModelCount");
861 }
862 else
863 {
864 size_t nProcessedModelInModel = 0;
865 for (size_t i = 0; i < nModelInModel;i++)
866 {
867 SCHEMA_MODEL_TYPE_HANDLE modelInModel = Schema_GetModelModelyByIndex(model, i);
868 if (modelInModel == NULL)
869 {
870 LogError("unexpected failure in Schema_GetModelModelyByIndex");
871 i = nModelInModel;
872 }
873 else
874 {
875 size_t offset = Schema_GetModelModelByIndex_Offset(model, i);
876 initializeDesiredProperties(modelInModel, (char*)destination + offset);
877 nProcessedModelInModel++;
878 }
879 }
880
881 if (nProcessedModelInModel == nModelInModel)
882 {
883 /*all is fine... */
884 }
885 }
886 }
887 }
888}
889
890/* Codes_SRS_CODEFIRST_99_079:[CodeFirst_CreateDevice shall create a device and allocate a memory block that should hold the device data.] */
891void* CodeFirst_CreateDevice(SCHEMA_MODEL_TYPE_HANDLE model, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata, size_t dataSize, bool includePropertyPath)
892{
893 void* result;
894 DEVICE_HEADER_DATA* deviceHeader;
895
896 /* Codes_SRS_CODEFIRST_99_080:[If CodeFirst_CreateDevice is invoked with a NULL model, it shall return NULL.]*/
897 if (model == NULL)
898 {
899 result = NULL;
900 LogError(" %s ", MU_ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_INVALID_ARG));
901 }
902 else
903 {
904 /*Codes_SRS_CODEFIRST_02_037: [ CodeFirst_CreateDevice shall call CodeFirst_Init, passing NULL for overrideSchemaNamespace. ]*/
905 (void)CodeFirst_Init_impl(NULL, false); /*lazy init*/
906
907 if ((deviceHeader = (DEVICE_HEADER_DATA*)calloc(1, sizeof(DEVICE_HEADER_DATA))) == NULL)
908 {
909 /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */
910 result = NULL;
911 LogError(" %s ", MU_ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR));
912 }
913 /* Codes_SRS_CODEFIRST_99_081:[CodeFirst_CreateDevice shall use Device_Create to create a device handle.] */
914 /* Codes_SRS_CODEFIRST_99_082: [ CodeFirst_CreateDevice shall pass to Device_Create the function CodeFirst_InvokeAction, action callback argument and the CodeFirst_InvokeMethod ] */
915 else
916 {
917 if ((deviceHeader->data = malloc(dataSize)) == NULL)
918 {
919 free(deviceHeader);
920 deviceHeader = NULL;
921 result = NULL;
922 LogError(" %s ", MU_ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR));
923 }
924 else
925 {
926 DEVICE_HEADER_DATA** newDevices;
927
928 initializeDesiredProperties(model, deviceHeader->data);
929
930 if (Device_Create(model, CodeFirst_InvokeAction, deviceHeader, CodeFirst_InvokeMethod, deviceHeader,
931 includePropertyPath, &deviceHeader->DeviceHandle) != DEVICE_OK)
932 {
933 free(deviceHeader->data);
934 free(deviceHeader);
935
936 /* Codes_SRS_CODEFIRST_99_084:[If Device_Create fails, CodeFirst_CreateDevice shall return NULL.] */
937 result = NULL;
938 LogError(" %s ", MU_ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_DEVICE_FAILED));
939 }
940 else if ((newDevices = (DEVICE_HEADER_DATA**)realloc(g_Devices, sizeof(DEVICE_HEADER_DATA*) * (g_DeviceCount + 1))) == NULL)
941 {
942 Device_Destroy(deviceHeader->DeviceHandle);
943 free(deviceHeader->data);
944 free(deviceHeader);
945
946 /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */
947 result = NULL;
948 LogError(" %s ", MU_ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR));
949 }
950 else
951 {
952 SCHEMA_RESULT schemaResult;
953 deviceHeader->ReflectedData = metadata;
954 deviceHeader->DataSize = dataSize;
955 deviceHeader->ModelHandle = model;
956 schemaResult = Schema_AddDeviceRef(model);
957 if (schemaResult != SCHEMA_OK)
958 {
959 Device_Destroy(deviceHeader->DeviceHandle);
960 free(newDevices);
961 free(deviceHeader->data);
962 free(deviceHeader);
963
964 /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */
965 result = NULL;
966 }
967 else
968 {
969 g_Devices = newDevices;
970 g_Devices[g_DeviceCount] = deviceHeader;
971 g_DeviceCount++;
972
973 /* Codes_SRS_CODEFIRST_99_101:[On success, CodeFirst_CreateDevice shall return a non NULL pointer to the device data.] */
974 result = deviceHeader->data;
975 }
976 }
977 }
978 }
979
980 }
981
982 return result;
983}
984
985void CodeFirst_DestroyDevice(void* device)
986{
987 /* Codes_SRS_CODEFIRST_99_086:[If the argument is NULL, CodeFirst_DestroyDevice shall do nothing.] */
988 if (device != NULL)
989 {
990 size_t i;
991
992 for (i = 0; i < g_DeviceCount; i++)
993 {
994 if (g_Devices[i]->data == device)
995 {
996 deinitializeDesiredProperties(g_Devices[i]->ModelHandle, g_Devices[i]->data);
997 Schema_ReleaseDeviceRef(g_Devices[i]->ModelHandle);
998
999 // Delete the Created Schema if all the devices are unassociated
1000 Schema_DestroyIfUnused(g_Devices[i]->ModelHandle);
1001
1002 DestroyDevice(g_Devices[i]);
1003 (void)memcpy(&g_Devices[i], &g_Devices[i + 1], (g_DeviceCount - i - 1) * sizeof(DEVICE_HEADER_DATA*));
1004 g_DeviceCount--;
1005 break;
1006 }
1007 }
1008
1009 /*Codes_SRS_CODEFIRST_02_039: [ If the current device count is zero then CodeFirst_DestroyDevice shall deallocate all other used resources. ]*/
1010 if ((g_state == CODEFIRST_STATE_INIT_BY_API) && (g_DeviceCount == 0))
1011 {
1012 free(g_Devices);
1013 g_Devices = NULL;
1014 g_state = CODEFIRST_STATE_NOT_INIT;
1015 }
1016 }
1017}
1018
1019static DEVICE_HEADER_DATA* FindDevice(void* value)
1020{
1021 size_t i;
1022 DEVICE_HEADER_DATA* result = NULL;
1023
1024 for (i = 0; i < g_DeviceCount; i++)
1025 {
1026 if ((g_Devices[i]->data <= (unsigned char*)value) &&
1027 (g_Devices[i]->data + g_Devices[i]->DataSize > (unsigned char*)value))
1028 {
1029 result = g_Devices[i];
1030 break;
1031 }
1032 }
1033
1034 return result;
1035}
1036
1037static const REFLECTED_SOMETHING* FindValue(DEVICE_HEADER_DATA* deviceHeader, void* value, const char* modelName, size_t startOffset, STRING_HANDLE valuePath)
1038{
1039 const REFLECTED_SOMETHING* result;
1040 size_t valueOffset = (size_t)((unsigned char*)value - (unsigned char*)deviceHeader->data) - startOffset;
1041
1042 for (result = deviceHeader->ReflectedData->reflectedData; result != NULL; result = result->next)
1043 {
1044 if (result->type == REFLECTION_PROPERTY_TYPE &&
1045 (strcmp(result->what.property.modelName, modelName) == 0) &&
1046 (result->what.property.offset <= valueOffset) &&
1047 (result->what.property.offset + result->what.property.size > valueOffset))
1048 {
1049 if (startOffset != 0)
1050 {
1051 STRING_concat(valuePath, "/");
1052 }
1053
1054 STRING_concat(valuePath, result->what.property.name);
1055 break;
1056 }
1057 }
1058
1059 if (result != NULL)
1060 {
1061 /* Codes_SRS_CODEFIRST_99_133:[CodeFirst_SendAsync shall allow sending of properties that are part of a child model.] */
1062 if (result->what.property.offset < valueOffset)
1063 {
1064 /* find recursively the property in the inner model, if there is one */
1065 result = FindValue(deviceHeader, value, result->what.property.type, startOffset + result->what.property.offset, valuePath);
1066 }
1067 }
1068
1069 return result;
1070}
1071
1072static const REFLECTED_SOMETHING* FindReportedProperty(DEVICE_HEADER_DATA* deviceHeader, void* value, const char* modelName, size_t startOffset, STRING_HANDLE valuePath)
1073{
1074 const REFLECTED_SOMETHING* result;
1075 size_t valueOffset = (size_t)((unsigned char*)value - (unsigned char*)deviceHeader->data) - startOffset;
1076
1077 for (result = deviceHeader->ReflectedData->reflectedData; result != NULL; result = result->next)
1078 {
1079 if (result->type == REFLECTION_REPORTED_PROPERTY_TYPE &&
1080 (strcmp(result->what.reportedProperty.modelName, modelName) == 0) &&
1081 (result->what.reportedProperty.offset <= valueOffset) &&
1082 (result->what.reportedProperty.offset + result->what.reportedProperty.size > valueOffset))
1083 {
1084 if (startOffset != 0)
1085 {
1086 if (STRING_concat(valuePath, "/") != 0)
1087 {
1088 LogError("unable to STRING_concat");
1089 result = NULL;
1090 break;
1091 }
1092 }
1093
1094 if (STRING_concat(valuePath, result->what.reportedProperty.name) != 0)
1095 {
1096 LogError("unable to STRING_concat");
1097 result = NULL;
1098 break;
1099 }
1100 break;
1101 }
1102 }
1103
1104 if (result != NULL)
1105 {
1106 /* Codes_SRS_CODEFIRST_99_133:[CodeFirst_SendAsync shall allow sending of properties that are part of a child model.] */
1107 if (result->what.reportedProperty.offset < valueOffset)
1108 {
1109 /* find recursively the property in the inner model, if there is one */
1110 result = FindReportedProperty(deviceHeader, value, result->what.reportedProperty.type, startOffset + result->what.reportedProperty.offset, valuePath);
1111 }
1112 }
1113
1114 return result;
1115}
1116
1117/* Codes_SRS_CODEFIRST_99_130:[If a pointer to the beginning of a device block is passed to CodeFirst_SendAsync instead of a pointer to a property, CodeFirst_SendAsync shall send all the properties that belong to that device.] */
1118/* Codes_SRS_CODEFIRST_99_131:[The properties shall be given to Device as one transaction, as if they were all passed as individual arguments to Code_First.] */
1119static CODEFIRST_RESULT SendAllDeviceProperties(DEVICE_HEADER_DATA* deviceHeader, TRANSACTION_HANDLE transaction)
1120{
1121 const char* modelName = Schema_GetModelName(deviceHeader->ModelHandle);
1122 const REFLECTED_SOMETHING* something;
1123 unsigned char* deviceAddress = (unsigned char*)deviceHeader->data;
1124 CODEFIRST_RESULT result = CODEFIRST_OK;
1125
1126 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next)
1127 {
1128 if ((something->type == REFLECTION_PROPERTY_TYPE) &&
1129 (strcmp(something->what.property.modelName, modelName) == 0))
1130 {
1131 AGENT_DATA_TYPE agentDataType;
1132
1133 /* Codes_SRS_CODEFIRST_99_097:[For each value marshalling to AGENT_DATA_TYPE shall be performed.] */
1134 /* Codes_SRS_CODEFIRST_99_098:[The marshalling shall be done by calling the Create_AGENT_DATA_TYPE_from_Ptr function associated with the property.] */
1135 if (something->what.property.Create_AGENT_DATA_TYPE_from_Ptr(deviceAddress + something->what.property.offset, &agentDataType) != AGENT_DATA_TYPES_OK)
1136 {
1137 /* Codes_SRS_CODEFIRST_99_099:[If Create_AGENT_DATA_TYPE_from_Ptr fails, CodeFirst_SendAsync shall return CODEFIRST_AGENT_DATA_TYPE_ERROR.] */
1138 result = CODEFIRST_AGENT_DATA_TYPE_ERROR;
1139 LOG_CODEFIRST_ERROR;
1140 break;
1141 }
1142 else
1143 {
1144 /* Codes_SRS_CODEFIRST_99_092:[CodeFirst shall publish each value by using Device_PublishTransacted.] */
1145 if (Device_PublishTransacted(transaction, something->what.property.name, &agentDataType) != DEVICE_OK)
1146 {
1147 Destroy_AGENT_DATA_TYPE(&agentDataType);
1148
1149 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
1150 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1151 LOG_CODEFIRST_ERROR;
1152 break;
1153 }
1154
1155 Destroy_AGENT_DATA_TYPE(&agentDataType);
1156 }
1157 }
1158 }
1159
1160 return result;
1161}
1162
1163static CODEFIRST_RESULT SendAllDeviceReportedProperties(DEVICE_HEADER_DATA* deviceHeader, REPORTED_PROPERTIES_TRANSACTION_HANDLE transaction)
1164{
1165 const char* modelName = Schema_GetModelName(deviceHeader->ModelHandle);
1166 const REFLECTED_SOMETHING* something;
1167 unsigned char* deviceAddress = (unsigned char*)deviceHeader->data;
1168 CODEFIRST_RESULT result = CODEFIRST_OK;
1169
1170 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next)
1171 {
1172 if ((something->type == REFLECTION_REPORTED_PROPERTY_TYPE) &&
1173 (strcmp(something->what.reportedProperty.modelName, modelName) == 0))
1174 {
1175 AGENT_DATA_TYPE agentDataType;
1176
1177 if (something->what.reportedProperty.Create_AGENT_DATA_TYPE_from_Ptr(deviceAddress + something->what.reportedProperty.offset, &agentDataType) != AGENT_DATA_TYPES_OK)
1178 {
1179 result = CODEFIRST_AGENT_DATA_TYPE_ERROR;
1180 LOG_CODEFIRST_ERROR;
1181 break;
1182 }
1183 else
1184 {
1185 if (Device_PublishTransacted_ReportedProperty(transaction, something->what.reportedProperty.name, &agentDataType) != DEVICE_OK)
1186 {
1187 Destroy_AGENT_DATA_TYPE(&agentDataType);
1188 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1189 LOG_CODEFIRST_ERROR;
1190 break;
1191 }
1192
1193 Destroy_AGENT_DATA_TYPE(&agentDataType);
1194 }
1195 }
1196 }
1197
1198 return result;
1199}
1200
1201
1202/* Codes_SRS_CODEFIRST_99_088:[CodeFirst_SendAsync shall send to the Device module a set of properties, a destination and a destinationSize.]*/
1203CODEFIRST_RESULT CodeFirst_SendAsync(unsigned char** destination, size_t* destinationSize, size_t numProperties, ...)
1204{
1205 CODEFIRST_RESULT result;
1206 va_list ap;
1207
1208 if (
1209 (numProperties == 0) ||
1210 (destination == NULL) ||
1211 (destinationSize == NULL)
1212 )
1213 {
1214 /* Codes_SRS_CODEFIRST_04_002: [If CodeFirst_SendAsync receives destination or destinationSize NULL, CodeFirst_SendAsync shall return Invalid Argument.]*/
1215 /* Codes_SRS_CODEFIRST_99_103:[If CodeFirst_SendAsync is called with numProperties being zero, CODEFIRST_INVALID_ARG shall be returned.] */
1216 result = CODEFIRST_INVALID_ARG;
1217 LOG_CODEFIRST_ERROR;
1218 }
1219 else
1220 {
1221 /*Codes_SRS_CODEFIRST_02_040: [ CodeFirst_SendAsync shall call CodeFirst_Init, passing NULL for overrideSchemaNamespace. ]*/
1222 (void)CodeFirst_Init_impl(NULL, false); /*lazy init*/
1223
1224 DEVICE_HEADER_DATA* deviceHeader = NULL;
1225 size_t i;
1226 TRANSACTION_HANDLE transaction = NULL;
1227 result = CODEFIRST_OK;
1228
1229 /* Codes_SRS_CODEFIRST_99_105:[The properties are passed as pointers to the memory locations where the data exists in the device block allocated by CodeFirst_CreateDevice.] */
1230 va_start(ap, numProperties);
1231
1232 /* Codes_SRS_CODEFIRST_99_089:[The numProperties argument shall indicate how many properties are to be sent.] */
1233 for (i = 0; i < numProperties; i++)
1234 {
1235 void* value = (void*)va_arg(ap, void*);
1236
1237 /* Codes_SRS_CODEFIRST_99_095:[For each value passed to it, CodeFirst_SendAsync shall look up to which device the value belongs.] */
1238 DEVICE_HEADER_DATA* currentValueDeviceHeader = FindDevice(value);
1239 if (currentValueDeviceHeader == NULL)
1240 {
1241 /* Codes_SRS_CODEFIRST_99_104:[If a property cannot be associated with a device, CodeFirst_SendAsync shall return CODEFIRST_INVALID_ARG.] */
1242 result = CODEFIRST_INVALID_ARG;
1243 LOG_CODEFIRST_ERROR;
1244 break;
1245 }
1246 else if ((deviceHeader != NULL) &&
1247 (currentValueDeviceHeader != deviceHeader))
1248 {
1249 /* Codes_SRS_CODEFIRST_99_096:[All values have to belong to the same device, otherwise CodeFirst_SendAsync shall return CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR.] */
1250 result = CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR;
1251 LOG_CODEFIRST_ERROR;
1252 break;
1253 }
1254 /* Codes_SRS_CODEFIRST_99_090:[All the properties shall be sent together by using the transacted APIs of the device.] */
1255 /* Codes_SRS_CODEFIRST_99_091:[CodeFirst_SendAsync shall start a transaction by calling Device_StartTransaction.] */
1256 else if ((deviceHeader == NULL) &&
1257 ((transaction = Device_StartTransaction(currentValueDeviceHeader->DeviceHandle)) == NULL))
1258 {
1259 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
1260 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1261 LOG_CODEFIRST_ERROR;
1262 break;
1263 }
1264 else
1265 {
1266 deviceHeader = currentValueDeviceHeader;
1267
1268 if (value == ((unsigned char*)deviceHeader->data))
1269 {
1270 /* we got a full device, send all its state data */
1271 result = SendAllDeviceProperties(deviceHeader, transaction);
1272 if (result != CODEFIRST_OK)
1273 {
1274 LOG_CODEFIRST_ERROR;
1275 break;
1276 }
1277 }
1278 else
1279 {
1280 const REFLECTED_SOMETHING* propertyReflectedData;
1281 const char* modelName;
1282 STRING_HANDLE valuePath;
1283
1284 if ((valuePath = STRING_new()) == NULL)
1285 {
1286 /* Codes_SRS_CODEFIRST_99_134:[If CodeFirst_Notify fails for any other reason it shall return CODEFIRST_ERROR.] */
1287 result = CODEFIRST_ERROR;
1288 LOG_CODEFIRST_ERROR;
1289 break;
1290 }
1291 else
1292 {
1293 if ((modelName = Schema_GetModelName(deviceHeader->ModelHandle)) == NULL)
1294 {
1295 /* Codes_SRS_CODEFIRST_99_134:[If CodeFirst_Notify fails for any other reason it shall return CODEFIRST_ERROR.] */
1296 result = CODEFIRST_ERROR;
1297 LOG_CODEFIRST_ERROR;
1298 STRING_delete(valuePath);
1299 break;
1300 }
1301 else if ((propertyReflectedData = FindValue(deviceHeader, value, modelName, 0, valuePath)) == NULL)
1302 {
1303 /* Codes_SRS_CODEFIRST_99_104:[If a property cannot be associated with a device, CodeFirst_SendAsync shall return CODEFIRST_INVALID_ARG.] */
1304 result = CODEFIRST_INVALID_ARG;
1305 LOG_CODEFIRST_ERROR;
1306 STRING_delete(valuePath);
1307 break;
1308 }
1309 else
1310 {
1311 AGENT_DATA_TYPE agentDataType;
1312
1313 /* Codes_SRS_CODEFIRST_99_097:[For each value marshalling to AGENT_DATA_TYPE shall be performed.] */
1314 /* Codes_SRS_CODEFIRST_99_098:[The marshalling shall be done by calling the Create_AGENT_DATA_TYPE_from_Ptr function associated with the property.] */
1315 if (propertyReflectedData->what.property.Create_AGENT_DATA_TYPE_from_Ptr(value, &agentDataType) != AGENT_DATA_TYPES_OK)
1316 {
1317 /* Codes_SRS_CODEFIRST_99_099:[If Create_AGENT_DATA_TYPE_from_Ptr fails, CodeFirst_SendAsync shall return CODEFIRST_AGENT_DATA_TYPE_ERROR.] */
1318 result = CODEFIRST_AGENT_DATA_TYPE_ERROR;
1319 LOG_CODEFIRST_ERROR;
1320 STRING_delete(valuePath);
1321 break;
1322 }
1323 else
1324 {
1325 /* Codes_SRS_CODEFIRST_99_092:[CodeFirst shall publish each value by using Device_PublishTransacted.] */
1326 /* Codes_SRS_CODEFIRST_99_136:[CodeFirst_SendAsync shall build the full path for each property and then pass it to Device_PublishTransacted.] */
1327 if (Device_PublishTransacted(transaction, STRING_c_str(valuePath), &agentDataType) != DEVICE_OK)
1328 {
1329 Destroy_AGENT_DATA_TYPE(&agentDataType);
1330
1331 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
1332 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1333 LOG_CODEFIRST_ERROR;
1334 STRING_delete(valuePath);
1335 break;
1336 }
1337 else
1338 {
1339 STRING_delete(valuePath); /*anyway*/
1340 }
1341
1342 Destroy_AGENT_DATA_TYPE(&agentDataType);
1343 }
1344 }
1345 }
1346 }
1347 }
1348 }
1349
1350 if (i < numProperties)
1351 {
1352 if (transaction != NULL)
1353 {
1354 (void)Device_CancelTransaction(transaction);
1355 }
1356 }
1357 /* Codes_SRS_CODEFIRST_99_093:[After all values have been published, Device_EndTransaction shall be called.] */
1358 else if (Device_EndTransaction(transaction, destination, destinationSize) != DEVICE_OK)
1359 {
1360 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */
1361 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1362 LOG_CODEFIRST_ERROR;
1363 }
1364 else
1365 {
1366 /* Codes_SRS_CODEFIRST_99_117:[On success, CodeFirst_SendAsync shall return CODEFIRST_OK.] */
1367 result = CODEFIRST_OK;
1368 }
1369
1370 va_end(ap);
1371
1372 }
1373
1374 return result;
1375}
1376
1377CODEFIRST_RESULT CodeFirst_SendAsyncReported(unsigned char** destination, size_t* destinationSize, size_t numReportedProperties, ...)
1378{
1379 CODEFIRST_RESULT result;
1380 if ((destination == NULL) || (destinationSize == NULL) || numReportedProperties == 0)
1381 {
1382 /*Codes_SRS_CODEFIRST_02_018: [ If parameter destination, destinationSize or any of the values passed through va_args is NULL then CodeFirst_SendAsyncReported shall fail and return CODEFIRST_INVALID_ARG. ]*/
1383 LogError("invalid argument unsigned char** destination=%p, size_t* destinationSize=%p, size_t numReportedProperties=%lu", destination, destinationSize, (unsigned long)numReportedProperties);
1384 result = CODEFIRST_INVALID_ARG;
1385 }
1386 else
1387 {
1388 /*Codes_SRS_CODEFIRST_02_046: [ CodeFirst_SendAsyncReported shall call CodeFirst_Init, passing NULL for overrideSchemaNamespace. ]*/
1389 (void)CodeFirst_Init_impl(NULL, false);/*lazy init*/
1390
1391 DEVICE_HEADER_DATA* deviceHeader = NULL;
1392 size_t i;
1393 REPORTED_PROPERTIES_TRANSACTION_HANDLE transaction = NULL;
1394 va_list ap;
1395 result = CODEFIRST_ACTION_EXECUTION_ERROR; /*this initialization squelches a false warning about result not being initialized*/
1396
1397 va_start(ap, numReportedProperties);
1398
1399 for (i = 0; i < numReportedProperties; i++)
1400 {
1401 void* value = (void*)va_arg(ap, void*);
1402 /*Codes_SRS_CODEFIRST_02_018: [ If parameter destination, destinationSize or any of the values passed through va_args is NULL then CodeFirst_SendAsyncReported shall fail and return CODEFIRST_INVALID_ARG. ]*/
1403 if (value == NULL)
1404 {
1405 LogError("argument number %lu passed through variable arguments is NULL", (unsigned long)i);
1406 result = CODEFIRST_INVALID_ARG;
1407 break;
1408 }
1409 else
1410 {
1411 DEVICE_HEADER_DATA* currentValueDeviceHeader = FindDevice(value);
1412 if (currentValueDeviceHeader == NULL)
1413 {
1414 result = CODEFIRST_INVALID_ARG;
1415 LOG_CODEFIRST_ERROR;
1416 break;
1417 }
1418 /*Codes_SRS_CODEFIRST_02_019: [ If values passed through va_args do not belong to the same device then CodeFirst_SendAsyncReported shall fail and return CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR. ]*/
1419 else if ((deviceHeader != NULL) &&
1420 (currentValueDeviceHeader != deviceHeader))
1421 {
1422 result = CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR;
1423 LOG_CODEFIRST_ERROR;
1424 break;
1425 }
1426 /*Codes_SRS_CODEFIRST_02_022: [ CodeFirst_SendAsyncReported shall start a transaction by calling Device_CreateTransaction_ReportedProperties. ]*/
1427 else if ((deviceHeader == NULL) &&
1428 ((transaction = Device_CreateTransaction_ReportedProperties(currentValueDeviceHeader->DeviceHandle)) == NULL))
1429 {
1430 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1431 LOG_CODEFIRST_ERROR;
1432 break;
1433 }
1434 else
1435 {
1436 deviceHeader = currentValueDeviceHeader;
1437 if (value == ((unsigned char*)deviceHeader->data))
1438 {
1439 /*Codes_SRS_CODEFIRST_02_021: [ If the value passed through va_args is a complete model instance, then CodeFirst_SendAsyncReported shall send all the reported properties of that device. ]*/
1440 result = SendAllDeviceReportedProperties(deviceHeader, transaction);
1441 if (result != CODEFIRST_OK)
1442 {
1443 LOG_CODEFIRST_ERROR;
1444 break;
1445 }
1446 }
1447 else
1448 {
1449 /*Codes_SRS_CODEFIRST_02_020: [ If values passed through va_args are not all of type REFLECTED_REPORTED_PROPERTY then CodeFirst_SendAsyncReported shall fail and return CODEFIRST_INVALID_ARG. ]*/
1450 const REFLECTED_SOMETHING* propertyReflectedData;
1451 const char* modelName;
1452
1453 STRING_HANDLE valuePath;
1454 if ((valuePath = STRING_new()) == NULL)
1455 {
1456 result = CODEFIRST_ERROR;
1457 LOG_CODEFIRST_ERROR;
1458 break;
1459 }
1460 else
1461 {
1462 modelName = Schema_GetModelName(deviceHeader->ModelHandle);
1463
1464 /*Codes_SRS_CODEFIRST_02_025: [ CodeFirst_SendAsyncReported shall compute for every AGENT_DATA_TYPE the valuePath. ]*/
1465 if ((propertyReflectedData = FindReportedProperty(deviceHeader, value, modelName, 0, valuePath)) == NULL)
1466 {
1467 result = CODEFIRST_INVALID_ARG;
1468 LOG_CODEFIRST_ERROR;
1469 STRING_delete(valuePath);
1470 break;
1471 }
1472 else
1473 {
1474 AGENT_DATA_TYPE agentDataType;
1475 /*Codes_SRS_CODEFIRST_02_023: [ CodeFirst_SendAsyncReported shall convert all REPORTED_PROPERTY model components to AGENT_DATA_TYPE. ]*/
1476 if (propertyReflectedData->what.reportedProperty.Create_AGENT_DATA_TYPE_from_Ptr(value, &agentDataType) != AGENT_DATA_TYPES_OK)
1477 {
1478 result = CODEFIRST_AGENT_DATA_TYPE_ERROR;
1479 LOG_CODEFIRST_ERROR;
1480 STRING_delete(valuePath);
1481 break;
1482 }
1483 else
1484 {
1485 /*Codes_SRS_CODEFIRST_02_024: [ CodeFirst_SendAsyncReported shall call Device_PublishTransacted_ReportedProperty for every AGENT_DATA_TYPE converted from REPORTED_PROPERTY. ]*/
1486 if (Device_PublishTransacted_ReportedProperty(transaction, STRING_c_str(valuePath), &agentDataType) != DEVICE_OK)
1487 {
1488 Destroy_AGENT_DATA_TYPE(&agentDataType);
1489 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1490 LOG_CODEFIRST_ERROR;
1491 STRING_delete(valuePath);
1492 break;
1493 }
1494 else
1495 {
1496 STRING_delete(valuePath);
1497 }
1498 Destroy_AGENT_DATA_TYPE(&agentDataType);
1499 }
1500 }
1501 }
1502 }
1503 }
1504 }
1505 }
1506
1507 /*Codes_SRS_CODEFIRST_02_027: [ If any error occurs, CodeFirst_SendAsyncReported shall fail and return CODEFIRST_ERROR. ]*/
1508 if (i < numReportedProperties)
1509 {
1510 if (transaction != NULL)
1511 {
1512 Device_DestroyTransaction_ReportedProperties(transaction);
1513 }
1514 }
1515 /*Codes_SRS_CODEFIRST_02_026: [ CodeFirst_SendAsyncReported shall call Device_CommitTransaction_ReportedProperties to commit the transaction. ]*/
1516 else
1517 {
1518 if (Device_CommitTransaction_ReportedProperties(transaction, destination, destinationSize) != DEVICE_OK)
1519 {
1520 result = CODEFIRST_DEVICE_PUBLISH_FAILED;
1521 LOG_CODEFIRST_ERROR;
1522 }
1523 else
1524 {
1525 /*Codes_SRS_CODEFIRST_02_028: [ CodeFirst_SendAsyncReported shall return CODEFIRST_OK when it succeeds. ]*/
1526 result = CODEFIRST_OK;
1527 }
1528
1529 /*Codes_SRS_CODEFIRST_02_029: [ CodeFirst_SendAsyncReported shall call Device_DestroyTransaction_ReportedProperties to destroy the transaction. ]*/
1530 Device_DestroyTransaction_ReportedProperties(transaction);
1531 }
1532
1533 va_end(ap);
1534 }
1535 return result;
1536}
1537
1538EXECUTE_COMMAND_RESULT CodeFirst_ExecuteCommand(void* device, const char* command)
1539{
1540 EXECUTE_COMMAND_RESULT result;
1541 /*Codes_SRS_CODEFIRST_02_014: [If parameter device or command is NULL then CodeFirst_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.] */
1542 if (
1543 (device == NULL) ||
1544 (command == NULL)
1545 )
1546 {
1547 result = EXECUTE_COMMAND_ERROR;
1548 LogError("invalid argument (NULL) passed to CodeFirst_ExecuteCommand void* device = %p, const char* command = %p", device, command);
1549 }
1550 else
1551 {
1552 /*Codes_SRS_CODEFIRST_02_015: [CodeFirst_ExecuteCommand shall find the device.]*/
1553 DEVICE_HEADER_DATA* deviceHeader = FindDevice(device);
1554 if(deviceHeader == NULL)
1555 {
1556 /*Codes_SRS_CODEFIRST_02_016: [If finding the device fails, then CodeFirst_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.]*/
1557 result = EXECUTE_COMMAND_ERROR;
1558 LogError("unable to find the device given by address %p", device);
1559 }
1560 else
1561 {
1562 /*Codes_SRS_CODEFIRST_02_017: [Otherwise CodeFirst_ExecuteCommand shall call Device_ExecuteCommand and return what Device_ExecuteCommand is returning.] */
1563 result = Device_ExecuteCommand(deviceHeader->DeviceHandle, command);
1564 }
1565 }
1566 return result;
1567}
1568
1569METHODRETURN_HANDLE CodeFirst_ExecuteMethod(void* device, const char* methodName, const char* methodPayload)
1570{
1571 METHODRETURN_HANDLE result;
1572 if (
1573 (device == NULL) ||
1574 (methodName== NULL) /*methodPayload can be NULL*/
1575 )
1576 {
1577 result = NULL;
1578 LogError("invalid argument (NULL) passed to CodeFirst_ExecuteMethod void* device = %p, const char* methodName = %p", device, methodName);
1579 }
1580 else
1581 {
1582 DEVICE_HEADER_DATA* deviceHeader = FindDevice(device);
1583 if (deviceHeader == NULL)
1584 {
1585 result = NULL;
1586 LogError("unable to find the device given by address %p", device);
1587 }
1588 else
1589 {
1590 result = Device_ExecuteMethod(deviceHeader->DeviceHandle, methodName, methodPayload);
1591 }
1592 }
1593 return result;
1594}
1595
1596CODEFIRST_RESULT CodeFirst_IngestDesiredProperties(void* device, const char* jsonPayload, bool parseDesiredNode)
1597{
1598 CODEFIRST_RESULT result;
1599 /*Codes_SRS_CODEFIRST_02_030: [ If argument device is NULL then CodeFirst_IngestDesiredProperties shall fail and return CODEFIRST_INVALID_ARG. ]*/
1600 /*Codes_SRS_CODEFIRST_02_031: [ If argument jsonPayload is NULL then CodeFirst_IngestDesiredProperties shall fail and return CODEFIRST_INVALID_ARG. ]*/
1601 if (
1602 (device == NULL) ||
1603 (jsonPayload == NULL)
1604 )
1605 {
1606 LogError("invalid argument void* device=%p, const char* jsonPayload=%p", device, jsonPayload);
1607 result = CODEFIRST_INVALID_ARG;
1608 }
1609 else
1610 {
1611 /*Codes_SRS_CODEFIRST_02_032: [ CodeFirst_IngestDesiredProperties shall locate the device associated with device. ]*/
1612 DEVICE_HEADER_DATA* deviceHeader = FindDevice(device);
1613 if (deviceHeader == NULL)
1614 {
1615 /*Codes_SRS_CODEFIRST_02_034: [ If there is any failure, then CodeFirst_IngestDesiredProperties shall fail and return CODEFIRST_ERROR. ]*/
1616 LogError("unable to find a device having this memory address %p", device);
1617 result = CODEFIRST_ERROR;
1618 }
1619 else
1620 {
1621 /*Codes_SRS_CODEFIRST_02_033: [ CodeFirst_IngestDesiredProperties shall call Device_IngestDesiredProperties. ]*/
1622 if (Device_IngestDesiredProperties(device, deviceHeader->DeviceHandle, jsonPayload, parseDesiredNode) != DEVICE_OK)
1623 {
1624 LogError("failure in Device_IngestDesiredProperties");
1625 result = CODEFIRST_ERROR;
1626 }
1627 else
1628 {
1629 /*Codes_SRS_CODEFIRST_02_035: [ Otherwise, CodeFirst_IngestDesiredProperties shall return CODEFIRST_OK. ]*/
1630 result = CODEFIRST_OK;
1631 }
1632 }
1633 }
1634 return result;
1635}
1636
1637
Note: See TracBrowser for help on using the repository browser.