source/include/azure_iot_adu_client.h (188 lines of code) (raw):

/* Copyright (c) Microsoft Corporation. * Licensed under the MIT License. */ /** * @file azure_iot_adu_client.h * * @brief Definition for the Azure IoT ADU Client. * * @warning Below is a limitation of features compared to ADU service capabilities: * - Proxy updates are not supported: https://learn.microsoft.com/azure/iot-hub-device-update/device-update-proxy-updates * - Delta updates are not supported: https://learn.microsoft.com/azure/iot-hub-device-update/understand-device-update#flexible-features-for-updating-devices * */ #ifndef AZURE_IOT_ADU_CLIENT_H #define AZURE_IOT_ADU_CLIENT_H #include <stdint.h> #include "azure_iot_result.h" #include "azure_iot_hub_client.h" #include "azure_iot_json_reader.h" #include <azure/iot/az_iot_adu_client.h> /** * @brief The DTMI specifying the capabilities for the Azure Device Update client. * * This may be used in the #AzureIoTHubClientOptions_t as the `pucModelID`. */ extern const uint8_t * AzureIoTADUModelID; /** * @brief The length of #AzureIoTADUModelID */ extern const uint32_t AzureIoTADUModelIDLength; /** * @brief Holds any user-defined custom properties of the device. * @remark Implementer can define other device properties to be used * for the compatibility check while targeting the update deployment. */ typedef struct AzureIoTADUDeviceCustomProperties { uint8_t * pucPropertyNames[ _az_IOT_ADU_CLIENT_MAX_DEVICE_CUSTOM_PROPERTIES ]; uint32_t ulPropertyNamesLengths[ _az_IOT_ADU_CLIENT_MAX_DEVICE_CUSTOM_PROPERTIES ]; uint8_t * pucPropertyValues[ _az_IOT_ADU_CLIENT_MAX_DEVICE_CUSTOM_PROPERTIES ]; uint32_t ulPropertyValuesLengths[ _az_IOT_ADU_CLIENT_MAX_DEVICE_CUSTOM_PROPERTIES ]; uint32_t ulPropertyCount; struct { az_iot_adu_device_custom_properties xCustomProperties; } _internal; } AzureIoTADUDeviceCustomProperties_t; /** * @brief ADU Device Properties. * * https://docs.microsoft.com/en-us/azure/iot-hub-device-update/understand-device-update#device-update-agent * * @note AzureIoTADUClient_DevicePropertiesInit() should be called first to initialize this struct. */ typedef struct AzureIoTADUClientDeviceProperties { const uint8_t * ucManufacturer; uint32_t ulManufacturerLength; const uint8_t * ucModel; uint32_t ulModelLength; AzureIoTADUDeviceCustomProperties_t * pxCustomProperties; const uint8_t * ucCurrentUpdateId; uint32_t ulCurrentUpdateIdLength; const uint8_t * ucDeliveryOptimizationAgentVersion; uint32_t ulDeliveryOptimizationAgentVersionLength; } AzureIoTADUClientDeviceProperties_t; /** * @brief Actions requested by the ADU Service * */ typedef enum AzureIoTADUAction { eAzureIoTADUActionApplyDownload = 3, eAzureIoTADUActionCancel = 255 } AzureIoTADUAction_t; /** * @brief ADU workflow struct. * @remark Format: * { * "action": 3, * "id": "someguid", * "retryTimestamp": "2020-04-22T12:12:12.0000000+00:00" * } * * https://docs.microsoft.com/en-us/azure/iot-hub-device-update/understand-device-update#device-update-agent */ typedef struct AzureIoTADUClientWorkflow { AzureIoTADUAction_t xAction; const uint8_t * pucID; uint32_t ulIDLength; const uint8_t * pucRetryTimestamp; uint32_t ulRetryTimestampLength; } AzureIoTADUClientWorkflow_t; /** * @brief The update step result reported by the agent. * */ typedef struct AzureIoTADUClientStepResult { uint32_t ulResultCode; uint32_t ulExtendedResultCode; const uint8_t * pucResultDetails; uint32_t ulResultDetailsLength; } AzureIoTADUClientStepResult_t; /** * @brief The update result reported by the agent. * */ typedef struct AzureIoTADUClientInstallResult { int32_t lResultCode; int32_t lExtendedResultCode; const uint8_t * pucResultDetails; uint32_t ulResultDetailsLength; AzureIoTADUClientStepResult_t pxStepResults[ _az_IOT_ADU_CLIENT_MAX_INSTRUCTIONS_STEPS ]; uint32_t ulStepResultsCount; } AzureIoTADUClientInstallResult_t; /** * @brief States of the ADU agent * @remark State is reported in response to an update request Action. * * https://docs.microsoft.com/en-us/azure/iot-hub-device-update/device-update-plug-and-play#state * */ typedef enum AzureIoTADUAgentState { eAzureIoTADUAgentStateIdle = 0, eAzureIoTADUAgentStateDeploymentInProgress = 6, eAzureIoTADUAgentStateFailed = 255, eAzureIoTADUAgentStateError, } AzureIoTADUAgentState_t; /** * @brief Decision values for accepting an update request or not. * */ typedef enum AzureIoTADURequestDecision { eAzureIoTADURequestDecisionAccept, eAzureIoTADURequestDecisionReject } AzureIoTADURequestDecision_t; /** * @brief A map of file ID to download url. * */ typedef struct AzureIoTADUUpdateManifestFileUrl { uint8_t * pucId; uint32_t ulIdLength; uint8_t * pucUrl; uint32_t ulUrlLength; } AzureIoTADUUpdateManifestFileUrl_t; /** * @brief Identity of the update request. * @remark This version refers to the update request itself. * For verifying if an update request is applicable to an * ADU agent, use the update manifest instructions steps "installed criteria". */ typedef struct AzureIoTADUUpdateId { uint8_t * pucProvider; uint32_t ulProviderLength; uint8_t * pucName; uint32_t ulNameLength; uint8_t * pucVersion; uint32_t ulVersionLength; } AzureIoTADUUpdateId_t; /** * @brief The name of a file referenced in the update manifest. * */ typedef struct AzureIoTADUInstructionStepFile { uint8_t * pucFileName; uint32_t ulFileNameLength; } AzureIoTADUUpdateManifestInstructionStepFile_t; /** * @brief Hash value of a given file. * */ typedef struct AzureIoTADUUpdateManifestFileHash { uint8_t * pucId; uint32_t ulIdLength; uint8_t * pucHash; uint32_t ulHashLength; } AzureIoTADUUpdateManifestFileHash_t; /** * @brief Details of a file referenced in the update request. * */ typedef struct AzureIoTADUUpdateManifestFile { uint8_t * pucId; uint32_t ulIdLength; uint8_t * pucFileName; uint32_t ulFileNameLength; int64_t llSizeInBytes; uint32_t ulHashesCount; AzureIoTADUUpdateManifestFileHash_t pxHashes[ _az_IOT_ADU_CLIENT_MAX_FILE_HASH_COUNT ]; } AzureIoTADUUpdateManifestFile_t; /** * @brief A step in the instructions of an ADU update manifest. * */ typedef struct AzureIoTADUInstructionStep { uint8_t * pucHandler; uint32_t ulHandlerLength; uint8_t * pucInstalledCriteria; uint32_t ulInstalledCriteriaLength; uint32_t ulFilesCount; AzureIoTADUUpdateManifestInstructionStepFile_t pxFiles[ _az_IOT_ADU_CLIENT_MAX_FILE_COUNT_PER_STEP ]; } AzureIoTADUInstructionStep_t; /** * @brief Instructions in the update manifest. */ typedef struct AzureIoTADUInstructions { uint32_t ulStepsCount; AzureIoTADUInstructionStep_t pxSteps[ _az_IOT_ADU_CLIENT_MAX_INSTRUCTIONS_STEPS ]; } AzureIoTADUInstructions_t; /** * @brief Structure that holds the parsed contents of the update manifest * sent by the ADU service. */ typedef struct AzureIoTADUUpdateManifest { AzureIoTADUUpdateId_t xUpdateId; AzureIoTADUInstructions_t xInstructions; uint32_t ulFilesCount; AzureIoTADUUpdateManifestFile_t pxFiles[ _az_IOT_ADU_CLIENT_MAX_TOTAL_FILE_COUNT ]; uint8_t * pucManifestVersion; uint32_t ulManifestVersionLength; uint8_t * pucCreateDateTime; uint32_t ulCreateDateTimeLength; } AzureIoTADUUpdateManifest_t; /** * @brief Structure that holds the parsed contents of the ADU * request in the Plug and Play writable properties sent * by the ADU service. */ typedef struct AzureIoTADUUpdateRequest { AzureIoTADUClientWorkflow_t xWorkflow; uint8_t * pucUpdateManifest; uint32_t ulUpdateManifestLength; uint8_t * pucUpdateManifestSignature; uint32_t ulUpdateManifestSignatureLength; uint32_t ulFileUrlCount; AzureIoTADUUpdateManifestFileUrl_t pxFileUrls[ _az_IOT_ADU_CLIENT_MAX_TOTAL_FILE_COUNT ]; AzureIoTADUUpdateManifest_t xUpdateManifest; } AzureIoTADUUpdateRequest_t; /** * @brief User-defined options for the Azure IoT ADU client. */ typedef struct AzureIoTADUClientOptions { const uint8_t * pucCompatibilityProperties; uint32_t ulCompatibilityPropertiesLength; } AzureIoTADUClientOptions_t; /** * @brief Azure IoT ADU Client (ADU agent) to handle stages of the ADU process. */ typedef struct AzureIoTADUClient { struct { az_iot_adu_client xADUClient; } _internal; /**< Internal */ } AzureIoTADUClient_t; /** * @brief Initialize the Azure IoT ADU Options with default values. * * @param[out] pxADUClientOptions The #AzureIoTADUClientOptions_t instance to set with default values. * @return An #AzureIoTResult_t with the result of the operation. */ AzureIoTResult_t AzureIoTADUClient_OptionsInit( AzureIoTADUClientOptions_t * pxADUClientOptions ); /** * @brief Initialize the Azure IoT ADU Client. * * @param[in] pxAzureIoTADUClient The #AzureIoTADUClient_t * to use for this call. * @param[in] pxADUClientOptions The #AzureIoTADUClientOptions_t for the IoT ADU client instance. * @return An #AzureIoTResult_t with the result of the operation. */ AzureIoTResult_t AzureIoTADUClient_Init( AzureIoTADUClient_t * pxAzureIoTADUClient, AzureIoTADUClientOptions_t * pxADUClientOptions ); /** * @brief Initialize the Azure IoT Device Properties with default values. * * @param[out] pxADUDeviceProperties The #AzureIoTADUClientDeviceProperties_t instance to set with default values. * @return An #AzureIoTResult_t with the result of the operation. */ AzureIoTResult_t AzureIoTADUClient_DevicePropertiesInit( AzureIoTADUClientDeviceProperties_t * pxADUDeviceProperties ); /** * @brief Returns whether the component is the ADU component * * @note If it is, user should follow by parsing the component with the * AzureIoTHubClient_ADUProcessComponent() call. The properties will be * processed into the AzureIoTADUClient. * * @param[in] pxAzureIoTADUClient The #AzureIoTADUClient_t * to use for this call. * @param[in] pucComponentName Name of writable properties component to be checked. * @param[in] ulComponentNameLength Length of \p pucComponentName. * @return A boolean value indicating if the writable properties component * is from ADU service. */ bool AzureIoTADUClient_IsADUComponent( AzureIoTADUClient_t * pxAzureIoTADUClient, const uint8_t * pucComponentName, uint32_t ulComponentNameLength ); /** * @brief Parse the ADU update request into the requisite structure. * * The JSON reader returned to the caller from AzureIoTHubClientProperties_GetNextComponentProperty() * should be passed to this API. * * @param[in] pxAzureIoTADUClient The #AzureIoTADUClient_t * to use for this call. * @param[in,out] pxReader The initialized JSON reader positioned at the beginning of the ADU subcomponent property. * @param[out] pxAduUpdateRequest The #AzureIoTADUUpdateRequest_t into which the properties will be parsed. * @return AzureIoTResult_t An #AzureIoTResult_t with the result of the operation. */ AzureIoTResult_t AzureIoTADUClient_ParseRequest( AzureIoTADUClient_t * pxAzureIoTADUClient, AzureIoTJSONReader_t * pxReader, AzureIoTADUUpdateRequest_t * pxAduUpdateRequest ); /** * @brief Updates the ADU Agent Client with ADU service device update properties. * @remark It must be called whenever writable properties are received containing * ADU service properties (verified with AzureIoTADUClient_IsADUComponent). * It effectively parses the properties (aka, the device update request) * from ADU and sets the state machine to perform the update process if the * the update request is applicable (e.g., if the version is not already * installed). * This function also provides the payload to acknowledge the ADU service * Azure Plug-and-Play writable properties. * * @param[in] pxAzureIoTADUClient The #AzureIoTADUClient_t * to use for this call. * @param[in] pxAzureIoTHubClient The #AzureIoTHubClient_t * to use for this call. * @param[in] xRequestDecision The #AzureIoTADURequestDecision_t for this response. * @param[in] ulPropertyVersion Version of the writable properties. * @param[out] pucWritablePropertyResponseBuffer A pointer to the memory buffer where to write * the resulting Azure Plug-and-Play properties acknowledgement payload. * @param[in] ulWritablePropertyResponseBufferSize Size of \p pucWritablePropertyResponseBuffer. * @param[in] pulRequestId Pointer to request id to use for the operation. * @return An #AzureIoTResult_t with the result of the operation. */ AzureIoTResult_t AzureIoTADUClient_SendResponse( AzureIoTADUClient_t * pxAzureIoTADUClient, AzureIoTHubClient_t * pxAzureIoTHubClient, AzureIoTADURequestDecision_t xRequestDecision, uint32_t ulPropertyVersion, uint8_t * pucWritablePropertyResponseBuffer, uint32_t ulWritablePropertyResponseBufferSize, uint32_t * pulRequestId ); /** * @brief Sends the current state of the Azure IoT ADU agent. * * @param[in] pxAzureIoTADUClient The #AzureIoTADUClient_t * to use for this call. * @param[in] pxAzureIoTHubClient The #AzureIoTHubClient_t * to use for this call. * @param[in] pxDeviceProperties The device information which will be used to generate the payload. * @param[in] pxAduUpdateRequest The current #AzureIoTADUUpdateRequest_t. This can be `NULL` if there isn't currently * an update request. * @param[in] xAgentState The current #AzureIoTADUAgentState_t. * @param[in] pxUpdateResults The current #AzureIoTADUClientInstallResult_t. This can be `NULL` if there aren't any * results from an update. * @param[out] pucBuffer The buffer into which the generated payload will be placed. * @param[in] ulBufferSize The length of \p pucBuffer. * @param[in] pulRequestId An optional request id to be used for the publish. This can be `NULL`. * @return An #AzureIoTResult_t with the result of the operation. */ AzureIoTResult_t AzureIoTADUClient_SendAgentState( AzureIoTADUClient_t * pxAzureIoTADUClient, AzureIoTHubClient_t * pxAzureIoTHubClient, AzureIoTADUClientDeviceProperties_t * pxDeviceProperties, AzureIoTADUUpdateRequest_t * pxAduUpdateRequest, AzureIoTADUAgentState_t xAgentState, AzureIoTADUClientInstallResult_t * pxUpdateResults, uint8_t * pucBuffer, uint32_t ulBufferSize, uint32_t * pulRequestId ); #endif /* AZURE_IOT_ADU_CLIENT_H */