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 */