Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: sht15_remote_monitoring f767zi_mqtt remote_monitoring simplesample_amqp ... more
codefirst.c
00001 // Copyright (c) Microsoft. All rights reserved. 00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 00003 00004 #include <stdlib.h> 00005 #include <stdarg.h> 00006 #include "azure_c_shared_utility/gballoc.h" 00007 00008 #include "codefirst.h" 00009 #include "azure_c_shared_utility/macro_utils.h" 00010 #include "azure_c_shared_utility/crt_abstractions.h" 00011 #include "azure_c_shared_utility/xlogging.h" 00012 #include <stddef.h> 00013 #include "azure_c_shared_utility/crt_abstractions.h" 00014 #include "iotdevice.h" 00015 00016 DEFINE_ENUM_STRINGS(CODEFIRST_RESULT, CODEFIRST_RESULT_VALUES) 00017 DEFINE_ENUM_STRINGS(EXECUTE_COMMAND_RESULT, EXECUTE_COMMAND_RESULT_VALUES) 00018 00019 #define LOG_CODEFIRST_ERROR \ 00020 LogError("(result = %s)", ENUM_TO_STRING(CODEFIRST_RESULT, result)) 00021 00022 typedef struct DEVICE_HEADER_DATA_TAG 00023 { 00024 DEVICE_HANDLE DeviceHandle; 00025 const REFLECTED_DATA_FROM_DATAPROVIDER* ReflectedData; 00026 SCHEMA_MODEL_TYPE_HANDLE ModelHandle; 00027 size_t DataSize; 00028 unsigned char* data; 00029 } DEVICE_HEADER_DATA; 00030 00031 #define COUNT_OF(A) (sizeof(A) / sizeof((A)[0])) 00032 00033 /*design considerations for lazy init of CodeFirst: 00034 There are 2 main states: either CodeFirst is in an initialized state, or it is not initialized. 00035 The initialized state means there's a g_OverrideSchemaNamespace set (even when it is set to NULL). 00036 The uninitialized state means g_OverrideSchemaNamespace is not set. 00037 00038 To switch to Init state, either call CodeFirst_Init (that sets g_OverrideSchemaNamespace to something) 00039 or call directly an API (that will set automatically g_OverrideSchemaNamespace to NULL). 00040 00041 To switch to NOT INIT state, depending on the method used to initialize: 00042 - if CodeFirst_Init was called, then only by a call to CodeFirst_Deinit the switch will take place 00043 (note how in this case g_OverrideSchemaNamespace survives destruction of all devices). 00044 - if the init has been done "lazily" by an API call then the module returns to uninitialized state 00045 when the number of devices reaches zero. 00046 00047 +-----------------------------+ 00048 Start +---------------->| | 00049 | NOT INIT | 00050 +---------------->| | 00051 | +------------+----------------+ 00052 | | 00053 | | 00054 | | _Init | APIs 00055 | | 00056 | v 00057 | +---------------------------------------------------+ 00058 | | Init State | 00059 | | +-----------------+ +-----------------+ | 00060 | | | | | | | 00061 | | | init by _Init | | init by API | | 00062 | | +------+----------+ +---------+-------+ | 00063 | | | | | 00064 | | |_DeInit | nDevices==0 | 00065 | | | | | 00066 | +--------v----------------+-----------v-------------+ 00067 | | 00068 +-------------------------------+ 00069 00070 */ 00071 00072 00073 #define CODEFIRST_STATE_VALUES \ 00074 CODEFIRST_STATE_NOT_INIT, \ 00075 CODEFIRST_STATE_INIT_BY_INIT, \ 00076 CODEFIRST_STATE_INIT_BY_API 00077 00078 DEFINE_ENUM(CODEFIRST_STATE, CODEFIRST_STATE_VALUES) 00079 00080 static CODEFIRST_STATE g_state = CODEFIRST_STATE_NOT_INIT; 00081 static const char* g_OverrideSchemaNamespace; 00082 static size_t g_DeviceCount = 0; 00083 static DEVICE_HEADER_DATA** g_Devices = NULL; 00084 00085 static void deinitializeDesiredProperties(SCHEMA_MODEL_TYPE_HANDLE model, void* destination) 00086 { 00087 size_t nDesiredProperties; 00088 if (Schema_GetModelDesiredPropertyCount(model, &nDesiredProperties) != SCHEMA_OK) 00089 { 00090 LogError("unexpected error in Schema_GetModelDesiredPropertyCount"); 00091 } 00092 else 00093 { 00094 size_t nProcessedDesiredProperties = 0; 00095 for (size_t i = 0;i < nDesiredProperties;i++) 00096 { 00097 SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle = Schema_GetModelDesiredPropertyByIndex(model, i); 00098 if (desiredPropertyHandle == NULL) 00099 { 00100 LogError("unexpected error in Schema_GetModelDesiredPropertyByIndex"); 00101 i = nDesiredProperties; 00102 } 00103 else 00104 { 00105 pfDesiredPropertyDeinitialize desiredPropertyDeinitialize = Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize(desiredPropertyHandle); 00106 if (desiredPropertyDeinitialize == NULL) 00107 { 00108 LogError("unexpected error in Schema_GetModelDesiredProperty_pfDesiredPropertyDeinitialize"); 00109 i = nDesiredProperties; 00110 } 00111 else 00112 { 00113 size_t offset = Schema_GetModelDesiredProperty_offset(desiredPropertyHandle); 00114 desiredPropertyDeinitialize((char*)destination + offset); 00115 nProcessedDesiredProperties++; 00116 } 00117 } 00118 } 00119 00120 if (nDesiredProperties == nProcessedDesiredProperties) 00121 { 00122 /*recursively go in the model and initialize the other fields*/ 00123 size_t nModelInModel; 00124 if (Schema_GetModelModelCount(model, &nModelInModel) != SCHEMA_OK) 00125 { 00126 LogError("unexpected error in Schema_GetModelModelCount"); 00127 } 00128 else 00129 { 00130 size_t nProcessedModelInModel = 0; 00131 for (size_t i = 0; i < nModelInModel;i++) 00132 { 00133 SCHEMA_MODEL_TYPE_HANDLE modelInModel = Schema_GetModelModelyByIndex(model, i); 00134 if (modelInModel == NULL) 00135 { 00136 LogError("unexpected failure in Schema_GetModelModelyByIndex"); 00137 i = nModelInModel; 00138 } 00139 else 00140 { 00141 size_t offset = Schema_GetModelModelByIndex_Offset(model, i); 00142 deinitializeDesiredProperties(modelInModel, (char*)destination + offset); 00143 nProcessedModelInModel++; 00144 } 00145 } 00146 00147 if (nProcessedModelInModel == nModelInModel) 00148 { 00149 /*all is fine... */ 00150 } 00151 } 00152 } 00153 } 00154 } 00155 00156 static void DestroyDevice(DEVICE_HEADER_DATA* deviceHeader) 00157 { 00158 /* Codes_SRS_CODEFIRST_99_085:[CodeFirst_DestroyDevice shall free all resources associated with a device.] */ 00159 /* Codes_SRS_CODEFIRST_99_087:[In order to release the device handle, CodeFirst_DestroyDevice shall call Device_Destroy.] */ 00160 00161 Device_Destroy(deviceHeader->DeviceHandle); 00162 free(deviceHeader->data); 00163 free(deviceHeader); 00164 } 00165 00166 static CODEFIRST_RESULT buildStructTypes(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData) 00167 { 00168 CODEFIRST_RESULT result = CODEFIRST_OK; 00169 00170 const REFLECTED_SOMETHING* something; 00171 for (something = reflectedData->reflectedData; something != NULL; something = something->next) 00172 { 00173 if (something->type == REFLECTION_STRUCT_TYPE) 00174 { 00175 SCHEMA_STRUCT_TYPE_HANDLE structTypeHandle; 00176 structTypeHandle = Schema_CreateStructType(schemaHandle, something->what.structure.name); 00177 00178 if (structTypeHandle == NULL) 00179 { 00180 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00181 result = CODEFIRST_SCHEMA_ERROR; 00182 LogError("create struct failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00183 break; 00184 } 00185 else 00186 { 00187 const REFLECTED_SOMETHING* maybeField; 00188 /*look for the field... */ 00189 for (maybeField = reflectedData->reflectedData; maybeField != NULL; maybeField = maybeField->next) 00190 { 00191 if (maybeField->type == REFLECTION_FIELD_TYPE) 00192 { 00193 if (strcmp(maybeField->what.field.structName, something->what.structure.name) == 0) 00194 { 00195 if (Schema_AddStructTypeProperty(structTypeHandle, maybeField->what.field.fieldName, maybeField->what.field.fieldType) != SCHEMA_OK) 00196 { 00197 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00198 result = CODEFIRST_SCHEMA_ERROR; 00199 LogError("add struct property failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00200 break; 00201 } 00202 } 00203 } 00204 } 00205 } 00206 } 00207 } 00208 00209 return result; 00210 } 00211 00212 static CODEFIRST_RESULT buildModel(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData, const REFLECTED_SOMETHING* modelReflectedData) 00213 { 00214 CODEFIRST_RESULT result = CODEFIRST_OK; 00215 const REFLECTED_SOMETHING* something; 00216 SCHEMA_MODEL_TYPE_HANDLE modelTypeHandle; 00217 00218 modelTypeHandle = Schema_GetModelByName(schemaHandle, modelReflectedData->what.model.name); 00219 if (modelTypeHandle == NULL) 00220 { 00221 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00222 result = CODEFIRST_SCHEMA_ERROR; 00223 LogError("cannot get model %s %s", modelReflectedData->what.model.name, ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00224 goto out; 00225 } 00226 00227 for (something = reflectedData->reflectedData; something != NULL; something = something->next) 00228 { 00229 /* looking for all elements that belong to a model: properties and actions */ 00230 if ((something->type == REFLECTION_PROPERTY_TYPE) && 00231 (strcmp(something->what.property.modelName, modelReflectedData->what.model.name) == 0)) 00232 { 00233 SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.property.type); 00234 00235 /* if this is a model type use the appropriate APIs for it */ 00236 if (childModelHande != NULL) 00237 { 00238 if (Schema_AddModelModel(modelTypeHandle, something->what.property.name, childModelHande, something->what.property.offset, NULL) != SCHEMA_OK) 00239 { 00240 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00241 result = CODEFIRST_SCHEMA_ERROR; 00242 LogError("add model failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00243 goto out; 00244 } 00245 } 00246 else 00247 { 00248 if (Schema_AddModelProperty(modelTypeHandle, something->what.property.name, something->what.property.type) != SCHEMA_OK) 00249 { 00250 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00251 result = CODEFIRST_SCHEMA_ERROR; 00252 LogError("add property failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00253 goto out; 00254 } 00255 } 00256 } 00257 00258 if ((something->type == REFLECTION_REPORTED_PROPERTY_TYPE) && 00259 (strcmp(something->what.reportedProperty.modelName, modelReflectedData->what.model.name) == 0)) 00260 { 00261 SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.reportedProperty.type); 00262 00263 /* if this is a model type use the appropriate APIs for it */ 00264 if (childModelHande != NULL) 00265 { 00266 if (Schema_AddModelModel(modelTypeHandle, something->what.reportedProperty.name, childModelHande, something->what.reportedProperty.offset, NULL) != SCHEMA_OK) 00267 { 00268 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00269 result = CODEFIRST_SCHEMA_ERROR; 00270 LogError("add model failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00271 goto out; 00272 } 00273 } 00274 else 00275 { 00276 if (Schema_AddModelReportedProperty(modelTypeHandle, something->what.reportedProperty.name, something->what.reportedProperty.type) != SCHEMA_OK) 00277 { 00278 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00279 result = CODEFIRST_SCHEMA_ERROR; 00280 LogError("add reported property failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00281 goto out; 00282 } 00283 } 00284 } 00285 00286 if ((something->type == REFLECTION_DESIRED_PROPERTY_TYPE) && 00287 (strcmp(something->what.desiredProperty.modelName, modelReflectedData->what.model.name) == 0)) 00288 { 00289 SCHEMA_MODEL_TYPE_HANDLE childModelHande = Schema_GetModelByName(schemaHandle, something->what.desiredProperty.type); 00290 00291 /* if this is a model type use the appropriate APIs for it */ 00292 if (childModelHande != NULL) 00293 { 00294 if (Schema_AddModelModel(modelTypeHandle, something->what.desiredProperty.name, childModelHande, something->what.desiredProperty.offset, something->what.desiredProperty.onDesiredProperty) != SCHEMA_OK) 00295 { 00296 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00297 result = CODEFIRST_SCHEMA_ERROR; 00298 LogError("add model failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00299 goto out; 00300 } 00301 } 00302 else 00303 { 00304 if (Schema_AddModelDesiredProperty(modelTypeHandle, 00305 something->what.desiredProperty.name, 00306 something->what.desiredProperty.type, 00307 something->what.desiredProperty.FromAGENT_DATA_TYPE, 00308 something->what.desiredProperty.desiredPropertInitialize, 00309 something->what.desiredProperty.desiredPropertDeinitialize, 00310 something->what.desiredProperty.offset, 00311 something->what.desiredProperty.onDesiredProperty) != SCHEMA_OK) 00312 { 00313 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00314 result = CODEFIRST_SCHEMA_ERROR; 00315 LogError("add desired property failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00316 goto out; 00317 } 00318 } 00319 } 00320 00321 if ((something->type == REFLECTION_ACTION_TYPE) && 00322 (strcmp(something->what.action.modelName, modelReflectedData->what.model.name) == 0)) 00323 { 00324 SCHEMA_ACTION_HANDLE actionHandle; 00325 size_t i; 00326 00327 if ((actionHandle = Schema_CreateModelAction(modelTypeHandle, something->what.action.name)) == NULL) 00328 { 00329 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00330 result = CODEFIRST_SCHEMA_ERROR; 00331 LogError("add model action failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00332 goto out; 00333 } 00334 00335 for (i = 0; i < something->what.action.nArguments; i++) 00336 { 00337 if (Schema_AddModelActionArgument(actionHandle, something->what.action.arguments[i].name, something->what.action.arguments[i].type) != SCHEMA_OK) 00338 { 00339 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00340 result = CODEFIRST_SCHEMA_ERROR; 00341 LogError("add model action argument failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00342 goto out; 00343 } 00344 } 00345 } 00346 00347 if ((something->type == REFLECTION_METHOD_TYPE) && 00348 (strcmp(something->what.method.modelName, modelReflectedData->what.model.name) == 0)) 00349 { 00350 SCHEMA_METHOD_HANDLE methodHandle; 00351 size_t i; 00352 00353 if ((methodHandle = Schema_CreateModelMethod(modelTypeHandle, something->what.method.name)) == NULL) 00354 { 00355 /*Codes_SRS_CODEFIRST_99_076: [ If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL. ]*/ 00356 result = CODEFIRST_SCHEMA_ERROR; 00357 LogError("add model method failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00358 goto out; 00359 } 00360 00361 for (i = 0; i < something->what.method.nArguments; i++) 00362 { 00363 if (Schema_AddModelMethodArgument(methodHandle, something->what.method.arguments[i].name, something->what.method.arguments[i].type) != SCHEMA_OK) 00364 { 00365 /*Codes_SRS_CODEFIRST_99_076: [ If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL. ]*/ 00366 result = CODEFIRST_SCHEMA_ERROR; 00367 LogError("add model method argument failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00368 goto out; 00369 } 00370 } 00371 } 00372 } 00373 00374 out: 00375 return result; 00376 } 00377 00378 static CODEFIRST_RESULT buildModelTypes(SCHEMA_HANDLE schemaHandle, const REFLECTED_DATA_FROM_DATAPROVIDER* reflectedData) 00379 { 00380 CODEFIRST_RESULT result = CODEFIRST_OK; 00381 const REFLECTED_SOMETHING* something; 00382 00383 /* first have a pass and add all the model types */ 00384 for (something = reflectedData->reflectedData; something != NULL; something = something->next) 00385 { 00386 if (something->type == REFLECTION_MODEL_TYPE) 00387 { 00388 if (Schema_CreateModelType(schemaHandle, something->what.model.name) == NULL) 00389 { 00390 /*Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CODEFIRST_SCHEMA_ERROR shall be returned.]*/ 00391 result = CODEFIRST_SCHEMA_ERROR; 00392 LogError("create model failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00393 goto out; 00394 } 00395 } 00396 } 00397 00398 for (something = reflectedData->reflectedData; something != NULL; something = something->next) 00399 { 00400 if (something->type == REFLECTION_MODEL_TYPE) 00401 { 00402 result = buildModel(schemaHandle, reflectedData, something); 00403 if (result != CODEFIRST_OK) 00404 { 00405 break; 00406 } 00407 } 00408 } 00409 00410 out: 00411 return result; 00412 } 00413 00414 static CODEFIRST_RESULT CodeFirst_Init_impl(const char* overrideSchemaNamespace, bool calledFromCodeFirst_Init) 00415 { 00416 /*shall build the default EntityContainer*/ 00417 CODEFIRST_RESULT result; 00418 00419 if (g_state != CODEFIRST_STATE_NOT_INIT) 00420 { 00421 /*Codes_SRS_CODEFIRST_99_003:[ If the module is already initialized, the initialization shall fail and the return value shall be CODEFIRST_ALREADY_INIT.]*/ 00422 result = CODEFIRST_ALREADY_INIT; 00423 if(calledFromCodeFirst_Init) /*do not log this error when APIs attempt lazy init*/ 00424 { 00425 LogError("CodeFirst was already init %s", ENUM_TO_STRING(CODEFIRST_RESULT, result)); 00426 } 00427 } 00428 else 00429 { 00430 g_DeviceCount = 0; 00431 g_OverrideSchemaNamespace = overrideSchemaNamespace; 00432 g_Devices = NULL; 00433 00434 /*Codes_SRS_CODEFIRST_99_002:[ CodeFirst_Init shall initialize the CodeFirst module. If initialization is successful, it shall return CODEFIRST_OK.]*/ 00435 g_state = calledFromCodeFirst_Init? CODEFIRST_STATE_INIT_BY_INIT: CODEFIRST_STATE_INIT_BY_API; 00436 result = CODEFIRST_OK; 00437 } 00438 return result; 00439 } 00440 00441 /*Codes_SRS_CODEFIRST_99_002:[ CodeFirst_Init shall initialize the CodeFirst module. If initialization is successful, it shall return CODEFIRST_OK.]*/ 00442 CODEFIRST_RESULT CodeFirst_Init(const char* overrideSchemaNamespace) 00443 { 00444 return CodeFirst_Init_impl(overrideSchemaNamespace, true); 00445 } 00446 00447 void CodeFirst_Deinit(void) 00448 { 00449 /*Codes_SRS_CODEFIRST_99_006:[If the module is not previously initialed, CodeFirst_Deinit shall do nothing.]*/ 00450 if (g_state != CODEFIRST_STATE_INIT_BY_INIT) 00451 { 00452 LogError("CodeFirst_Deinit called when CodeFirst was not initialized by CodeFirst_Init"); 00453 } 00454 else 00455 { 00456 size_t i; 00457 00458 /*Codes_SRS_CODEFIRST_99_005:[ CodeFirst_Deinit shall deinitialize the module, freeing all the resources and placing the module in an uninitialized state.]*/ 00459 for (i = 0; i < g_DeviceCount; i++) 00460 { 00461 DestroyDevice(g_Devices[i]); 00462 } 00463 00464 free(g_Devices); 00465 g_Devices = NULL; 00466 g_DeviceCount = 0; 00467 00468 g_state = CODEFIRST_STATE_NOT_INIT; 00469 } 00470 } 00471 00472 static const REFLECTED_SOMETHING* FindModelInCodeFirstMetadata(const REFLECTED_SOMETHING* reflectedData, const char* modelName) 00473 { 00474 const REFLECTED_SOMETHING* result; 00475 00476 for (result = reflectedData; result != NULL; result = result->next) 00477 { 00478 if ((result->type == REFLECTION_MODEL_TYPE) && 00479 (strcmp(result->what.model.name, modelName) == 0)) 00480 { 00481 /* found model type */ 00482 break; 00483 } 00484 } 00485 00486 return result; 00487 } 00488 00489 static const REFLECTED_SOMETHING* FindChildModelInCodeFirstMetadata(const REFLECTED_SOMETHING* reflectedData, const REFLECTED_SOMETHING* startModel, const char* relativePath, size_t* offset) 00490 { 00491 const REFLECTED_SOMETHING* result = startModel; 00492 *offset = 0; 00493 00494 /* Codes_SRS_CODEFIRST_99_139:[If the relativeActionPath is empty then the action shall be looked up in the device model.] */ 00495 while ((*relativePath != 0) && (result != NULL)) 00496 { 00497 /* Codes_SRS_CODEFIRST_99_142:[The relativeActionPath argument shall be in the format "childModel1/childModel2/.../childModelN".] */ 00498 const REFLECTED_SOMETHING* childModelProperty; 00499 size_t propertyNameLength; 00500 const char* slashPos = strchr(relativePath, '/'); 00501 if (slashPos == NULL) 00502 { 00503 slashPos = &relativePath[strlen(relativePath)]; 00504 } 00505 00506 propertyNameLength = slashPos - relativePath; 00507 00508 for (childModelProperty = reflectedData; childModelProperty != NULL; childModelProperty = childModelProperty->next) 00509 { 00510 if ((childModelProperty->type == REFLECTION_PROPERTY_TYPE) && 00511 (strcmp(childModelProperty->what.property.modelName, result->what.model.name) == 0) && 00512 (strncmp(childModelProperty->what.property.name, relativePath, propertyNameLength) == 0) && 00513 (strlen(childModelProperty->what.property.name) == propertyNameLength)) 00514 { 00515 /* property found, now let's find the model */ 00516 /* 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.] */ 00517 *offset += childModelProperty->what.property.offset; 00518 break; 00519 } 00520 } 00521 00522 if (childModelProperty == NULL) 00523 { 00524 /* not found */ 00525 result = NULL; 00526 } 00527 else 00528 { 00529 result = FindModelInCodeFirstMetadata(reflectedData, childModelProperty->what.property.type); 00530 } 00531 00532 relativePath = slashPos; 00533 } 00534 00535 return result; 00536 } 00537 00538 EXECUTE_COMMAND_RESULT CodeFirst_InvokeAction(DEVICE_HANDLE deviceHandle, void* callbackUserContext, const char* relativeActionPath, const char* actionName, size_t parameterCount, const AGENT_DATA_TYPE* parameterValues) 00539 { 00540 EXECUTE_COMMAND_RESULT result; 00541 DEVICE_HEADER_DATA* deviceHeader = (DEVICE_HEADER_DATA*)callbackUserContext; 00542 00543 /*Codes_SRS_CODEFIRST_99_068:[ If the function is called before CodeFirst is initialized then EXECUTE_COMMAND_ERROR shall be returned.] */ 00544 if (g_state == CODEFIRST_STATE_NOT_INIT) 00545 { 00546 result = EXECUTE_COMMAND_ERROR; 00547 LogError("CodeFirst_InvokeAction called before init has an error %s ", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result)); 00548 } 00549 /*Codes_SRS_CODEFIRST_99_066:[ If actionName, relativeActionPath or deviceHandle is NULL then EXECUTE_COMMAND_ERROR shall be returned*/ 00550 else if ((actionName == NULL) || 00551 (deviceHandle == NULL) || 00552 (relativeActionPath == NULL)) 00553 { 00554 result = EXECUTE_COMMAND_ERROR; 00555 LogError("action Name is NULL %s ", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result)); 00556 } 00557 /*Codes_SRS_CODEFIRST_99_067:[ If parameterCount is greater than zero and parameterValues is NULL then EXECUTE_COMMAND_ERROR shall be returned.]*/ 00558 else if ((parameterCount > 0) && (parameterValues == NULL)) 00559 { 00560 result = EXECUTE_COMMAND_ERROR; 00561 LogError("parameterValues error %s ", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result)); 00562 } 00563 else 00564 { 00565 const REFLECTED_SOMETHING* something; 00566 const REFLECTED_SOMETHING* childModel; 00567 const char* modelName; 00568 size_t offset; 00569 00570 modelName = Schema_GetModelName(deviceHeader->ModelHandle); 00571 00572 if (((childModel = FindModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, modelName)) == NULL) || 00573 /* Codes_SRS_CODEFIRST_99_138:[The relativeActionPath argument shall be used by CodeFirst_InvokeAction to find the child model where the action is declared.] */ 00574 ((childModel = FindChildModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, childModel, relativeActionPath, &offset)) == NULL)) 00575 { 00576 /*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.] */ 00577 result = EXECUTE_COMMAND_ERROR; 00578 LogError("action %s was not found %s ", actionName, ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result)); 00579 } 00580 else 00581 { 00582 /* 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.]*/ 00583 /* Codes_SRS_CODEFIRST_99_078:[If such a function is not found then the function shall return EXECUTE_COMMAND_ERROR.]*/ 00584 result = EXECUTE_COMMAND_ERROR; 00585 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next) 00586 { 00587 if ((something->type == REFLECTION_ACTION_TYPE) && 00588 (strcmp(actionName, something->what.action.name) == 0) && 00589 (strcmp(childModel->what.model.name, something->what.action.modelName) == 0)) 00590 { 00591 /*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.]*/ 00592 /*Codes_SRS_CODEFIRST_99_064:[ If the wrapper call succeeds then CODEFIRST_OK shall be returned. ]*/ 00593 /*Codes_SRS_CODEFIRST_99_065:[ For all the other return values CODEFIRST_ACTION_EXECUTION_ERROR shall be returned.]*/ 00594 /* 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.] */ 00595 /*Codes_SRS_CODEFIRST_02_013: [The wrapper's return value shall be returned.]*/ 00596 result = something->what.action.wrapper(deviceHeader->data + offset, parameterCount, parameterValues); 00597 break; 00598 } 00599 } 00600 } 00601 } 00602 00603 if (result == EXECUTE_COMMAND_ERROR) 00604 { 00605 LogError(" %s ", ENUM_TO_STRING(EXECUTE_COMMAND_RESULT, result)); 00606 } 00607 return result; 00608 } 00609 00610 METHODRETURN_HANDLE CodeFirst_InvokeMethod(DEVICE_HANDLE deviceHandle, void* callbackUserContext, const char* relativeMethodPath, const char* methodName, size_t parameterCount, const AGENT_DATA_TYPE* parameterValues) 00611 { 00612 METHODRETURN_HANDLE result; 00613 DEVICE_HEADER_DATA* deviceHeader = (DEVICE_HEADER_DATA*)callbackUserContext; 00614 00615 if (g_state == CODEFIRST_STATE_NOT_INIT) 00616 { 00617 result = NULL; 00618 LogError("CodeFirst_InvokeMethod called before CodeFirst_Init"); 00619 } 00620 else if ((methodName == NULL) || 00621 (deviceHandle == NULL) || 00622 (relativeMethodPath == NULL)) 00623 { 00624 result = NULL; 00625 LogError("invalid args: DEVICE_HANDLE deviceHandle=%p, void* callbackUserContext=%p, const char* relativeMethodPath=%p, const char* methodName=%p, size_t parameterCount=%zu, const AGENT_DATA_TYPE* parameterValues=%p", 00626 deviceHandle, callbackUserContext, relativeMethodPath, methodName, parameterCount, parameterValues); 00627 } 00628 else if ((parameterCount > 0) && (parameterValues == NULL)) 00629 { 00630 result = NULL; 00631 LogError("parameterValues error "); 00632 } 00633 else 00634 { 00635 const REFLECTED_SOMETHING* something; 00636 const REFLECTED_SOMETHING* childModel; 00637 const char* modelName; 00638 size_t offset; 00639 00640 modelName = Schema_GetModelName(deviceHeader->ModelHandle); 00641 00642 if (((childModel = FindModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, modelName)) == NULL) || 00643 ((childModel = FindChildModelInCodeFirstMetadata(deviceHeader->ReflectedData->reflectedData, childModel, relativeMethodPath, &offset)) == NULL)) 00644 { 00645 result = NULL; 00646 LogError("method %s was not found", methodName); 00647 } 00648 else 00649 { 00650 result = NULL; 00651 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next) 00652 { 00653 if ((something->type == REFLECTION_METHOD_TYPE) && 00654 (strcmp(methodName, something->what.method.name) == 0) && 00655 (strcmp(childModel->what.model.name, something->what.method.modelName) == 0)) 00656 { 00657 break; /*found...*/ 00658 } 00659 } 00660 00661 if (something == NULL) 00662 { 00663 LogError("method \"%s\" not found", methodName); 00664 result = NULL; 00665 } 00666 else 00667 { 00668 result = something->what.method.wrapper(deviceHeader->data + offset, parameterCount, parameterValues); 00669 if (result == NULL) 00670 { 00671 LogError("method \"%s\" execution error (returned NULL)", methodName); 00672 } 00673 } 00674 } 00675 } 00676 return result; 00677 } 00678 00679 00680 /* 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.] */ 00681 SCHEMA_HANDLE CodeFirst_RegisterSchema(const char* schemaNamespace, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata) 00682 { 00683 SCHEMA_HANDLE result; 00684 /*Codes_SRS_CODEFIRST_02_048: [ If schemaNamespace is NULL then CodeFirst_RegisterSchema shall fail and return NULL. ]*/ 00685 /*Codes_SRS_CODEFIRST_02_049: [ If metadata is NULL then CodeFirst_RegisterSchema shall fail and return NULL. ]*/ 00686 if ( 00687 (schemaNamespace == NULL) || 00688 (metadata == NULL) 00689 ) 00690 { 00691 LogError("invalid arg const char* schemaNamespace=%p, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata=%p", schemaNamespace, metadata); 00692 result = NULL; 00693 } 00694 else 00695 { 00696 if (g_OverrideSchemaNamespace != NULL) 00697 { 00698 schemaNamespace = g_OverrideSchemaNamespace; 00699 } 00700 00701 /* Codes_SRS_CODEFIRST_99_121:[If the schema has already been registered, CodeFirst_RegisterSchema shall return its handle.] */ 00702 result = Schema_GetSchemaByNamespace(schemaNamespace); 00703 if (result == NULL) 00704 { 00705 if ((result = Schema_Create(schemaNamespace, (void*)metadata)) == NULL) 00706 { 00707 /* Codes_SRS_CODEFIRST_99_076:[If any Schema APIs fail, CodeFirst_RegisterSchema shall return NULL.] */ 00708 result = NULL; 00709 LogError("schema init failed %s", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_SCHEMA_ERROR)); 00710 } 00711 else 00712 { 00713 if ((buildStructTypes(result, metadata) != CODEFIRST_OK) || 00714 (buildModelTypes(result, metadata) != CODEFIRST_OK)) 00715 { 00716 Schema_Destroy(result); 00717 result = NULL; 00718 } 00719 else 00720 { 00721 /* do nothing, everything is OK */ 00722 } 00723 } 00724 } 00725 } 00726 00727 return result; 00728 } 00729 00730 AGENT_DATA_TYPE_TYPE CodeFirst_GetPrimitiveType(const char* typeName) 00731 { 00732 #ifndef NO_FLOATS 00733 if (strcmp(typeName, "double") == 0) 00734 { 00735 return EDM_DOUBLE_TYPE; 00736 } 00737 else if (strcmp(typeName, "float") == 0) 00738 { 00739 return EDM_SINGLE_TYPE; 00740 } 00741 else 00742 #endif 00743 if (strcmp(typeName, "int") == 0) 00744 { 00745 return EDM_INT32_TYPE; 00746 } 00747 else if (strcmp(typeName, "long") == 0) 00748 { 00749 return EDM_INT64_TYPE; 00750 } 00751 else if (strcmp(typeName, "int8_t") == 0) 00752 { 00753 return EDM_SBYTE_TYPE; 00754 } 00755 else if (strcmp(typeName, "uint8_t") == 0) 00756 { 00757 return EDM_BYTE_TYPE; 00758 } 00759 else if (strcmp(typeName, "int16_t") == 0) 00760 { 00761 return EDM_INT16_TYPE; 00762 } 00763 else if (strcmp(typeName, "int32_t") == 0) 00764 { 00765 return EDM_INT32_TYPE; 00766 } 00767 else if (strcmp(typeName, "int64_t") == 0) 00768 { 00769 return EDM_INT64_TYPE; 00770 } 00771 else if ( 00772 (strcmp(typeName, "_Bool") == 0) || 00773 (strcmp(typeName, "bool") == 0) 00774 ) 00775 { 00776 return EDM_BOOLEAN_TYPE; 00777 } 00778 else if (strcmp(typeName, "ascii_char_ptr") == 0) 00779 { 00780 return EDM_STRING_TYPE; 00781 } 00782 else if (strcmp(typeName, "ascii_char_ptr_no_quotes") == 0) 00783 { 00784 return EDM_STRING_NO_QUOTES_TYPE; 00785 } 00786 else if (strcmp(typeName, "EDM_DATE_TIME_OFFSET") == 0) 00787 { 00788 return EDM_DATE_TIME_OFFSET_TYPE; 00789 } 00790 else if (strcmp(typeName, "EDM_GUID") == 0) 00791 { 00792 return EDM_GUID_TYPE; 00793 } 00794 else if (strcmp(typeName, "EDM_BINARY") == 0) 00795 { 00796 return EDM_BINARY_TYPE; 00797 } 00798 else 00799 { 00800 return EDM_NO_TYPE; 00801 } 00802 } 00803 00804 static void initializeDesiredProperties(SCHEMA_MODEL_TYPE_HANDLE model, void* destination) 00805 { 00806 /*this function assumes that at the address given by destination there is an instance of a model*/ 00807 /*some constituents of the model need to be initialized - ascii_char_ptr for example should be set to NULL*/ 00808 00809 size_t nDesiredProperties; 00810 if (Schema_GetModelDesiredPropertyCount(model, &nDesiredProperties) != SCHEMA_OK) 00811 { 00812 LogError("unexpected error in Schema_GetModelDesiredPropertyCount"); 00813 } 00814 else 00815 { 00816 size_t nProcessedDesiredProperties = 0; 00817 for (size_t i = 0;i < nDesiredProperties;i++) 00818 { 00819 SCHEMA_DESIRED_PROPERTY_HANDLE desiredPropertyHandle = Schema_GetModelDesiredPropertyByIndex(model, i); 00820 if (desiredPropertyHandle == NULL) 00821 { 00822 LogError("unexpected error in Schema_GetModelDesiredPropertyByIndex"); 00823 i = nDesiredProperties; 00824 } 00825 else 00826 { 00827 pfDesiredPropertyInitialize desiredPropertyInitialize = Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize(desiredPropertyHandle); 00828 if (desiredPropertyInitialize == NULL) 00829 { 00830 LogError("unexpected error in Schema_GetModelDesiredProperty_pfDesiredPropertyInitialize"); 00831 i = nDesiredProperties; 00832 } 00833 else 00834 { 00835 /*Codes_SRS_CODEFIRST_02_036: [ CodeFirst_CreateDevice shall initialize all the desired properties to their default values. ]*/ 00836 size_t offset = Schema_GetModelDesiredProperty_offset(desiredPropertyHandle); 00837 desiredPropertyInitialize((char*)destination + offset); 00838 nProcessedDesiredProperties++; 00839 } 00840 } 00841 } 00842 00843 if (nDesiredProperties == nProcessedDesiredProperties) 00844 { 00845 /*recursively go in the model and initialize the other fields*/ 00846 size_t nModelInModel; 00847 if (Schema_GetModelModelCount(model, &nModelInModel) != SCHEMA_OK) 00848 { 00849 LogError("unexpected error in Schema_GetModelModelCount"); 00850 } 00851 else 00852 { 00853 size_t nProcessedModelInModel = 0; 00854 for (size_t i = 0; i < nModelInModel;i++) 00855 { 00856 SCHEMA_MODEL_TYPE_HANDLE modelInModel = Schema_GetModelModelyByIndex(model, i); 00857 if (modelInModel == NULL) 00858 { 00859 LogError("unexpected failure in Schema_GetModelModelyByIndex"); 00860 i = nModelInModel; 00861 } 00862 else 00863 { 00864 size_t offset = Schema_GetModelModelByIndex_Offset(model, i); 00865 initializeDesiredProperties(modelInModel, (char*)destination + offset); 00866 nProcessedModelInModel++; 00867 } 00868 } 00869 00870 if (nProcessedModelInModel == nModelInModel) 00871 { 00872 /*all is fine... */ 00873 } 00874 } 00875 } 00876 } 00877 } 00878 00879 /* Codes_SRS_CODEFIRST_99_079:[CodeFirst_CreateDevice shall create a device and allocate a memory block that should hold the device data.] */ 00880 void* CodeFirst_CreateDevice(SCHEMA_MODEL_TYPE_HANDLE model, const REFLECTED_DATA_FROM_DATAPROVIDER* metadata, size_t dataSize, bool includePropertyPath) 00881 { 00882 void* result; 00883 DEVICE_HEADER_DATA* deviceHeader; 00884 00885 /* Codes_SRS_CODEFIRST_99_080:[If CodeFirst_CreateDevice is invoked with a NULL model, it shall return NULL.]*/ 00886 if (model == NULL) 00887 { 00888 result = NULL; 00889 LogError(" %s ", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_INVALID_ARG)); 00890 } 00891 else 00892 { 00893 /*Codes_SRS_CODEFIRST_02_037: [ CodeFirst_CreateDevice shall call CodeFirst_Init, passing NULL for overrideSchemaNamespace. ]*/ 00894 (void)CodeFirst_Init_impl(NULL, false); /*lazy init*/ 00895 00896 if ((deviceHeader = (DEVICE_HEADER_DATA*)malloc(sizeof(DEVICE_HEADER_DATA))) == NULL) 00897 { 00898 /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */ 00899 result = NULL; 00900 LogError(" %s ", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR)); 00901 } 00902 /* Codes_SRS_CODEFIRST_99_081:[CodeFirst_CreateDevice shall use Device_Create to create a device handle.] */ 00903 /* Codes_SRS_CODEFIRST_99_082: [ CodeFirst_CreateDevice shall pass to Device_Create the function CodeFirst_InvokeAction, action callback argument and the CodeFirst_InvokeMethod ] */ 00904 else 00905 { 00906 if ((deviceHeader->data = malloc(dataSize)) == NULL) 00907 { 00908 free(deviceHeader); 00909 deviceHeader = NULL; 00910 result = NULL; 00911 LogError(" %s ", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR)); 00912 } 00913 else 00914 { 00915 DEVICE_HEADER_DATA** newDevices; 00916 00917 initializeDesiredProperties(model, deviceHeader->data); 00918 00919 if (Device_Create(model, CodeFirst_InvokeAction, deviceHeader, CodeFirst_InvokeMethod, deviceHeader, 00920 includePropertyPath, &deviceHeader->DeviceHandle) != DEVICE_OK) 00921 { 00922 free(deviceHeader->data); 00923 free(deviceHeader); 00924 00925 /* Codes_SRS_CODEFIRST_99_084:[If Device_Create fails, CodeFirst_CreateDevice shall return NULL.] */ 00926 result = NULL; 00927 LogError(" %s ", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_DEVICE_FAILED)); 00928 } 00929 else if ((newDevices = (DEVICE_HEADER_DATA**)realloc(g_Devices, sizeof(DEVICE_HEADER_DATA*) * (g_DeviceCount + 1))) == NULL) 00930 { 00931 Device_Destroy(deviceHeader->DeviceHandle); 00932 free(deviceHeader->data); 00933 free(deviceHeader); 00934 00935 /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */ 00936 result = NULL; 00937 LogError(" %s ", ENUM_TO_STRING(CODEFIRST_RESULT, CODEFIRST_ERROR)); 00938 } 00939 else 00940 { 00941 SCHEMA_RESULT schemaResult; 00942 deviceHeader->ReflectedData = metadata; 00943 deviceHeader->DataSize = dataSize; 00944 deviceHeader->ModelHandle = model; 00945 schemaResult = Schema_AddDeviceRef(model); 00946 if (schemaResult != SCHEMA_OK) 00947 { 00948 Device_Destroy(deviceHeader->DeviceHandle); 00949 free(newDevices); 00950 free(deviceHeader->data); 00951 free(deviceHeader); 00952 00953 /* Codes_SRS_CODEFIRST_99_102:[On any other errors, Device_Create shall return NULL.] */ 00954 result = NULL; 00955 } 00956 else 00957 { 00958 g_Devices = newDevices; 00959 g_Devices[g_DeviceCount] = deviceHeader; 00960 g_DeviceCount++; 00961 00962 /* Codes_SRS_CODEFIRST_99_101:[On success, CodeFirst_CreateDevice shall return a non NULL pointer to the device data.] */ 00963 result = deviceHeader->data; 00964 } 00965 } 00966 } 00967 } 00968 00969 } 00970 00971 return result; 00972 } 00973 00974 void CodeFirst_DestroyDevice(void* device) 00975 { 00976 /* Codes_SRS_CODEFIRST_99_086:[If the argument is NULL, CodeFirst_DestroyDevice shall do nothing.] */ 00977 if (device != NULL) 00978 { 00979 size_t i; 00980 00981 for (i = 0; i < g_DeviceCount; i++) 00982 { 00983 if (g_Devices[i]->data == device) 00984 { 00985 deinitializeDesiredProperties(g_Devices[i]->ModelHandle, g_Devices[i]->data); 00986 Schema_ReleaseDeviceRef(g_Devices[i]->ModelHandle); 00987 00988 // Delete the Created Schema if all the devices are unassociated 00989 Schema_DestroyIfUnused(g_Devices[i]->ModelHandle); 00990 00991 DestroyDevice(g_Devices[i]); 00992 (void)memcpy(&g_Devices[i], &g_Devices[i + 1], (g_DeviceCount - i - 1) * sizeof(DEVICE_HEADER_DATA*)); 00993 g_DeviceCount--; 00994 break; 00995 } 00996 } 00997 00998 /*Codes_SRS_CODEFIRST_02_039: [ If the current device count is zero then CodeFirst_DestroyDevice shall deallocate all other used resources. ]*/ 00999 if ((g_state == CODEFIRST_STATE_INIT_BY_API) && (g_DeviceCount == 0)) 01000 { 01001 free(g_Devices); 01002 g_Devices = NULL; 01003 g_state = CODEFIRST_STATE_NOT_INIT; 01004 } 01005 } 01006 } 01007 01008 static DEVICE_HEADER_DATA* FindDevice(void* value) 01009 { 01010 size_t i; 01011 DEVICE_HEADER_DATA* result = NULL; 01012 01013 for (i = 0; i < g_DeviceCount; i++) 01014 { 01015 if ((g_Devices[i]->data <= (unsigned char*)value) && 01016 (g_Devices[i]->data + g_Devices[i]->DataSize > (unsigned char*)value)) 01017 { 01018 result = g_Devices[i]; 01019 break; 01020 } 01021 } 01022 01023 return result; 01024 } 01025 01026 static const REFLECTED_SOMETHING* FindValue(DEVICE_HEADER_DATA* deviceHeader, void* value, const char* modelName, size_t startOffset, STRING_HANDLE valuePath) 01027 { 01028 const REFLECTED_SOMETHING* result; 01029 size_t valueOffset = (size_t)((unsigned char*)value - (unsigned char*)deviceHeader->data) - startOffset; 01030 01031 for (result = deviceHeader->ReflectedData->reflectedData; result != NULL; result = result->next) 01032 { 01033 if (result->type == REFLECTION_PROPERTY_TYPE && 01034 (strcmp(result->what.property.modelName, modelName) == 0) && 01035 (result->what.property.offset <= valueOffset) && 01036 (result->what.property.offset + result->what.property.size > valueOffset)) 01037 { 01038 if (startOffset != 0) 01039 { 01040 STRING_concat(valuePath, "/"); 01041 } 01042 01043 STRING_concat(valuePath, result->what.property.name); 01044 break; 01045 } 01046 } 01047 01048 if (result != NULL) 01049 { 01050 /* Codes_SRS_CODEFIRST_99_133:[CodeFirst_SendAsync shall allow sending of properties that are part of a child model.] */ 01051 if (result->what.property.offset < valueOffset) 01052 { 01053 /* find recursively the property in the inner model, if there is one */ 01054 result = FindValue(deviceHeader, value, result->what.property.type, startOffset + result->what.property.offset, valuePath); 01055 } 01056 } 01057 01058 return result; 01059 } 01060 01061 static const REFLECTED_SOMETHING* FindReportedProperty(DEVICE_HEADER_DATA* deviceHeader, void* value, const char* modelName, size_t startOffset, STRING_HANDLE valuePath) 01062 { 01063 const REFLECTED_SOMETHING* result; 01064 size_t valueOffset = (size_t)((unsigned char*)value - (unsigned char*)deviceHeader->data) - startOffset; 01065 01066 for (result = deviceHeader->ReflectedData->reflectedData; result != NULL; result = result->next) 01067 { 01068 if (result->type == REFLECTION_REPORTED_PROPERTY_TYPE && 01069 (strcmp(result->what.reportedProperty.modelName, modelName) == 0) && 01070 (result->what.reportedProperty.offset <= valueOffset) && 01071 (result->what.reportedProperty.offset + result->what.reportedProperty.size > valueOffset)) 01072 { 01073 if (startOffset != 0) 01074 { 01075 if (STRING_concat(valuePath, "/") != 0) 01076 { 01077 LogError("unable to STRING_concat"); 01078 result = NULL; 01079 break; 01080 } 01081 } 01082 01083 if (STRING_concat(valuePath, result->what.reportedProperty.name) != 0) 01084 { 01085 LogError("unable to STRING_concat"); 01086 result = NULL; 01087 break; 01088 } 01089 break; 01090 } 01091 } 01092 01093 if (result != NULL) 01094 { 01095 /* Codes_SRS_CODEFIRST_99_133:[CodeFirst_SendAsync shall allow sending of properties that are part of a child model.] */ 01096 if (result->what.reportedProperty.offset < valueOffset) 01097 { 01098 /* find recursively the property in the inner model, if there is one */ 01099 result = FindReportedProperty(deviceHeader, value, result->what.reportedProperty.type, startOffset + result->what.reportedProperty.offset, valuePath); 01100 } 01101 } 01102 01103 return result; 01104 } 01105 01106 /* 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.] */ 01107 /* 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.] */ 01108 static CODEFIRST_RESULT SendAllDeviceProperties(DEVICE_HEADER_DATA* deviceHeader, TRANSACTION_HANDLE transaction) 01109 { 01110 const char* modelName = Schema_GetModelName(deviceHeader->ModelHandle); 01111 const REFLECTED_SOMETHING* something; 01112 unsigned char* deviceAddress = (unsigned char*)deviceHeader->data; 01113 CODEFIRST_RESULT result = CODEFIRST_OK; 01114 01115 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next) 01116 { 01117 if ((something->type == REFLECTION_PROPERTY_TYPE) && 01118 (strcmp(something->what.property.modelName, modelName) == 0)) 01119 { 01120 AGENT_DATA_TYPE agentDataType; 01121 01122 /* Codes_SRS_CODEFIRST_99_097:[For each value marshalling to AGENT_DATA_TYPE shall be performed.] */ 01123 /* Codes_SRS_CODEFIRST_99_098:[The marshalling shall be done by calling the Create_AGENT_DATA_TYPE_from_Ptr function associated with the property.] */ 01124 if (something->what.property.Create_AGENT_DATA_TYPE_from_Ptr(deviceAddress + something->what.property.offset, &agentDataType) != AGENT_DATA_TYPES_OK) 01125 { 01126 /* Codes_SRS_CODEFIRST_99_099:[If Create_AGENT_DATA_TYPE_from_Ptr fails, CodeFirst_SendAsync shall return CODEFIRST_AGENT_DATA_TYPE_ERROR.] */ 01127 result = CODEFIRST_AGENT_DATA_TYPE_ERROR; 01128 LOG_CODEFIRST_ERROR; 01129 break; 01130 } 01131 else 01132 { 01133 /* Codes_SRS_CODEFIRST_99_092:[CodeFirst shall publish each value by using Device_PublishTransacted.] */ 01134 if (Device_PublishTransacted(transaction, something->what.property.name, &agentDataType) != DEVICE_OK) 01135 { 01136 Destroy_AGENT_DATA_TYPE(&agentDataType); 01137 01138 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */ 01139 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01140 LOG_CODEFIRST_ERROR; 01141 break; 01142 } 01143 01144 Destroy_AGENT_DATA_TYPE(&agentDataType); 01145 } 01146 } 01147 } 01148 01149 return result; 01150 } 01151 01152 static CODEFIRST_RESULT SendAllDeviceReportedProperties(DEVICE_HEADER_DATA* deviceHeader, REPORTED_PROPERTIES_TRANSACTION_HANDLE transaction) 01153 { 01154 const char* modelName = Schema_GetModelName(deviceHeader->ModelHandle); 01155 const REFLECTED_SOMETHING* something; 01156 unsigned char* deviceAddress = (unsigned char*)deviceHeader->data; 01157 CODEFIRST_RESULT result = CODEFIRST_OK; 01158 01159 for (something = deviceHeader->ReflectedData->reflectedData; something != NULL; something = something->next) 01160 { 01161 if ((something->type == REFLECTION_REPORTED_PROPERTY_TYPE) && 01162 (strcmp(something->what.reportedProperty.modelName, modelName) == 0)) 01163 { 01164 AGENT_DATA_TYPE agentDataType; 01165 01166 if (something->what.reportedProperty.Create_AGENT_DATA_TYPE_from_Ptr(deviceAddress + something->what.reportedProperty.offset, &agentDataType) != AGENT_DATA_TYPES_OK) 01167 { 01168 result = CODEFIRST_AGENT_DATA_TYPE_ERROR; 01169 LOG_CODEFIRST_ERROR; 01170 break; 01171 } 01172 else 01173 { 01174 if (Device_PublishTransacted_ReportedProperty(transaction, something->what.reportedProperty.name, &agentDataType) != DEVICE_OK) 01175 { 01176 Destroy_AGENT_DATA_TYPE(&agentDataType); 01177 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01178 LOG_CODEFIRST_ERROR; 01179 break; 01180 } 01181 01182 Destroy_AGENT_DATA_TYPE(&agentDataType); 01183 } 01184 } 01185 } 01186 01187 return result; 01188 } 01189 01190 01191 /* Codes_SRS_CODEFIRST_99_088:[CodeFirst_SendAsync shall send to the Device module a set of properties, a destination and a destinationSize.]*/ 01192 CODEFIRST_RESULT CodeFirst_SendAsync(unsigned char** destination, size_t* destinationSize, size_t numProperties, ...) 01193 { 01194 CODEFIRST_RESULT result; 01195 va_list ap; 01196 01197 if ( 01198 (numProperties == 0) || 01199 (destination == NULL) || 01200 (destinationSize == NULL) 01201 ) 01202 { 01203 /* Codes_SRS_CODEFIRST_04_002: [If CodeFirst_SendAsync receives destination or destinationSize NULL, CodeFirst_SendAsync shall return Invalid Argument.]*/ 01204 /* Codes_SRS_CODEFIRST_99_103:[If CodeFirst_SendAsync is called with numProperties being zero, CODEFIRST_INVALID_ARG shall be returned.] */ 01205 result = CODEFIRST_INVALID_ARG; 01206 LOG_CODEFIRST_ERROR; 01207 } 01208 else 01209 { 01210 /*Codes_SRS_CODEFIRST_02_040: [ CodeFirst_SendAsync shall call CodeFirst_Init, passing NULL for overrideSchemaNamespace. ]*/ 01211 (void)CodeFirst_Init_impl(NULL, false); /*lazy init*/ 01212 01213 DEVICE_HEADER_DATA* deviceHeader = NULL; 01214 size_t i; 01215 TRANSACTION_HANDLE transaction = NULL; 01216 result = CODEFIRST_OK; 01217 01218 /* 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.] */ 01219 va_start(ap, numProperties); 01220 01221 /* Codes_SRS_CODEFIRST_99_089:[The numProperties argument shall indicate how many properties are to be sent.] */ 01222 for (i = 0; i < numProperties; i++) 01223 { 01224 void* value = (void*)va_arg(ap, void*); 01225 01226 /* Codes_SRS_CODEFIRST_99_095:[For each value passed to it, CodeFirst_SendAsync shall look up to which device the value belongs.] */ 01227 DEVICE_HEADER_DATA* currentValueDeviceHeader = FindDevice(value); 01228 if (currentValueDeviceHeader == NULL) 01229 { 01230 /* Codes_SRS_CODEFIRST_99_104:[If a property cannot be associated with a device, CodeFirst_SendAsync shall return CODEFIRST_INVALID_ARG.] */ 01231 result = CODEFIRST_INVALID_ARG; 01232 LOG_CODEFIRST_ERROR; 01233 break; 01234 } 01235 else if ((deviceHeader != NULL) && 01236 (currentValueDeviceHeader != deviceHeader)) 01237 { 01238 /* 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.] */ 01239 result = CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR; 01240 LOG_CODEFIRST_ERROR; 01241 break; 01242 } 01243 /* Codes_SRS_CODEFIRST_99_090:[All the properties shall be sent together by using the transacted APIs of the device.] */ 01244 /* Codes_SRS_CODEFIRST_99_091:[CodeFirst_SendAsync shall start a transaction by calling Device_StartTransaction.] */ 01245 else if ((deviceHeader == NULL) && 01246 ((transaction = Device_StartTransaction(currentValueDeviceHeader->DeviceHandle)) == NULL)) 01247 { 01248 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */ 01249 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01250 LOG_CODEFIRST_ERROR; 01251 break; 01252 } 01253 else 01254 { 01255 deviceHeader = currentValueDeviceHeader; 01256 01257 if (value == ((unsigned char*)deviceHeader->data)) 01258 { 01259 /* we got a full device, send all its state data */ 01260 result = SendAllDeviceProperties(deviceHeader, transaction); 01261 if (result != CODEFIRST_OK) 01262 { 01263 LOG_CODEFIRST_ERROR; 01264 break; 01265 } 01266 } 01267 else 01268 { 01269 const REFLECTED_SOMETHING* propertyReflectedData; 01270 const char* modelName; 01271 STRING_HANDLE valuePath; 01272 01273 if ((valuePath = STRING_new()) == NULL) 01274 { 01275 /* Codes_SRS_CODEFIRST_99_134:[If CodeFirst_Notify fails for any other reason it shall return CODEFIRST_ERROR.] */ 01276 result = CODEFIRST_ERROR; 01277 LOG_CODEFIRST_ERROR; 01278 break; 01279 } 01280 else 01281 { 01282 if ((modelName = Schema_GetModelName(deviceHeader->ModelHandle)) == NULL) 01283 { 01284 /* Codes_SRS_CODEFIRST_99_134:[If CodeFirst_Notify fails for any other reason it shall return CODEFIRST_ERROR.] */ 01285 result = CODEFIRST_ERROR; 01286 LOG_CODEFIRST_ERROR; 01287 STRING_delete(valuePath); 01288 break; 01289 } 01290 else if ((propertyReflectedData = FindValue(deviceHeader, value, modelName, 0, valuePath)) == NULL) 01291 { 01292 /* Codes_SRS_CODEFIRST_99_104:[If a property cannot be associated with a device, CodeFirst_SendAsync shall return CODEFIRST_INVALID_ARG.] */ 01293 result = CODEFIRST_INVALID_ARG; 01294 LOG_CODEFIRST_ERROR; 01295 STRING_delete(valuePath); 01296 break; 01297 } 01298 else 01299 { 01300 AGENT_DATA_TYPE agentDataType; 01301 01302 /* Codes_SRS_CODEFIRST_99_097:[For each value marshalling to AGENT_DATA_TYPE shall be performed.] */ 01303 /* Codes_SRS_CODEFIRST_99_098:[The marshalling shall be done by calling the Create_AGENT_DATA_TYPE_from_Ptr function associated with the property.] */ 01304 if (propertyReflectedData->what.property.Create_AGENT_DATA_TYPE_from_Ptr(value, &agentDataType) != AGENT_DATA_TYPES_OK) 01305 { 01306 /* Codes_SRS_CODEFIRST_99_099:[If Create_AGENT_DATA_TYPE_from_Ptr fails, CodeFirst_SendAsync shall return CODEFIRST_AGENT_DATA_TYPE_ERROR.] */ 01307 result = CODEFIRST_AGENT_DATA_TYPE_ERROR; 01308 LOG_CODEFIRST_ERROR; 01309 STRING_delete(valuePath); 01310 break; 01311 } 01312 else 01313 { 01314 /* Codes_SRS_CODEFIRST_99_092:[CodeFirst shall publish each value by using Device_PublishTransacted.] */ 01315 /* Codes_SRS_CODEFIRST_99_136:[CodeFirst_SendAsync shall build the full path for each property and then pass it to Device_PublishTransacted.] */ 01316 if (Device_PublishTransacted(transaction, STRING_c_str(valuePath), &agentDataType) != DEVICE_OK) 01317 { 01318 Destroy_AGENT_DATA_TYPE(&agentDataType); 01319 01320 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */ 01321 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01322 LOG_CODEFIRST_ERROR; 01323 STRING_delete(valuePath); 01324 break; 01325 } 01326 else 01327 { 01328 STRING_delete(valuePath); /*anyway*/ 01329 } 01330 01331 Destroy_AGENT_DATA_TYPE(&agentDataType); 01332 } 01333 } 01334 } 01335 } 01336 } 01337 } 01338 01339 if (i < numProperties) 01340 { 01341 if (transaction != NULL) 01342 { 01343 (void)Device_CancelTransaction(transaction); 01344 } 01345 } 01346 /* Codes_SRS_CODEFIRST_99_093:[After all values have been published, Device_EndTransaction shall be called.] */ 01347 else if (Device_EndTransaction(transaction, destination, destinationSize) != DEVICE_OK) 01348 { 01349 /* Codes_SRS_CODEFIRST_99_094:[If any Device API fail, CodeFirst_SendAsync shall return CODEFIRST_DEVICE_PUBLISH_FAILED.] */ 01350 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01351 LOG_CODEFIRST_ERROR; 01352 } 01353 else 01354 { 01355 /* Codes_SRS_CODEFIRST_99_117:[On success, CodeFirst_SendAsync shall return CODEFIRST_OK.] */ 01356 result = CODEFIRST_OK; 01357 } 01358 01359 va_end(ap); 01360 01361 } 01362 01363 return result; 01364 } 01365 01366 CODEFIRST_RESULT CodeFirst_SendAsyncReported(unsigned char** destination, size_t* destinationSize, size_t numReportedProperties, ...) 01367 { 01368 CODEFIRST_RESULT result; 01369 if ((destination == NULL) || (destinationSize == NULL) || numReportedProperties == 0) 01370 { 01371 /*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. ]*/ 01372 LogError("invalid argument unsigned char** destination=%p, size_t* destinationSize=%p, size_t numReportedProperties=%zu", destination, destinationSize, numReportedProperties); 01373 result = CODEFIRST_INVALID_ARG; 01374 } 01375 else 01376 { 01377 /*Codes_SRS_CODEFIRST_02_046: [ CodeFirst_SendAsyncReported shall call CodeFirst_Init, passing NULL for overrideSchemaNamespace. ]*/ 01378 (void)CodeFirst_Init_impl(NULL, false);/*lazy init*/ 01379 01380 DEVICE_HEADER_DATA* deviceHeader = NULL; 01381 size_t i; 01382 REPORTED_PROPERTIES_TRANSACTION_HANDLE transaction = NULL; 01383 va_list ap; 01384 result = CODEFIRST_ACTION_EXECUTION_ERROR; /*this initialization squelches a false warning about result not being initialized*/ 01385 01386 va_start(ap, numReportedProperties); 01387 01388 for (i = 0; i < numReportedProperties; i++) 01389 { 01390 void* value = (void*)va_arg(ap, void*); 01391 /*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. ]*/ 01392 if (value == NULL) 01393 { 01394 LogError("argument number %zu passed through variable arguments is NULL", i); 01395 result = CODEFIRST_INVALID_ARG; 01396 break; 01397 } 01398 else 01399 { 01400 DEVICE_HEADER_DATA* currentValueDeviceHeader = FindDevice(value); 01401 if (currentValueDeviceHeader == NULL) 01402 { 01403 result = CODEFIRST_INVALID_ARG; 01404 LOG_CODEFIRST_ERROR; 01405 break; 01406 } 01407 /*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. ]*/ 01408 else if ((deviceHeader != NULL) && 01409 (currentValueDeviceHeader != deviceHeader)) 01410 { 01411 result = CODEFIRST_VALUES_FROM_DIFFERENT_DEVICES_ERROR; 01412 LOG_CODEFIRST_ERROR; 01413 break; 01414 } 01415 /*Codes_SRS_CODEFIRST_02_022: [ CodeFirst_SendAsyncReported shall start a transaction by calling Device_CreateTransaction_ReportedProperties. ]*/ 01416 else if ((deviceHeader == NULL) && 01417 ((transaction = Device_CreateTransaction_ReportedProperties(currentValueDeviceHeader->DeviceHandle)) == NULL)) 01418 { 01419 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01420 LOG_CODEFIRST_ERROR; 01421 break; 01422 } 01423 else 01424 { 01425 deviceHeader = currentValueDeviceHeader; 01426 if (value == ((unsigned char*)deviceHeader->data)) 01427 { 01428 /*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. ]*/ 01429 result = SendAllDeviceReportedProperties(deviceHeader, transaction); 01430 if (result != CODEFIRST_OK) 01431 { 01432 LOG_CODEFIRST_ERROR; 01433 break; 01434 } 01435 } 01436 else 01437 { 01438 /*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. ]*/ 01439 const REFLECTED_SOMETHING* propertyReflectedData; 01440 const char* modelName; 01441 01442 STRING_HANDLE valuePath; 01443 if ((valuePath = STRING_new()) == NULL) 01444 { 01445 result = CODEFIRST_ERROR; 01446 LOG_CODEFIRST_ERROR; 01447 break; 01448 } 01449 else 01450 { 01451 modelName = Schema_GetModelName(deviceHeader->ModelHandle); 01452 01453 /*Codes_SRS_CODEFIRST_02_025: [ CodeFirst_SendAsyncReported shall compute for every AGENT_DATA_TYPE the valuePath. ]*/ 01454 if ((propertyReflectedData = FindReportedProperty(deviceHeader, value, modelName, 0, valuePath)) == NULL) 01455 { 01456 result = CODEFIRST_INVALID_ARG; 01457 LOG_CODEFIRST_ERROR; 01458 STRING_delete(valuePath); 01459 break; 01460 } 01461 else 01462 { 01463 AGENT_DATA_TYPE agentDataType; 01464 /*Codes_SRS_CODEFIRST_02_023: [ CodeFirst_SendAsyncReported shall convert all REPORTED_PROPERTY model components to AGENT_DATA_TYPE. ]*/ 01465 if (propertyReflectedData->what.reportedProperty.Create_AGENT_DATA_TYPE_from_Ptr(value, &agentDataType) != AGENT_DATA_TYPES_OK) 01466 { 01467 result = CODEFIRST_AGENT_DATA_TYPE_ERROR; 01468 LOG_CODEFIRST_ERROR; 01469 STRING_delete(valuePath); 01470 break; 01471 } 01472 else 01473 { 01474 /*Codes_SRS_CODEFIRST_02_024: [ CodeFirst_SendAsyncReported shall call Device_PublishTransacted_ReportedProperty for every AGENT_DATA_TYPE converted from REPORTED_PROPERTY. ]*/ 01475 if (Device_PublishTransacted_ReportedProperty(transaction, STRING_c_str(valuePath), &agentDataType) != DEVICE_OK) 01476 { 01477 Destroy_AGENT_DATA_TYPE(&agentDataType); 01478 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01479 LOG_CODEFIRST_ERROR; 01480 STRING_delete(valuePath); 01481 break; 01482 } 01483 else 01484 { 01485 STRING_delete(valuePath); 01486 } 01487 Destroy_AGENT_DATA_TYPE(&agentDataType); 01488 } 01489 } 01490 } 01491 } 01492 } 01493 } 01494 } 01495 01496 /*Codes_SRS_CODEFIRST_02_027: [ If any error occurs, CodeFirst_SendAsyncReported shall fail and return CODEFIRST_ERROR. ]*/ 01497 if (i < numReportedProperties) 01498 { 01499 if (transaction != NULL) 01500 { 01501 Device_DestroyTransaction_ReportedProperties(transaction); 01502 } 01503 } 01504 /*Codes_SRS_CODEFIRST_02_026: [ CodeFirst_SendAsyncReported shall call Device_CommitTransaction_ReportedProperties to commit the transaction. ]*/ 01505 else 01506 { 01507 if (Device_CommitTransaction_ReportedProperties(transaction, destination, destinationSize) != DEVICE_OK) 01508 { 01509 result = CODEFIRST_DEVICE_PUBLISH_FAILED; 01510 LOG_CODEFIRST_ERROR; 01511 } 01512 else 01513 { 01514 /*Codes_SRS_CODEFIRST_02_028: [ CodeFirst_SendAsyncReported shall return CODEFIRST_OK when it succeeds. ]*/ 01515 result = CODEFIRST_OK; 01516 } 01517 01518 /*Codes_SRS_CODEFIRST_02_029: [ CodeFirst_SendAsyncReported shall call Device_DestroyTransaction_ReportedProperties to destroy the transaction. ]*/ 01519 Device_DestroyTransaction_ReportedProperties(transaction); 01520 } 01521 01522 va_end(ap); 01523 } 01524 return result; 01525 } 01526 01527 EXECUTE_COMMAND_RESULT CodeFirst_ExecuteCommand(void* device, const char* command) 01528 { 01529 EXECUTE_COMMAND_RESULT result; 01530 /*Codes_SRS_CODEFIRST_02_014: [If parameter device or command is NULL then CodeFirst_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.] */ 01531 if ( 01532 (device == NULL) || 01533 (command == NULL) 01534 ) 01535 { 01536 result = EXECUTE_COMMAND_ERROR; 01537 LogError("invalid argument (NULL) passed to CodeFirst_ExecuteCommand void* device = %p, const char* command = %p", device, command); 01538 } 01539 else 01540 { 01541 /*Codes_SRS_CODEFIRST_02_015: [CodeFirst_ExecuteCommand shall find the device.]*/ 01542 DEVICE_HEADER_DATA* deviceHeader = FindDevice(device); 01543 if(deviceHeader == NULL) 01544 { 01545 /*Codes_SRS_CODEFIRST_02_016: [If finding the device fails, then CodeFirst_ExecuteCommand shall return EXECUTE_COMMAND_ERROR.]*/ 01546 result = EXECUTE_COMMAND_ERROR; 01547 LogError("unable to find the device given by address %p", device); 01548 } 01549 else 01550 { 01551 /*Codes_SRS_CODEFIRST_02_017: [Otherwise CodeFirst_ExecuteCommand shall call Device_ExecuteCommand and return what Device_ExecuteCommand is returning.] */ 01552 result = Device_ExecuteCommand(deviceHeader->DeviceHandle, command); 01553 } 01554 } 01555 return result; 01556 } 01557 01558 METHODRETURN_HANDLE CodeFirst_ExecuteMethod(void* device, const char* methodName, const char* methodPayload) 01559 { 01560 METHODRETURN_HANDLE result; 01561 if ( 01562 (device == NULL) || 01563 (methodName== NULL) /*methodPayload can be NULL*/ 01564 ) 01565 { 01566 result = NULL; 01567 LogError("invalid argument (NULL) passed to CodeFirst_ExecuteMethod void* device = %p, const char* methodName = %p", device, methodName); 01568 } 01569 else 01570 { 01571 DEVICE_HEADER_DATA* deviceHeader = FindDevice(device); 01572 if (deviceHeader == NULL) 01573 { 01574 result = NULL; 01575 LogError("unable to find the device given by address %p", device); 01576 } 01577 else 01578 { 01579 result = Device_ExecuteMethod(deviceHeader->DeviceHandle, methodName, methodPayload); 01580 } 01581 } 01582 return result; 01583 } 01584 01585 CODEFIRST_RESULT CodeFirst_IngestDesiredProperties(void* device, const char* jsonPayload, bool parseDesiredNode) 01586 { 01587 CODEFIRST_RESULT result; 01588 /*Codes_SRS_CODEFIRST_02_030: [ If argument device is NULL then CodeFirst_IngestDesiredProperties shall fail and return CODEFIRST_INVALID_ARG. ]*/ 01589 /*Codes_SRS_CODEFIRST_02_031: [ If argument jsonPayload is NULL then CodeFirst_IngestDesiredProperties shall fail and return CODEFIRST_INVALID_ARG. ]*/ 01590 if ( 01591 (device == NULL) || 01592 (jsonPayload == NULL) 01593 ) 01594 { 01595 LogError("invalid argument void* device=%p, const char* jsonPayload=%p", device, jsonPayload); 01596 result = CODEFIRST_INVALID_ARG; 01597 } 01598 else 01599 { 01600 /*Codes_SRS_CODEFIRST_02_032: [ CodeFirst_IngestDesiredProperties shall locate the device associated with device. ]*/ 01601 DEVICE_HEADER_DATA* deviceHeader = FindDevice(device); 01602 if (deviceHeader == NULL) 01603 { 01604 /*Codes_SRS_CODEFIRST_02_034: [ If there is any failure, then CodeFirst_IngestDesiredProperties shall fail and return CODEFIRST_ERROR. ]*/ 01605 LogError("unable to find a device having this memory address %p", device); 01606 result = CODEFIRST_ERROR; 01607 } 01608 else 01609 { 01610 /*Codes_SRS_CODEFIRST_02_033: [ CodeFirst_IngestDesiredProperties shall call Device_IngestDesiredProperties. ]*/ 01611 if (Device_IngestDesiredProperties(device, deviceHeader->DeviceHandle, jsonPayload, parseDesiredNode) != DEVICE_OK) 01612 { 01613 LogError("failure in Device_IngestDesiredProperties"); 01614 result = CODEFIRST_ERROR; 01615 } 01616 else 01617 { 01618 /*Codes_SRS_CODEFIRST_02_035: [ Otherwise, CodeFirst_IngestDesiredProperties shall return CODEFIRST_OK. ]*/ 01619 result = CODEFIRST_OK; 01620 } 01621 } 01622 } 01623 return result; 01624 } 01625 01626
Generated on Tue Jul 12 2022 19:56:37 by
1.7.2