Address CR comments for ESP32 Azure IoT Central samples

This commit is contained in:
Ewerton Scaboro da Silva 2022-01-19 17:11:24 -08:00
Родитель 041de369dc
Коммит ffa12ad78a
14 изменённых файлов: 447 добавлений и 383 удалений

Просмотреть файл

@ -15,8 +15,8 @@
log_function_t default_logging_function = NULL; log_function_t default_logging_function = NULL;
#endif // DISABLE_LOGGING #endif // DISABLE_LOGGING
/* --- Azure Abstractions --- */ /* --- Azure Definitions --- */
#define IOT_HUB_MQTT_PORT 8883 #define IOT_HUB_MQTT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define MQTT_PROTOCOL_PREFIX "mqtts://" #define MQTT_PROTOCOL_PREFIX "mqtts://"
#define DPS_GLOBAL_ENDPOINT_MQTT_URI MQTT_PROTOCOL_PREFIX DPS_GLOBAL_ENDPOINT_FQDN #define DPS_GLOBAL_ENDPOINT_MQTT_URI MQTT_PROTOCOL_PREFIX DPS_GLOBAL_ENDPOINT_FQDN
#define DPS_GLOBAL_ENDPOINT_MQTT_URI_WITH_PORT DPS_GLOBAL_ENDPOINT_MQTT_URI ":" STR(DPS_GLOBAL_ENDPOINT_PORT) #define DPS_GLOBAL_ENDPOINT_MQTT_URI_WITH_PORT DPS_GLOBAL_ENDPOINT_MQTT_URI ":" STR(DPS_GLOBAL_ENDPOINT_PORT)
@ -45,6 +45,8 @@ log_function_t default_logging_function = NULL;
#define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \ #define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \
EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__ ) EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__ )
#define NUMBER_OF_SECONDS_IN_A_MINUTE 60
/* --- Internal function prototypes --- */ /* --- Internal function prototypes --- */
static uint32_t get_current_unix_time(); static uint32_t get_current_unix_time();
@ -71,17 +73,17 @@ static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_clien
static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder); static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder);
#define is_device_provisioned(azure_iot) \ #define is_device_provisioned(azure_iot) \
(!az_span_is_empty(azure_iot->config->iot_hub_fqdn) && !az_span_is_empty(azure_iot->config->device_id)) (!is_az_span_empty(azure_iot->config->iot_hub_fqdn) && !is_az_span_empty(azure_iot->config->device_id))
/* --- Public API --- */ /* --- Public API --- */
int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config) void azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config)
{ {
_az_PRECONDITION_NOT_NULL(azure_iot); _az_PRECONDITION_NOT_NULL(azure_iot);
_az_PRECONDITION_NOT_NULL(azure_iot_config); _az_PRECONDITION_NOT_NULL(azure_iot_config);
if (azure_iot_config->use_device_provisioning) if (azure_iot_config->use_device_provisioning)
{ {
_az_PRECONDITION(az_span_is_empty(azure_iot_config->iot_hub_fqdn)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->iot_hub_fqdn));
_az_PRECONDITION(az_span_is_empty(azure_iot_config->device_id)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->device_id));
_az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_id_scope, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_id_scope, 1, false);
_az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_registration_id, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_registration_id, 1, false);
} }
@ -89,14 +91,14 @@ int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config)
{ {
_az_PRECONDITION_VALID_SPAN(azure_iot_config->iot_hub_fqdn, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->iot_hub_fqdn, 1, false);
_az_PRECONDITION_VALID_SPAN(azure_iot_config->device_id, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->device_id, 1, false);
_az_PRECONDITION(az_span_is_empty(azure_iot_config->dps_id_scope)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->dps_id_scope));
_az_PRECONDITION(az_span_is_empty(azure_iot_config->dps_registration_id)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->dps_registration_id));
} }
_az_PRECONDITION_VALID_SPAN(azure_iot_config->device_key, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->device_key, 1, false);
_az_PRECONDITION_VALID_SPAN(azure_iot_config->data_buffer, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->data_buffer, 1, false);
_az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_decode); _az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_decode);
_az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_encode); _az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_encode);
_az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.hmac_sha512_encrypt); _az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.hmac_sha256_encrypt);
_az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_init); _az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_init);
_az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_deinit); _az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_deinit);
_az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_subscribe); _az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_subscribe);
@ -115,8 +117,6 @@ int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config)
{ {
azure_iot->config->sas_token_lifetime_in_minutes = DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES; azure_iot->config->sas_token_lifetime_in_minutes = DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES;
} }
return RESULT_OK;
} }
int azure_iot_start(azure_iot_t* azure_iot) int azure_iot_start(azure_iot_t* azure_iot)
@ -237,7 +237,8 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
size_t length; size_t length;
mqtt_client_config_t mqtt_client_config; mqtt_client_config_t mqtt_client_config;
mqtt_message_t mqtt_message; mqtt_message_t mqtt_message;
az_span data_buffer, dps_register_custom_property; az_span data_buffer;
az_span dps_register_custom_property;
switch (azure_iot->state) switch (azure_iot->state)
{ {
@ -250,7 +251,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
// This seems harmless, but... // This seems harmless, but...
// azure_iot->config->data_buffer always points to the original buffer provided by the user. // azure_iot->config->data_buffer always points to the original buffer provided by the user.
// azure_iot->data_buffer is an intermediate pointer. It starts by pointint to azure_iot->config->data_buffer. // azure_iot->data_buffer is an intermediate pointer. It starts by pointing to azure_iot->config->data_buffer.
// In the steps below the code might need to retain part of azure_iot->data_buffer for saving some critical information, // In the steps below the code might need to retain part of azure_iot->data_buffer for saving some critical information,
// namely the DPS operation id, the provisioned IoT Hub FQDN and provisioned Device ID (if provisioning is being used). // namely the DPS operation id, the provisioned IoT Hub FQDN and provisioned Device ID (if provisioning is being used).
// In these cases, azure_iot->data_buffer will then point to `the remaining available space` of azure_iot->config->data_buffer // In these cases, azure_iot->data_buffer will then point to `the remaining available space` of azure_iot->config->data_buffer
@ -277,6 +278,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed initializing MQTT client."); LogError("Failed initializing MQTT client.");
return;
} }
break; break;
@ -287,15 +289,15 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_subscribing_to_dps; azure_iot->state = azure_iot_state_subscribing_to_dps;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, azure_iot->mqtt_client_handle,
(const uint8_t*)AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC, AZ_SPAN_FROM_STR(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC),
lengthof(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC),
mqtt_qos_at_most_once); mqtt_qos_at_most_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Device Provisioning respose topic."); LogError("Failed subscribing to Azure Device Provisioning respose topic.");
return;
} }
break; break;
@ -314,19 +316,19 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
return; return;
} }
mqtt_message.topic = az_span_split(data_buffer, length, &data_buffer); mqtt_message.topic = split_az_span(data_buffer, length, &data_buffer);
if (az_span_is_empty(mqtt_message.topic) || az_span_is_empty(data_buffer)) if (is_az_span_empty(mqtt_message.topic) || is_az_span_empty(data_buffer))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed allocating memory for DPS register payload."); LogError("Failed reserving memory for DPS register payload.");
return; return;
} }
dps_register_custom_property = generate_dps_register_custom_property( dps_register_custom_property = generate_dps_register_custom_property(
azure_iot->config->model_id, data_buffer, &mqtt_message.payload); azure_iot->config->model_id, data_buffer, &mqtt_message.payload);
if (az_span_is_empty(dps_register_custom_property)) if (is_az_span_empty(dps_register_custom_property))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed generating DPS register custom property payload."); LogError("Failed generating DPS register custom property payload.");
@ -359,6 +361,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed publishing to DPS registration topic"); LogError("Failed publishing to DPS registration topic");
return;
} }
break; break;
@ -405,6 +408,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed publishing to DPS status query topic"); LogError("Failed publishing to DPS status query topic");
return;
} }
break; break;
@ -437,7 +441,8 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
if (azure_iot->config->mqtt_client_interface.mqtt_client_init(&mqtt_client_config, &azure_iot->mqtt_client_handle) != 0) if (azure_iot->config->mqtt_client_interface.mqtt_client_init(&mqtt_client_config, &azure_iot->mqtt_client_handle) != 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed initializing MQTT client."); LogError("Failed initializing MQTT client for IoT Hub connection.");
return;
} }
break; break;
@ -447,13 +452,15 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_subscribing_to_pnp_cmds; azure_iot->state = azure_iot_state_subscribing_to_pnp_cmds;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, (const uint8_t*)AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC, azure_iot->mqtt_client_handle,
lengthof(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC),
mqtt_qos_at_least_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Plug and Play commands topic."); LogError("Failed subscribing to IoT Plug and Play commands topic.");
return;
} }
break; break;
@ -463,30 +470,33 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_subscribing_to_pnp_props; azure_iot->state = azure_iot_state_subscribing_to_pnp_props;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, (const uint8_t*)AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC, azure_iot->mqtt_client_handle,
lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC),
mqtt_qos_at_least_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Plug and Play properties topic."); LogError("Failed subscribing to IoT Plug and Play properties topic.");
return;
} }
break;
break;
case azure_iot_state_subscribing_to_pnp_props: case azure_iot_state_subscribing_to_pnp_props:
break; break;
case azure_iot_state_subscribed_to_pnp_props: case azure_iot_state_subscribed_to_pnp_props:
azure_iot->state = azure_iot_state_subscribing_to_pnp_writable_props; azure_iot->state = azure_iot_state_subscribing_to_pnp_writable_props;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, (const uint8_t*)AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC, azure_iot->mqtt_client_handle,
lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC),
mqtt_qos_at_least_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Plug and Play writable properties topic."); LogError("Failed subscribing to IoT Plug and Play writable properties topic.");
return;
} }
break; break;
@ -501,13 +511,14 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed getting current time for checking SAS token expiration."); LogError("Failed getting current time for checking SAS token expiration.");
} }
else if ((azure_iot->sas_token_expiration_time - now) < SAS_TOKEN_REFRESH_THRESHOLD_SECS) else if ((azure_iot->sas_token_expiration_time - now) < SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS)
{ {
azure_iot->state = azure_iot_state_refreshing_sas; azure_iot->state = azure_iot_state_refreshing_sas;
if (azure_iot->config->mqtt_client_interface.mqtt_client_deinit(&azure_iot->mqtt_client_handle) != 0) if (azure_iot->config->mqtt_client_interface.mqtt_client_deinit(&azure_iot->mqtt_client_handle) != 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed de-initializing MQTT client."); LogError("Failed de-initializing MQTT client.");
return;
} }
} }
break; break;
@ -559,7 +570,7 @@ int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id
azr = az_iot_hub_client_properties_get_reported_publish_topic( azr = az_iot_hub_client_properties_get_reported_publish_topic(
&azure_iot->iot_hub_client, request_id_span, (char*)az_span_ptr(data_buffer), az_span_size(data_buffer), &topic_length); &azure_iot->iot_hub_client, request_id_span, (char*)az_span_ptr(data_buffer), az_span_size(data_buffer), &topic_length);
EXIT_IF_AZ_FAILED(azr, RESULT_ERROR, "Failed to get the repoted properties publish topic"); EXIT_IF_AZ_FAILED(azr, RESULT_ERROR, "Failed to get the reported properties publish topic");
mqtt_message.topic = az_span_slice(data_buffer, 0, topic_length); mqtt_message.topic = az_span_slice(data_buffer, 0, topic_length);
mqtt_message.payload = message; mqtt_message.payload = message;
@ -690,7 +701,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
{ {
// This message should either be: // This message should either be:
// - a response to a properties update request, or // - a response to a properties update request, or
// - a response to a get properties request, or // - a response to a "get" properties request, or
// - a command request. // - a command request.
az_iot_hub_client_properties_message property_message; az_iot_hub_client_properties_message property_message;
@ -725,7 +736,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
if (az_result_failed(az_span_atou32(property_message.request_id, &request_id))) if (az_result_failed(az_span_atou32(property_message.request_id, &request_id)))
{ {
LogError("Failed parsing properties update request id (%.*s)", LogError("Failed parsing properties update request id (%.*s).",
az_span_size(property_message.request_id), az_span_ptr(property_message.request_id)); az_span_size(property_message.request_id), az_span_ptr(property_message.request_id));
result = RESULT_ERROR; result = RESULT_ERROR;
} }
@ -789,14 +800,14 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
{ {
result = RESULT_OK; result = RESULT_OK;
if (az_span_is_empty(azure_iot->dps_operation_id)) if (is_az_span_empty(azure_iot->dps_operation_id))
{ {
azure_iot->dps_operation_id = az_span_slice_and_copy(azure_iot->data_buffer, register_response.operation_id, &azure_iot->data_buffer); azure_iot->dps_operation_id = slice_and_copy_az_span(azure_iot->data_buffer, register_response.operation_id, &azure_iot->data_buffer);
if (az_span_is_empty(azure_iot->dps_operation_id)) if (is_az_span_empty(azure_iot->dps_operation_id))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed allocating memory for DPS operation id."); LogError("Failed reserving memory for DPS operation id.");
result = RESULT_ERROR; result = RESULT_ERROR;
} }
} }
@ -812,9 +823,9 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
az_span data_buffer = azure_iot->config->data_buffer; // Operation ID is no longer needed. az_span data_buffer = azure_iot->config->data_buffer; // Operation ID is no longer needed.
azure_iot->data_buffer = data_buffer; // In case any step below fails. azure_iot->data_buffer = data_buffer; // In case any step below fails.
azure_iot->config->iot_hub_fqdn = az_span_slice_and_copy(data_buffer, register_response.registration_state.assigned_hub_hostname, &data_buffer); azure_iot->config->iot_hub_fqdn = slice_and_copy_az_span(data_buffer, register_response.registration_state.assigned_hub_hostname, &data_buffer);
if (az_span_is_empty(azure_iot->config->iot_hub_fqdn)) if (is_az_span_empty(azure_iot->config->iot_hub_fqdn))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed saving IoT Hub fqdn from provisioning."); LogError("Failed saving IoT Hub fqdn from provisioning.");
@ -822,9 +833,9 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
} }
else else
{ {
azure_iot->config->device_id = az_span_slice_and_copy(data_buffer, register_response.registration_state.device_id, &data_buffer); azure_iot->config->device_id = slice_and_copy_az_span(data_buffer, register_response.registration_state.device_id, &data_buffer);
if (az_span_is_empty(azure_iot->config->device_id)) if (is_az_span_empty(azure_iot->config->device_id))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed saving device id from provisioning."); LogError("Failed saving device id from provisioning.");
@ -848,7 +859,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
} }
else else
{ {
LogError("No PUBLISH notification expected"); LogError("No PUBLISH notification expected.");
result = RESULT_ERROR; result = RESULT_ERROR;
} }
@ -870,7 +881,7 @@ int azure_iot_send_command_response(azure_iot_t* azure_iot, az_span request_id,
azrc = az_iot_hub_client_commands_response_get_publish_topic( azrc = az_iot_hub_client_commands_response_get_publish_topic(
&azure_iot->iot_hub_client, request_id, response_status, &azure_iot->iot_hub_client, request_id, response_status,
(char*)az_span_ptr(mqtt_message.topic), az_span_size(mqtt_message.topic), &topic_length); (char*)az_span_ptr(mqtt_message.topic), az_span_size(mqtt_message.topic), &topic_length);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed to get the commands response topic"); EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed to get the commands response topic.");
mqtt_message.topic = az_span_slice(mqtt_message.topic, 0, topic_length); mqtt_message.topic = az_span_slice(mqtt_message.topic, 0, topic_length);
mqtt_message.payload = payload; mqtt_message.payload = payload;
@ -903,7 +914,7 @@ static uint32_t get_current_unix_time()
} }
/* /*
* @brief Initializes the Device Provisioning client and generates the config for a MQTT client. * @brief Initializes the Device Provisioning client and generates the config for an MQTT client.
* @param[in] azure_iot A pointer to an initialized instance of azure_iot_t. * @param[in] azure_iot A pointer to an initialized instance of azure_iot_t.
* @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for * @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for
* creating and connecting an MQTT client to Azure Device Provisioning service. * creating and connecting an MQTT client to Azure Device Provisioning service.
@ -912,8 +923,13 @@ static uint32_t get_current_unix_time()
*/ */
static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config) static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config)
{ {
az_span data_buffer_span, client_id_span, username_span, password_span; az_span data_buffer_span;
size_t client_id_length, username_length, password_length; az_span client_id_span;
az_span username_span;
az_span password_span;
size_t client_id_length;
size_t username_length;
size_t password_length;
az_result azrc; az_result azrc;
azrc = az_iot_provisioning_client_init( azrc = az_iot_provisioning_client_init(
@ -926,8 +942,8 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
data_buffer_span = azure_iot->data_buffer; data_buffer_span = azure_iot->data_buffer;
password_span = az_span_split(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span); password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(password_span), RESULT_ERROR, "Failed allocating buffer for password_span."); EXIT_IF_TRUE(is_az_span_empty(password_span), RESULT_ERROR, "Failed reserving buffer for password_span.");
password_length = generate_sas_token_for_dps( password_length = generate_sas_token_for_dps(
&azure_iot->dps_client, &azure_iot->dps_client,
@ -939,14 +955,14 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
&azure_iot->sas_token_expiration_time); &azure_iot->sas_token_expiration_time);
EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for DPS connection."); EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for DPS connection.");
client_id_span = az_span_split(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span); client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); EXIT_IF_TRUE(is_az_span_empty(client_id_span), RESULT_ERROR, "Failed reserving buffer for client_id_span.");
azrc = az_iot_provisioning_client_get_client_id( azrc = az_iot_provisioning_client_get_client_id(
&azure_iot->dps_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length); &azure_iot->dps_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for DPS connection."); EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for DPS connection.");
username_span = az_span_split(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span); username_span = split_az_span(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span);
azrc = az_iot_provisioning_client_get_user_name( azrc = az_iot_provisioning_client_get_user_name(
&azure_iot->dps_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length); &azure_iot->dps_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length);
@ -963,7 +979,7 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
} }
/* /*
* @brief Initializes the Azure IoT Hub client and generates the config for a MQTT client. * @brief Initializes the Azure IoT Hub client and generates the config for an MQTT client.
* @param[in] azure_iot A pointer to an initialized instance of azure_iot_t. * @param[in] azure_iot A pointer to an initialized instance of azure_iot_t.
* @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for * @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for
* creating and connecting an MQTT client to Azure IoT Hub. * creating and connecting an MQTT client to Azure IoT Hub.
@ -972,8 +988,13 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
*/ */
static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config) static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config)
{ {
az_span data_buffer_span, client_id_span, username_span, password_span; az_span data_buffer_span;
size_t client_id_length, username_length, password_length; az_span client_id_span;
az_span username_span;
az_span password_span;
size_t client_id_length;
size_t username_length;
size_t password_length;
az_result azrc; az_result azrc;
azure_iot->iot_hub_client_options = az_iot_hub_client_options_default(); azure_iot->iot_hub_client_options = az_iot_hub_client_options_default();
@ -989,8 +1010,8 @@ static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_clien
data_buffer_span = azure_iot->data_buffer; data_buffer_span = azure_iot->data_buffer;
password_span = az_span_split(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span); password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(password_span), RESULT_ERROR, "Failed allocating buffer for password_span."); EXIT_IF_TRUE(is_az_span_empty(password_span), RESULT_ERROR, "Failed reserving buffer for password_span.");
password_length = generate_sas_token_for_iot_hub( password_length = generate_sas_token_for_iot_hub(
&azure_iot->iot_hub_client, &azure_iot->iot_hub_client,
@ -1002,14 +1023,14 @@ static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_clien
&azure_iot->sas_token_expiration_time); &azure_iot->sas_token_expiration_time);
EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for IoT Hub connection."); EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for IoT Hub connection.");
client_id_span = az_span_split(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span); client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); EXIT_IF_TRUE(is_az_span_empty(client_id_span), RESULT_ERROR, "Failed reserving buffer for client_id_span.");
azrc = az_iot_hub_client_get_client_id( azrc = az_iot_hub_client_get_client_id(
&azure_iot->iot_hub_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length); &azure_iot->iot_hub_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for IoT Hub connection."); EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for IoT Hub connection.");
username_span = az_span_split(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span); username_span = split_az_span(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span);
azrc = az_iot_hub_client_get_user_name( azrc = az_iot_hub_client_get_user_name(
&azure_iot->iot_hub_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length); &azure_iot->iot_hub_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length);
@ -1064,32 +1085,32 @@ static int generate_sas_token_for_dps(
current_unix_time = get_current_unix_time(); current_unix_time = get_current_unix_time();
EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time."); EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time.");
*expiration_time = current_unix_time + duration_in_minutes * 60; *expiration_time = current_unix_time + duration_in_minutes * NUMBER_OF_SECONDS_IN_A_MINUTE;
// Step 2.a. // Step 2.a.
plain_sas_signature = az_span_split(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(plain_sas_signature), 0, "Failed allocating buffer for plain sas token."); EXIT_IF_TRUE(is_az_span_empty(plain_sas_signature), 0, "Failed reserving buffer for plain sas token.");
rc = az_iot_provisioning_client_sas_get_signature( rc = az_iot_provisioning_client_sas_get_signature(
provisioning_client, *expiration_time, plain_sas_signature, &plain_sas_signature); provisioning_client, *expiration_time, plain_sas_signature, &plain_sas_signature);
EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key"); EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key.");
// Step 2.b. // Step 2.b.
sas_signature = az_span_split(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_signature), 0, "Failed allocating buffer for sas_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_signature), 0, "Failed reserving buffer for sas_signature.");
decoded_sas_key = az_span_split(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key.");
result = data_manipulation_functions.base64_decode( result = data_manipulation_functions.base64_decode(
az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length); az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length);
EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key.");
// Step 2.c. // Step 2.c.
sas_hmac256_signed_signature = az_span_split(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_hmac256_signed_signature), 0, "Failed allocating buffer for sas_hmac256_signed_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_hmac256_signed_signature), 0, "Failed reserving buffer for sas_hmac256_signed_signature.");
result = data_manipulation_functions.hmac_sha512_encrypt( result = data_manipulation_functions.hmac_sha256_encrypt(
az_span_ptr(decoded_sas_key), decoded_sas_key_length, az_span_ptr(decoded_sas_key), decoded_sas_key_length,
az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature), az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature),
az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature)); az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature));
@ -1155,32 +1176,32 @@ static int generate_sas_token_for_iot_hub(
current_unix_time = get_current_unix_time(); current_unix_time = get_current_unix_time();
EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time."); EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time.");
*expiration_time = current_unix_time + duration_in_minutes * 60; *expiration_time = current_unix_time + duration_in_minutes * NUMBER_OF_SECONDS_IN_A_MINUTE;
// Step 2.a. // Step 2.a.
plain_sas_signature = az_span_split(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(plain_sas_signature), 0, "Failed allocating buffer for plain sas token."); EXIT_IF_TRUE(is_az_span_empty(plain_sas_signature), 0, "Failed reserving buffer for plain sas token.");
rc = az_iot_hub_client_sas_get_signature( rc = az_iot_hub_client_sas_get_signature(
iot_hub_client, *expiration_time, plain_sas_signature, &plain_sas_signature); iot_hub_client, *expiration_time, plain_sas_signature, &plain_sas_signature);
EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key"); EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key.");
// Step 2.b. // Step 2.b.
sas_signature = az_span_split(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_signature), 0, "Failed allocating buffer for sas_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_signature), 0, "Failed reserving buffer for sas_signature.");
decoded_sas_key = az_span_split(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key.");
result = data_manipulation_functions.base64_decode( result = data_manipulation_functions.base64_decode(
az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length); az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length);
EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key.");
// Step 2.c. // Step 2.c.
sas_hmac256_signed_signature = az_span_split(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_hmac256_signed_signature), 0, "Failed allocating buffer for sas_hmac256_signed_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_hmac256_signed_signature), 0, "Failed reserving buffer for sas_hmac256_signed_signature.");
result = data_manipulation_functions.hmac_sha512_encrypt( result = data_manipulation_functions.hmac_sha256_encrypt(
az_span_ptr(decoded_sas_key), decoded_sas_key_length, az_span_ptr(decoded_sas_key), decoded_sas_key_length,
az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature), az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature),
az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature)); az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature));
@ -1207,32 +1228,45 @@ static int generate_sas_token_for_iot_hub(
return mqtt_password_length; return mqtt_password_length;
} }
/**
* @brief Generates a custom payload for DPS registration request containing the Azure PnP model ID.
* @remark This payload with the model ID is required for Azure IoT Central to properly
* assign the IoT Plug and Play template.
*
* @param[in] mode_id The string with the IoT Plug and Play model ID.
* @param[in] data_buffer Buffer where to write the resulting payload.
* @param[in] remainder The remainder space of `data_buffer` after enough is reserved for
* the resulting payload.
*
* @return az_span An az_span (reserved from `data_buffer`) containing the payload
* for the DPS registration request.
*/
static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder) static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder)
{ {
az_span custom_property; az_span custom_property;
size_t length = lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN) + az_span_size(model_id) + lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_END); size_t length = lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN) + az_span_size(model_id) + lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_END);
custom_property = az_span_split(data_buffer, length, remainder); custom_property = split_az_span(data_buffer, length, remainder);
EXIT_IF_TRUE(az_span_is_empty(custom_property), AZ_SPAN_EMPTY, "Failed generating DPS register custom property."); EXIT_IF_TRUE(is_az_span_empty(custom_property), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (not enough space).");
data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN)); data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN));
EXIT_IF_TRUE(az_span_is_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (prefix)."); EXIT_IF_TRUE(is_az_span_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (prefix).");
data_buffer = az_span_copy(data_buffer, model_id); data_buffer = az_span_copy(data_buffer, model_id);
EXIT_IF_TRUE(az_span_is_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (model id)."); EXIT_IF_TRUE(is_az_span_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (model id).");
data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_END)); data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_END));
EXIT_IF_TRUE(az_span_is_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (suffix)."); EXIT_IF_TRUE(is_az_span_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (suffix).");
return custom_property; return custom_property;
} }
/* --- az_core extensions --- */ /* --- az_core extensions --- */
az_span az_span_split(az_span span, int32_t size, az_span* remainder) az_span split_az_span(az_span span, int32_t size, az_span* remainder)
{ {
az_span result = az_span_slice(span, 0, size); az_span result = az_span_slice(span, 0, size);
if (remainder != NULL && !az_span_is_empty(result)) if (remainder != NULL && !is_az_span_empty(result))
{ {
*remainder = az_span_slice(span, size, az_span_size(span)); *remainder = az_span_slice(span, size, az_span_size(span));
} }
@ -1240,16 +1274,16 @@ az_span az_span_split(az_span span, int32_t size, az_span* remainder)
return result; return result;
} }
az_span az_span_slice_and_copy(az_span destination, az_span source, az_span* remainder) az_span slice_and_copy_az_span(az_span destination, az_span source, az_span* remainder)
{ {
az_span result = az_span_split(destination, az_span_size(source), remainder); az_span result = split_az_span(destination, az_span_size(source), remainder);
if (az_span_is_empty(*remainder)) if (is_az_span_empty(*remainder))
{ {
result = AZ_SPAN_EMPTY; result = AZ_SPAN_EMPTY;
} }
if (!az_span_is_empty(result)) if (!is_az_span_empty(result))
{ {
(void)az_span_copy(result, source); (void)az_span_copy(result, source);
} }

Просмотреть файл

@ -2,8 +2,10 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
/* /*
* AzureIoT.cpp contains a state machine that implements those steps, plus abstractions to simplify * AzureIoT.cpp contains a state machine that implements the necessary calls to azure-sdk-for-c
* its overall use. Besides the basic configuration needed to access the Azure IoT services, * for aiding to connect and work with Azure IoT services, plus abstractions to
* simplify overall use of azure-sdk-for-c.
* Besides the basic configuration needed to access the Azure IoT services,
* all that is needed is to provide the functions required by that layer to: * all that is needed is to provide the functions required by that layer to:
* - Interact with your MQTT client, * - Interact with your MQTT client,
* - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding), * - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding),
@ -57,13 +59,13 @@ extern log_function_t default_logging_function;
#endif // DISABLE_LOGGING #endif // DISABLE_LOGGING
/* --- Azure Abstraction --- */ /* --- Azure Definitions --- */
#define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net" #define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net"
#define DPS_GLOBAL_ENDPOINT_PORT 8883 #define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define IOT_HUB_ENDPOINT_PORT 8883 #define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES 60 #define DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES 60
#define SAS_TOKEN_REFRESH_THRESHOLD_SECS 30 #define SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS 30
/* /*
* The structures below define a generic interface to abstract the interaction of this module, * The structures below define a generic interface to abstract the interaction of this module,
@ -83,12 +85,13 @@ typedef enum mqtt_qos_t_enum
mqtt_qos_t; mqtt_qos_t;
/* /*
* @brief Defines a generic MQTT message to be exchanged between the AzureIoT.h layer * @brief Defines a generic MQTT message to be exchanged between the AzureIoT layer
* and the user application. * and the user application.
* @remark It uses azure-sdk-for-c's az_span construct, which is merely a structure that * @remark It uses azure-sdk-for-c's az_span construct, which is merely a structure that
* has a pointer to a buffer and its size. Messages without a payload will have * has a pointer to a buffer and its size. Messages without a payload will have
* the `payload` member set to AZ_SPAN_EMPTY. * the `payload` member set to AZ_SPAN_EMPTY.
* Please see the az_span.h in azure-sdk-for-c for more details. * Please see the az_span.h in azure-sdk-for-c for more details at
* https://azuresdkdocs.blob.core.windows.net/$web/c/az_core/1.2.0/az__span_8h.html
*/ */
typedef struct mqtt_message_t_struct typedef struct mqtt_message_t_struct
{ {
@ -105,12 +108,12 @@ mqtt_message_t;
typedef struct mqtt_client_config_t_struct typedef struct mqtt_client_config_t_struct
{ {
/* /*
* @brief FQDN address of the broker the MQTT client shall connect to. * @brief FQDN address of the broker that the MQTT client shall connect to.
*/ */
az_span address; az_span address;
/* /*
* @brief Port of the broker the MQTT client shall connect to. * @brief Port of the broker that the MQTT client shall connect to.
*/ */
int port; int port;
@ -133,12 +136,12 @@ mqtt_client_config_t;
/* /*
* @brief Generic pointer to the actual instance of the application MQTT client. * @brief Generic pointer to the actual instance of the application MQTT client.
* @remark set by the user application when the `mqtt_client_init_function_t` calback is invoked. * @remark set by the user application when the `mqtt_client_init_function_t` callback is invoked.
*/ */
typedef void* mqtt_client_handle_t; typedef void* mqtt_client_handle_t;
/* /*
* @brief Function to initialize and connect a MQTT client. * @brief Function to initialize and connect an MQTT client.
* @remark When this function is called, it provides the information necessary to initialize a * @remark When this function is called, it provides the information necessary to initialize a
* specific MQTT client (whichever is used by the user application). In this callback * specific MQTT client (whichever is used by the user application). In this callback
* it is expected that the MQTT client will be created/initialized, started and that it * it is expected that the MQTT client will be created/initialized, started and that it
@ -155,7 +158,7 @@ typedef void* mqtt_client_handle_t;
typedef int (*mqtt_client_init_function_t)(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t* mqtt_client_handle); typedef int (*mqtt_client_init_function_t)(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t* mqtt_client_handle);
/* /*
* @brief Function to disconnect and deinitialize a MQTT client. * @brief Function to disconnect and deinitialize an MQTT client.
* @remark When this function is called the MQTT client instance referenced by `mqtt_client_handle` shall disconnect * @remark When this function is called the MQTT client instance referenced by `mqtt_client_handle` shall disconnect
* from the server and any functions of the MQTT client API that destroy the instance shall be called * from the server and any functions of the MQTT client API that destroy the instance shall be called
* (so any allocated memory resources can be released). * (so any allocated memory resources can be released).
@ -193,10 +196,8 @@ typedef int (*mqtt_client_publish_function_t)(mqtt_client_handle_t mqtt_client_h
* `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to subscribe to * `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to subscribe to
* an MQTT topic. * an MQTT topic.
* *
* @param[in] topic The string containing the complete MQTT topic name to subscribed to. * @param[in] topic The az_span with the string containing the complete MQTT topic name to subscribed to.
* This string is always NULL-terminated. * This string is always NULL-terminated.
* @param[in] topic_length The length of `topic`. It can be used in case the MQTT client takes a
* topic name as a non-NULL-terminated string.
* @param[in] qos MQTT QoS to be used for the topic subscription. * @param[in] qos MQTT QoS to be used for the topic subscription.
* *
* *
@ -204,7 +205,7 @@ typedef int (*mqtt_client_publish_function_t)(mqtt_client_handle_t mqtt_client_h
* Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called once the * Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called once the
* MQTT client receives a SUBACK. * MQTT client receives a SUBACK.
*/ */
typedef int (*mqtt_client_subscribe_function_t)(mqtt_client_handle_t mqtt_client_handle, const uint8_t* topic, size_t topic_lenght, mqtt_qos_t qos); typedef int (*mqtt_client_subscribe_function_t)(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos);
/* /*
* @brief Structure that consolidates all the abstracted MQTT functions. * @brief Structure that consolidates all the abstracted MQTT functions.
@ -213,13 +214,13 @@ typedef struct mqtt_client_interface_t_struct
{ {
mqtt_client_init_function_t mqtt_client_init; mqtt_client_init_function_t mqtt_client_init;
mqtt_client_deinit_function_t mqtt_client_deinit; mqtt_client_deinit_function_t mqtt_client_deinit;
mqtt_client_subscribe_function_t mqtt_client_subscribe;
mqtt_client_publish_function_t mqtt_client_publish; mqtt_client_publish_function_t mqtt_client_publish;
mqtt_client_subscribe_function_t mqtt_client_subscribe;
} }
mqtt_client_interface_t; mqtt_client_interface_t;
/* /*
* @brief This function must be provided by the user for the AzureIoT.h layer * @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords. * to perform the generation of the SAS tokens used as MQTT passwords.
* *
* @param[in] data Buffer containing the Base64-encoded content. * @param[in] data Buffer containing the Base64-encoded content.
@ -234,14 +235,14 @@ mqtt_client_interface_t;
typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length); typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length);
/* /*
* @brief This function must be provided by the user for the AzureIoT.h layer * @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords. * to perform the generation of the SAS tokens used as MQTT passwords.
* *
* @param[in] data Buffer containing the Base64-decoded content. * @param[in] data Buffer containing the Base64-decoded content.
* @param[in] data_length Length of `data`. * @param[in] data_length Length of `data`.
* @param[in] decoded Buffer where to write the Base64-encoded content of `data`. * @param[in] encoded Buffer where to write the Base64-encoded content of `data`.
* @param[in] decoded_size Size of `encoded`. * @param[in] encoded_size Size of `encoded`.
* @param[out] decoded_length The final length of the Base64-encoded content written in * @param[out] encoded_length The final length of the Base64-encoded content written in
* the `encoded` buffer. * the `encoded` buffer.
* *
* @return int 0 on success, or non-zero if any failure occurs. * @return int 0 on success, or non-zero if any failure occurs.
@ -249,19 +250,19 @@ typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8
typedef int (*base64_encode_function_t)(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length); typedef int (*base64_encode_function_t)(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length);
/* /*
* @brief This function must be provided by the user for the AzureIoT.h layer * @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords. * to perform the generation of the SAS tokens used as MQTT passwords.
* *
* @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm. * @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm.
* @param[in] key_length Length of `key`. * @param[in] key_length Length of `key`.
* @param[in] payload Buffer containing the data to be encrypted. * @param[in] payload Buffer containing the data to be encrypted.
* @param[in] payload_size Size of `payload`. * @param[in] payload_size Size of `payload`.
* @param[in] encrypted_payload Buffer where to write teh HMAC-SHA256 encrypted content of `payload`. * @param[in] encrypted_payload Buffer where to write the HMAC-SHA256 encrypted content of `payload`.
* @param[in] encrypted_payload_size The size of the `encrypted_payload` buffer. * @param[in] encrypted_payload_size The size of the `encrypted_payload` buffer.
* *
* @return int 0 on success, or non-zero if any failure occurs. * @return int 0 on success, or non-zero if any failure occurs.
*/ */
typedef int (*hmac_sha512_encryption_function_t)(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* encrypted_payload, size_t encrypted_payload_size); typedef int (*hmac_sha256_encryption_function_t)(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* encrypted_payload, size_t encrypted_payload_size);
/* /*
* @brief Structure that consolidates all the data manipulation functions. * @brief Structure that consolidates all the data manipulation functions.
@ -270,7 +271,7 @@ typedef struct data_manipulation_functions_t_struct
{ {
base64_decode_function_t base64_decode; base64_decode_function_t base64_decode;
base64_encode_function_t base64_encode; base64_encode_function_t base64_encode;
hmac_sha512_encryption_function_t hmac_sha512_encrypt; hmac_sha256_encryption_function_t hmac_sha256_encrypt;
} }
data_manipulation_functions_t; data_manipulation_functions_t;
@ -295,7 +296,7 @@ typedef void (*properties_update_completed_t)(uint32_t request_id, az_iot_status
typedef void (*properties_received_t)(az_span properties); typedef void (*properties_received_t)(az_span properties);
/* /*
* @brief Structure containing all the details of a Azure Plug and Play Command. * @brief Structure containing all the details of a IoT Plug and Play Command.
*/ */
typedef struct command_request_t_struct typedef struct command_request_t_struct
{ {
@ -323,7 +324,7 @@ typedef struct command_request_t_struct
command_request_t; command_request_t;
/* /*
* @brief Defines the callback for receiving an Azure Plug-and-Play Command. * @brief Defines the callback for receiving an IoT Plug and Play Command.
* @remark A response for this command MUST be provided to Azure by calling * @remark A response for this command MUST be provided to Azure by calling
* `azure_iot_send_command_response`. * `azure_iot_send_command_response`.
* *
@ -335,7 +336,7 @@ command_request_t;
typedef void (*command_request_received_t)(command_request_t command); typedef void (*command_request_received_t)(command_request_t command);
/* /*
* @brief All the possible status returned by `azure_iot_get_status`. * @brief All the possible statuses returned by `azure_iot_get_status`.
*/ */
typedef enum azure_iot_status_t_struct typedef enum azure_iot_status_t_struct
{ {
@ -407,7 +408,7 @@ azure_iot_client_state_t;
* Also make sure that the instance of `azure_iot_config_t` (and its members) do not * Also make sure that the instance of `azure_iot_config_t` (and its members) do not
* lose scope throughout the lifetime of the Azure IoT client. * lose scope throughout the lifetime of the Azure IoT client.
* Most of the members of this structure use az_span for encapsulating a buffer and * Most of the members of this structure use az_span for encapsulating a buffer and
* its size. For more details on az_span, please explorer the code at * its size. For more details on az_span, please explore the code at
* https://github.com/azure/azure-sdk-for-c. * https://github.com/azure/azure-sdk-for-c.
*/ */
typedef struct azure_iot_config_t_struct typedef struct azure_iot_config_t_struct
@ -447,8 +448,8 @@ typedef struct azure_iot_config_t_struct
az_span device_id; az_span device_id;
/* /*
* @brief Symetric key of the device to authenticate as when connecting to Azure IoT Hub. * @brief Symmetric key of the device to authenticate as when connecting to Azure IoT Hub.
* @remark This key will be used to generate the MQTT client password, is using SAS-token * @remark This key will be used to generate the MQTT client password, if using SAS-token
* authentication (which is used, for example, when connecting to Azure IoT Central). * authentication (which is used, for example, when connecting to Azure IoT Central).
*/ */
az_span device_key; az_span device_key;
@ -456,7 +457,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief The "Registration ID" to authenticate with when connecting to * @brief The "Registration ID" to authenticate with when connecting to
* Azure Device Provisioning service. * Azure Device Provisioning service.
* @remark This information only when performing device-provisioning (which is used, * @remark This information is only needed when performing device-provisioning (which is used,
for example, when connecting to Azure IoT Central). If device-provisioning is for example, when connecting to Azure IoT Central). If device-provisioning is
not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub)
this member MUST be set with AZ_SPAN_EMPTY. this member MUST be set with AZ_SPAN_EMPTY.
@ -468,7 +469,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief The "ID Scope" to authenticate with when connecting to * @brief The "ID Scope" to authenticate with when connecting to
* Azure Device Provisioning service. * Azure Device Provisioning service.
* @remark This information only when performing device-provisioning (which is used, * @remark This information is only needed when performing device-provisioning (which is used,
for example, when connecting to Azure IoT Central). If device-provisioning is for example, when connecting to Azure IoT Central). If device-provisioning is
not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub)
this member MUST be set with AZ_SPAN_EMPTY. this member MUST be set with AZ_SPAN_EMPTY.
@ -476,8 +477,8 @@ typedef struct azure_iot_config_t_struct
az_span dps_id_scope; az_span dps_id_scope;
/* /*
* @brief Model ID of the Azure Plug-and-Play template implemented by the user application. * @brief Model ID of the IoT Plug and Play template implemented by the user application.
* @remark This is used only when the application uses/implements Azure IoT Plug-and-Play. * @remark This is used only when the application uses/implements IoT Plug and Play.
*/ */
az_span model_id; az_span model_id;
@ -533,9 +534,9 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief Amount of minutes for which the MQTT password should be valid. * @brief Amount of minutes for which the MQTT password should be valid.
* @remark If set to zero, Azure Iot client sets it to the default value of 60 minutes. * @remark If set to zero, Azure IoT client sets it to the default value of 60 minutes.
* Once this amount of minutes has passed and the MQTT password is expired, * Once this amount of minutes has passed and the MQTT password is expired,
* Azure IoT client trigers its logic to generate a new password and reconnect with * Azure IoT client triggers its logic to generate a new password and reconnect with
* Azure IoT Hub. * Azure IoT Hub.
*/ */
uint32_t sas_token_lifetime_in_minutes; uint32_t sas_token_lifetime_in_minutes;
@ -543,7 +544,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief Callback handler used by Azure IoT client to inform the user application of * @brief Callback handler used by Azure IoT client to inform the user application of
* a completion of properties update. * a completion of properties update.
* @remark A properties update is trigered by the user application when * @remark A properties update is triggered by the user application when
* `azure_iot_send_properties_update` is called. * `azure_iot_send_properties_update` is called.
*/ */
properties_update_completed_t on_properties_update_completed; properties_update_completed_t on_properties_update_completed;
@ -551,7 +552,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief Callback handler used by Azure IoT client to inform the user application of * @brief Callback handler used by Azure IoT client to inform the user application of
* a writable-properties update received from Azure IoT Hub. * a writable-properties update received from Azure IoT Hub.
* @remark If Azure IoT Plug.-and-Play is used, a response must be sent back to * @remark If IoT Plug and Play is used, a response must be sent back to
* Azure IoT Hub. * Azure IoT Hub.
*/ */
properties_received_t on_properties_received; properties_received_t on_properties_received;
@ -590,7 +591,7 @@ typedef struct azure_iot_t_struct
azure_iot_t; azure_iot_t;
/* /*
* @brief Initialies the azure_iot_t structure that holds the Azure IoT client state. * @brief Initializes the azure_iot_t structure that holds the Azure IoT client state.
* @remark This function must be called only once per `azure_iot_t` instance, * @remark This function must be called only once per `azure_iot_t` instance,
* before any other function can be called using it. * before any other function can be called using it.
* *
@ -598,9 +599,9 @@ azure_iot_t;
* @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the * @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the
* configuration neeeded for the client to connect and work with * configuration neeeded for the client to connect and work with
* the Azure IoT services. * the Azure IoT services.
* @return int 0 on success, or non-zero if any failure occurs. * @return Nothing.
*/ */
int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config); void azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config);
/* /*
* @brief Starts an Azure IoT client. * @brief Starts an Azure IoT client.
@ -673,23 +674,23 @@ void azure_iot_do_work(azure_iot_t* azure_iot);
int azure_iot_send_telemetry(azure_iot_t* azure_iot, az_span message); int azure_iot_send_telemetry(azure_iot_t* azure_iot, az_span message);
/** /**
* @brief Checks whether `span` is equal AZ_SPAN_EMPTY. * @brief Sends a property update message to Azure IoT Hub.
* *
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client. * @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] message An `az_span` with the message with the reported properties update * @param[in] request_id An unique identification number to correlate the response with when
* (a JSON document formatted according to the DTDL specification). * @param[in] message An `az_span` with the message with the reported properties update
* `message` gets passed as-is to the MQTT client publish function as the payload, so if * (a JSON document formatted according to the DTDL specification).
* your MQTT client expects a null-terminated string for payload, make sure `message` is * `message` gets passed as-is to the MQTT client publish function as the payload, so if
* a null-terminated string. * your MQTT client expects a null-terminated string for payload, make sure `message` is
* @param[in] request_id An unique identification number to correlate the response with when * a null-terminated string.
* `on_properties_update_completed` (set in azure_iot_config_t) is invoked. * `on_properties_update_completed` (set in azure_iot_config_t) is invoked.
* *
* @return int 0 if the function succeeds, or non-zero if any failure occurs. * @return int 0 if the function succeeds, or non-zero if any failure occurs.
*/ */
int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id, az_span message); int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id, az_span message);
/** /**
* @brief Checks whether `span` is equal AZ_SPAN_EMPTY. * @brief Sends a property update message to Azure IoT Hub.
* *
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client. * @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] request_id The same `request_id` of the device command received from Azure IoT Hub. * @param[in] request_id The same `request_id` of the device command received from Azure IoT Hub.
@ -720,7 +721,7 @@ int azure_iot_mqtt_client_connected(azure_iot_t* azure_iot);
/* /*
* @brief Informs the Azure IoT client that the MQTT client is disconnected. * @brief Informs the Azure IoT client that the MQTT client is disconnected.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit` callback * @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has disconencted * (provided in the azure_iot_config_t instance) so it knows the MQTT client has disconnected
* from the Azure IoT service. * from the Azure IoT service.
* *
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller. * @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
@ -746,7 +747,7 @@ int azure_iot_mqtt_client_subscribe_completed(azure_iot_t* azure_iot, int packet
* @brief Informs the Azure IoT client that the MQTT client has completed a PUBLISH. * @brief Informs the Azure IoT client that the MQTT client has completed a PUBLISH.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_publish` callback * @remark This must be called after Azure IoT client invokes the `mqtt_client_publish` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has * (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* completed a MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by * completed an MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by
* the user application right after `mqtt_client_publish` is invoked. If the QoS of * the user application right after `mqtt_client_publish` is invoked. If the QoS of
* is 1 (AT LEAST ONCE), this shall be called whenever a PUBACK is received. * is 1 (AT LEAST ONCE), this shall be called whenever a PUBACK is received.
* *
@ -776,13 +777,13 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
*/ */
/** /**
* @brief Checks whether `span` is equal AZ_SPAN_EMPTY. * @brief Checks whether `span` is equal to AZ_SPAN_EMPTY.
* *
* @param[in] span A span to be verified. * @param[in] span A span to be verified.
* *
* @return boolean True if `span`'s pointer and size are equal to AZ_SPAN_EMPTY, or false otherwise. * @return boolean True if `span`'s pointer and size are equal to AZ_SPAN_EMPTY, or false otherwise.
*/ */
#define az_span_is_empty(span) az_span_is_content_equal(span, AZ_SPAN_EMPTY) #define is_az_span_empty(span) az_span_is_content_equal(span, AZ_SPAN_EMPTY)
/** /**
* @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to `remainder`. * @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to `remainder`.
@ -793,7 +794,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
* *
* @return az_span A slice of `span` from position zero to `size`. * @return az_span A slice of `span` from position zero to `size`.
*/ */
az_span az_span_split(az_span span, int32_t size, az_span* remainder); az_span split_az_span(az_span span, int32_t size, az_span* remainder);
/** /**
* @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the second through `remainder`. * @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the second through `remainder`.
@ -804,6 +805,6 @@ az_span az_span_split(az_span span, int32_t size, az_span* remainder);
* *
* @return az_span A slice of `destination` with the same size as `source`, with `source`'s content copied over. * @return az_span A slice of `destination` with the same size as `source`, with `source`'s content copied over.
*/ */
static az_span az_span_slice_and_copy(az_span destination, az_span source, az_span* remainder); static az_span slice_and_copy_az_span(az_span destination, az_span source, az_span* remainder);
#endif // AZURE_IOT_H #endif // AZURE_IOT_H

Просмотреть файл

@ -6,9 +6,9 @@
* It uses our Azure Embedded SDK for C to help interact with Azure IoT. * It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/. * For reference, please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/.
* *
* To connect and work with Azure IoT Hub you need a MQTT client, connecting, subscribing * To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub. * and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is a MQTT client support library, helping composing and parsing the * Our azure-sdk-for-c is an MQTT client support library, helping composing and parsing the
* MQTT topic names and messages exchanged with the Azure IoT Hub. * MQTT topic names and messages exchanged with the Azure IoT Hub.
* *
* The additional layers in this sketch provide a structured use of azure-sdk-for-c and * The additional layers in this sketch provide a structured use of azure-sdk-for-c and
@ -22,8 +22,8 @@
* - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding), * - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding),
* - Receive the callbacks for Plug and Play properties and commands. * - Receive the callbacks for Plug and Play properties and commands.
* *
* Azure_IoT_PnP_Template.cpp contains the actual implementation of the Azure Plug-and-Play template * Azure_IoT_PnP_Template.cpp contains the actual implementation of the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board. * specific for the Espressif ESP32 board.
* *
* To properly connect to your Azure IoT services, please fill the information in the `iot_configs.h` file. * To properly connect to your Azure IoT services, please fill the information in the `iot_configs.h` file.
*/ */
@ -197,13 +197,13 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
/* /*
* See the documentation of `mqtt_client_subscribe_function_t` in AzureIoT.h for details. * See the documentation of `mqtt_client_subscribe_function_t` in AzureIoT.h for details.
*/ */
static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handle, const uint8_t* topic, size_t topic_length, mqtt_qos_t qos) static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos)
{ {
LogInfo("MQTT client subscribing to '%s'", topic); LogInfo("MQTT client subscribing to '%.*s'", az_span_size(topic), az_span_ptr(topic));
// As per documentation, `topic` always ends with a null-terminator. // As per documentation, `topic` always ends with a null-terminator.
// esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion is needed. // esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion is needed.
int packet_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)topic, (int)qos); int packet_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)az_span_ptr(topic), (int)qos);
return packet_id; return packet_id;
} }
@ -236,7 +236,7 @@ static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle,
/* --- Other Interface functions required by Azure IoT --- */ /* --- Other Interface functions required by Azure IoT --- */
/* /*
* See the documentation of `hmac_sha512_encryption_function_t` in AzureIoT.h for details. * See the documentation of `hmac_sha256_encryption_function_t` in AzureIoT.h for details.
*/ */
static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* signed_payload, size_t signed_payload_size) static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* signed_payload, size_t signed_payload_size)
{ {
@ -324,7 +324,7 @@ void setup()
/* /*
* The configuration structure used by Azure IoT must remain unchanged (including data buffer) * The configuration structure used by Azure IoT must remain unchanged (including data buffer)
* throughout the lifetime of the sample. This variable must also not loose context so other * throughout the lifetime of the sample. This variable must also not lose context so other
* components do not overwrite any information within this structure. * components do not overwrite any information within this structure.
*/ */
azure_iot_config.user_agent = AZ_SPAN_FROM_STR(AZURE_SDK_CLIENT_USER_AGENT_WORKAROUND); azure_iot_config.user_agent = AZ_SPAN_FROM_STR(AZURE_SDK_CLIENT_USER_AGENT_WORKAROUND);
@ -341,22 +341,17 @@ void setup()
azure_iot_config.mqtt_client_interface.mqtt_client_deinit = mqtt_client_deinit_function; azure_iot_config.mqtt_client_interface.mqtt_client_deinit = mqtt_client_deinit_function;
azure_iot_config.mqtt_client_interface.mqtt_client_subscribe = mqtt_client_subscribe_function; azure_iot_config.mqtt_client_interface.mqtt_client_subscribe = mqtt_client_subscribe_function;
azure_iot_config.mqtt_client_interface.mqtt_client_publish = mqtt_client_publish_function; azure_iot_config.mqtt_client_interface.mqtt_client_publish = mqtt_client_publish_function;
azure_iot_config.data_manipulation_functions.hmac_sha512_encrypt = mbedtls_hmac_sha256; azure_iot_config.data_manipulation_functions.hmac_sha256_encrypt = mbedtls_hmac_sha256;
azure_iot_config.data_manipulation_functions.base64_decode = base64_decode; azure_iot_config.data_manipulation_functions.base64_decode = base64_decode;
azure_iot_config.data_manipulation_functions.base64_encode = base64_encode; azure_iot_config.data_manipulation_functions.base64_encode = base64_encode;
azure_iot_config.on_properties_update_completed = on_properties_update_completed; azure_iot_config.on_properties_update_completed = on_properties_update_completed;
azure_iot_config.on_properties_received = on_properties_received; azure_iot_config.on_properties_received = on_properties_received;
azure_iot_config.on_command_request_received = on_command_request_received; azure_iot_config.on_command_request_received = on_command_request_received;
if (azure_iot_init(&azure_iot, &azure_iot_config) != 0) azure_iot_init(&azure_iot, &azure_iot_config);
{ azure_iot_start(&azure_iot);
LogError("Failed initializing the Azure IoT client.");
} LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state);
else
{
LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state);
azure_iot_start(&azure_iot);
}
} }
void loop() void loop()
@ -445,7 +440,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
int i, r; int i, r;
case MQTT_EVENT_ERROR: case MQTT_EVENT_ERROR:
LogError("MQTT client in ERROR state."); LogError("MQTT client in ERROR state.");
LogError( LogError(
"esp_tls_stack_err=%d; esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_code=%d", "esp_tls_stack_err=%d; esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_code=%d",
event->error_handle->esp_tls_stack_err, event->error_handle->esp_tls_stack_err,
@ -475,7 +470,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED"); LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED");
break; break;
default: default:
LogError("connect_return_code=unknown"); LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code);
break; break;
}; };
@ -537,7 +532,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
LogInfo("MQTT client connecting."); LogInfo("MQTT client connecting.");
break; break;
default: default:
LogError("MQTT event UNKNOWN"); LogError("MQTT event UNKNOWN.");
break; break;
} }

Просмотреть файл

@ -351,7 +351,7 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1) if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1)
{ {
LogError("Insuficient space for telemetry payload null terminator."); LogError("Insufficient space for telemetry payload null terminator.");
return RESULT_ERROR; return RESULT_ERROR;
} }
@ -428,7 +428,7 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1) if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1)
{ {
LogError("Insuficient space for telemetry payload null terminator."); LogError("Insufficient space for telemetry payload null terminator.");
return RESULT_ERROR; return RESULT_ERROR;
} }
@ -526,7 +526,7 @@ static int consume_properties_and_generate_response(
} }
else else
{ {
LogError("Unexpected property received (%.*s)", LogError("Unexpected property received (%.*s).",
az_span_size(jr.token.slice), az_span_ptr(jr.token.slice)); az_span_size(jr.token.slice), az_span_ptr(jr.token.slice));
} }

Просмотреть файл

@ -2,7 +2,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
/* /*
* Azure_IoT_PnP_Template.cpp implements the the Azure Plug-and-Play template * Azure_IoT_PnP_Template.cpp implements the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board. * specific for the Espressif ESP32 Azure IoT Kit board.
*/ */
@ -19,8 +19,8 @@
void azure_pnp_init(); void azure_pnp_init();
/* /*
* @brief Returns the model id of the Azure Plug and Play template implemented by this module. * @brief Returns the model id of the IoT Plug and Play template implemented by this device.
* @remark Every Azure Plug and Play template has a model id that must be informed by the * @remark Every IoT Plug and Play template has a model id that must be informed by the
* device during Azure IoT provisioning and connection with the Azure IoT Hub. * device during Azure IoT provisioning and connection with the Azure IoT Hub.
* @return az_span An `az_span` containing the model id implemented by this module. * @return az_span An `az_span` containing the model id implemented by this module.
*/ */
@ -52,12 +52,12 @@ int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id);
void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds); void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds);
/* /*
* @brief Sends telemetry implemented by this Azure Plug and Play application to Azure IoT Central. * @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT Central.
* @remark The Azure Plug and Play template implemented by this module is specific to the * @remark The IoT Plug and Play template implemented by this device is specific to the
* Espressif ESP32 Azure IoT Kit board, which contains several sensors. * Espressif ESP32 Azure IoT Kit board, which contains several sensors.
* The template defines telemetry data points for temperature, humidity, * The template defines telemetry data points for temperature, humidity,
* pressure, altitude, luminosity, magnetic field, rolling and pitch angles, * pressure, altitude, luminosity, magnetic field, rolling and pitch angles,
* as well as acceleration. All of these data is read from the board sensors and sent to * as well as acceleration. All of these data are read from the board sensors and sent to
* Azure IoT Central when `azure_pnp_send_telemetry` is called. * Azure IoT Central when `azure_pnp_send_telemetry` is called.
* This function must be called frequently enough, no slower than the frequency set * This function must be called frequently enough, no slower than the frequency set
* with `azure_pnp_set_telemetry_frequency` (or the default frequency of 10 seconds). * with `azure_pnp_set_telemetry_frequency` (or the default frequency of 10 seconds).
@ -72,7 +72,7 @@ int azure_pnp_send_telemetry(azure_iot_t* azure_iot);
/* /*
* @brief Handles a command when it is received from Azure IoT Central. * @brief Handles a command when it is received from Azure IoT Central.
* @remark This function will perform the task requested by the command received * @remark This function will perform the task requested by the command received
* (if the command matches the expected name) and send back a response to * (if the command matches the expected name) and sends back a response to
* Azure IoT Central. * Azure IoT Central.
* *
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized * @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized

Просмотреть файл

@ -15,8 +15,8 @@
log_function_t default_logging_function = NULL; log_function_t default_logging_function = NULL;
#endif // DISABLE_LOGGING #endif // DISABLE_LOGGING
/* --- Azure Abstractions --- */ /* --- Azure Definitions --- */
#define IOT_HUB_MQTT_PORT 8883 #define IOT_HUB_MQTT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define MQTT_PROTOCOL_PREFIX "mqtts://" #define MQTT_PROTOCOL_PREFIX "mqtts://"
#define DPS_GLOBAL_ENDPOINT_MQTT_URI MQTT_PROTOCOL_PREFIX DPS_GLOBAL_ENDPOINT_FQDN #define DPS_GLOBAL_ENDPOINT_MQTT_URI MQTT_PROTOCOL_PREFIX DPS_GLOBAL_ENDPOINT_FQDN
#define DPS_GLOBAL_ENDPOINT_MQTT_URI_WITH_PORT DPS_GLOBAL_ENDPOINT_MQTT_URI ":" STR(DPS_GLOBAL_ENDPOINT_PORT) #define DPS_GLOBAL_ENDPOINT_MQTT_URI_WITH_PORT DPS_GLOBAL_ENDPOINT_MQTT_URI ":" STR(DPS_GLOBAL_ENDPOINT_PORT)
@ -32,6 +32,8 @@ log_function_t default_logging_function = NULL;
#define DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN "{\"modelId\":\"" #define DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN "{\"modelId\":\""
#define DPS_REGISTER_CUSTOM_PAYLOAD_END "\"}" #define DPS_REGISTER_CUSTOM_PAYLOAD_END "\"}"
#define NUMBER_OF_SECONDS_IN_A_MINUTE 60
#define EXIT_IF_TRUE(condition, retcode, message, ...) \ #define EXIT_IF_TRUE(condition, retcode, message, ...) \
do \ do \
{ \ { \
@ -71,17 +73,17 @@ static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_clien
static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder); static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder);
#define is_device_provisioned(azure_iot) \ #define is_device_provisioned(azure_iot) \
(!az_span_is_empty(azure_iot->config->iot_hub_fqdn) && !az_span_is_empty(azure_iot->config->device_id)) (!is_az_span_empty(azure_iot->config->iot_hub_fqdn) && !is_az_span_empty(azure_iot->config->device_id))
/* --- Public API --- */ /* --- Public API --- */
int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config) void azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config)
{ {
_az_PRECONDITION_NOT_NULL(azure_iot); _az_PRECONDITION_NOT_NULL(azure_iot);
_az_PRECONDITION_NOT_NULL(azure_iot_config); _az_PRECONDITION_NOT_NULL(azure_iot_config);
if (azure_iot_config->use_device_provisioning) if (azure_iot_config->use_device_provisioning)
{ {
_az_PRECONDITION(az_span_is_empty(azure_iot_config->iot_hub_fqdn)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->iot_hub_fqdn));
_az_PRECONDITION(az_span_is_empty(azure_iot_config->device_id)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->device_id));
_az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_id_scope, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_id_scope, 1, false);
_az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_registration_id, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->dps_registration_id, 1, false);
} }
@ -89,14 +91,14 @@ int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config)
{ {
_az_PRECONDITION_VALID_SPAN(azure_iot_config->iot_hub_fqdn, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->iot_hub_fqdn, 1, false);
_az_PRECONDITION_VALID_SPAN(azure_iot_config->device_id, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->device_id, 1, false);
_az_PRECONDITION(az_span_is_empty(azure_iot_config->dps_id_scope)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->dps_id_scope));
_az_PRECONDITION(az_span_is_empty(azure_iot_config->dps_registration_id)); _az_PRECONDITION(is_az_span_empty(azure_iot_config->dps_registration_id));
} }
_az_PRECONDITION_VALID_SPAN(azure_iot_config->device_key, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->device_key, 1, false);
_az_PRECONDITION_VALID_SPAN(azure_iot_config->data_buffer, 1, false); _az_PRECONDITION_VALID_SPAN(azure_iot_config->data_buffer, 1, false);
_az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_decode); _az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_decode);
_az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_encode); _az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.base64_encode);
_az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.hmac_sha512_encrypt); _az_PRECONDITION_NOT_NULL(azure_iot_config->data_manipulation_functions.hmac_sha256_encrypt);
_az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_init); _az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_init);
_az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_deinit); _az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_deinit);
_az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_subscribe); _az_PRECONDITION_NOT_NULL(azure_iot_config->mqtt_client_interface.mqtt_client_subscribe);
@ -115,8 +117,6 @@ int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config)
{ {
azure_iot->config->sas_token_lifetime_in_minutes = DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES; azure_iot->config->sas_token_lifetime_in_minutes = DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES;
} }
return RESULT_OK;
} }
int azure_iot_start(azure_iot_t* azure_iot) int azure_iot_start(azure_iot_t* azure_iot)
@ -237,7 +237,8 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
size_t length; size_t length;
mqtt_client_config_t mqtt_client_config; mqtt_client_config_t mqtt_client_config;
mqtt_message_t mqtt_message; mqtt_message_t mqtt_message;
az_span data_buffer, dps_register_custom_property; az_span data_buffer;
az_span dps_register_custom_property;
switch (azure_iot->state) switch (azure_iot->state)
{ {
@ -250,7 +251,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
// This seems harmless, but... // This seems harmless, but...
// azure_iot->config->data_buffer always points to the original buffer provided by the user. // azure_iot->config->data_buffer always points to the original buffer provided by the user.
// azure_iot->data_buffer is an intermediate pointer. It starts by pointint to azure_iot->config->data_buffer. // azure_iot->data_buffer is an intermediate pointer. It starts by pointing to azure_iot->config->data_buffer.
// In the steps below the code might need to retain part of azure_iot->data_buffer for saving some critical information, // In the steps below the code might need to retain part of azure_iot->data_buffer for saving some critical information,
// namely the DPS operation id, the provisioned IoT Hub FQDN and provisioned Device ID (if provisioning is being used). // namely the DPS operation id, the provisioned IoT Hub FQDN and provisioned Device ID (if provisioning is being used).
// In these cases, azure_iot->data_buffer will then point to `the remaining available space` of azure_iot->config->data_buffer // In these cases, azure_iot->data_buffer will then point to `the remaining available space` of azure_iot->config->data_buffer
@ -277,6 +278,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed initializing MQTT client."); LogError("Failed initializing MQTT client.");
return;
} }
break; break;
@ -288,14 +290,14 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, azure_iot->mqtt_client_handle,
(const uint8_t*)AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC, AZ_SPAN_FROM_STR(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC),
lengthof(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC),
mqtt_qos_at_most_once); mqtt_qos_at_most_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Device Provisioning respose topic."); LogError("Failed subscribing to Azure Device Provisioning respose topic.");
return;
} }
break; break;
@ -314,19 +316,19 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
return; return;
} }
mqtt_message.topic = az_span_split(data_buffer, length, &data_buffer); mqtt_message.topic = split_az_span(data_buffer, length, &data_buffer);
if (az_span_is_empty(mqtt_message.topic) || az_span_is_empty(data_buffer)) if (is_az_span_empty(mqtt_message.topic) || is_az_span_empty(data_buffer))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed allocating memory for DPS register payload."); LogError("Failed reserving memory for DPS register payload.");
return; return;
} }
dps_register_custom_property = generate_dps_register_custom_property( dps_register_custom_property = generate_dps_register_custom_property(
azure_iot->config->model_id, data_buffer, &mqtt_message.payload); azure_iot->config->model_id, data_buffer, &mqtt_message.payload);
if (az_span_is_empty(dps_register_custom_property)) if (is_az_span_empty(dps_register_custom_property))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed generating DPS register custom property payload."); LogError("Failed generating DPS register custom property payload.");
@ -359,6 +361,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed publishing to DPS registration topic"); LogError("Failed publishing to DPS registration topic");
return;
} }
break; break;
@ -405,6 +408,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed publishing to DPS status query topic"); LogError("Failed publishing to DPS status query topic");
return;
} }
break; break;
@ -437,7 +441,8 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
if (azure_iot->config->mqtt_client_interface.mqtt_client_init(&mqtt_client_config, &azure_iot->mqtt_client_handle) != 0) if (azure_iot->config->mqtt_client_interface.mqtt_client_init(&mqtt_client_config, &azure_iot->mqtt_client_handle) != 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed initializing MQTT client."); LogError("Failed initializing MQTT client for IoT Hub connection.");
return;
} }
break; break;
@ -447,13 +452,15 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_subscribing_to_pnp_cmds; azure_iot->state = azure_iot_state_subscribing_to_pnp_cmds;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, (const uint8_t*)AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC, azure_iot->mqtt_client_handle,
lengthof(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC),
mqtt_qos_at_least_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Plug and Play commands topic."); LogError("Failed subscribing to IoT Plug and Play commands topic.");
return;
} }
break; break;
@ -463,30 +470,33 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_subscribing_to_pnp_props; azure_iot->state = azure_iot_state_subscribing_to_pnp_props;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, (const uint8_t*)AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC, azure_iot->mqtt_client_handle,
lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC),
mqtt_qos_at_least_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Plug and Play properties topic."); LogError("Failed subscribing to IoT Plug and Play properties topic.");
return;
} }
break;
break;
case azure_iot_state_subscribing_to_pnp_props: case azure_iot_state_subscribing_to_pnp_props:
break; break;
case azure_iot_state_subscribed_to_pnp_props: case azure_iot_state_subscribed_to_pnp_props:
azure_iot->state = azure_iot_state_subscribing_to_pnp_writable_props; azure_iot->state = azure_iot_state_subscribing_to_pnp_writable_props;
packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe(
azure_iot->mqtt_client_handle, (const uint8_t*)AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC, azure_iot->mqtt_client_handle,
lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC),
mqtt_qos_at_least_once);
if (packet_id < 0) if (packet_id < 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed subscribing to Azure Plug and Play writable properties topic."); LogError("Failed subscribing to IoT Plug and Play writable properties topic.");
return;
} }
break; break;
@ -501,13 +511,14 @@ void azure_iot_do_work(azure_iot_t* azure_iot)
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed getting current time for checking SAS token expiration."); LogError("Failed getting current time for checking SAS token expiration.");
} }
else if ((azure_iot->sas_token_expiration_time - now) < SAS_TOKEN_REFRESH_THRESHOLD_SECS) else if ((azure_iot->sas_token_expiration_time - now) < SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS)
{ {
azure_iot->state = azure_iot_state_refreshing_sas; azure_iot->state = azure_iot_state_refreshing_sas;
if (azure_iot->config->mqtt_client_interface.mqtt_client_deinit(&azure_iot->mqtt_client_handle) != 0) if (azure_iot->config->mqtt_client_interface.mqtt_client_deinit(&azure_iot->mqtt_client_handle) != 0)
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed de-initializing MQTT client."); LogError("Failed de-initializing MQTT client.");
return;
} }
} }
break; break;
@ -559,7 +570,7 @@ int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id
azr = az_iot_hub_client_properties_get_reported_publish_topic( azr = az_iot_hub_client_properties_get_reported_publish_topic(
&azure_iot->iot_hub_client, request_id_span, (char*)az_span_ptr(data_buffer), az_span_size(data_buffer), &topic_length); &azure_iot->iot_hub_client, request_id_span, (char*)az_span_ptr(data_buffer), az_span_size(data_buffer), &topic_length);
EXIT_IF_AZ_FAILED(azr, RESULT_ERROR, "Failed to get the repoted properties publish topic"); EXIT_IF_AZ_FAILED(azr, RESULT_ERROR, "Failed to get the reported properties publish topic");
mqtt_message.topic = az_span_slice(data_buffer, 0, topic_length); mqtt_message.topic = az_span_slice(data_buffer, 0, topic_length);
mqtt_message.payload = message; mqtt_message.payload = message;
@ -690,7 +701,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
{ {
// This message should either be: // This message should either be:
// - a response to a properties update request, or // - a response to a properties update request, or
// - a response to a get properties request, or // - a response to a "get" properties request, or
// - a command request. // - a command request.
az_iot_hub_client_properties_message property_message; az_iot_hub_client_properties_message property_message;
@ -725,7 +736,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
if (az_result_failed(az_span_atou32(property_message.request_id, &request_id))) if (az_result_failed(az_span_atou32(property_message.request_id, &request_id)))
{ {
LogError("Failed parsing properties update request id (%.*s)", LogError("Failed parsing properties update request id (%.*s).",
az_span_size(property_message.request_id), az_span_ptr(property_message.request_id)); az_span_size(property_message.request_id), az_span_ptr(property_message.request_id));
result = RESULT_ERROR; result = RESULT_ERROR;
} }
@ -789,14 +800,14 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
{ {
result = RESULT_OK; result = RESULT_OK;
if (az_span_is_empty(azure_iot->dps_operation_id)) if (is_az_span_empty(azure_iot->dps_operation_id))
{ {
azure_iot->dps_operation_id = az_span_slice_and_copy(azure_iot->data_buffer, register_response.operation_id, &azure_iot->data_buffer); azure_iot->dps_operation_id = slice_and_copy_az_span(azure_iot->data_buffer, register_response.operation_id, &azure_iot->data_buffer);
if (az_span_is_empty(azure_iot->dps_operation_id)) if (is_az_span_empty(azure_iot->dps_operation_id))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed allocating memory for DPS operation id."); LogError("Failed reserving memory for DPS operation id.");
result = RESULT_ERROR; result = RESULT_ERROR;
} }
} }
@ -812,9 +823,9 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
az_span data_buffer = azure_iot->config->data_buffer; // Operation ID is no longer needed. az_span data_buffer = azure_iot->config->data_buffer; // Operation ID is no longer needed.
azure_iot->data_buffer = data_buffer; // In case any step below fails. azure_iot->data_buffer = data_buffer; // In case any step below fails.
azure_iot->config->iot_hub_fqdn = az_span_slice_and_copy(data_buffer, register_response.registration_state.assigned_hub_hostname, &data_buffer); azure_iot->config->iot_hub_fqdn = slice_and_copy_az_span(data_buffer, register_response.registration_state.assigned_hub_hostname, &data_buffer);
if (az_span_is_empty(azure_iot->config->iot_hub_fqdn)) if (is_az_span_empty(azure_iot->config->iot_hub_fqdn))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed saving IoT Hub fqdn from provisioning."); LogError("Failed saving IoT Hub fqdn from provisioning.");
@ -822,9 +833,9 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
} }
else else
{ {
azure_iot->config->device_id = az_span_slice_and_copy(data_buffer, register_response.registration_state.device_id, &data_buffer); azure_iot->config->device_id = slice_and_copy_az_span(data_buffer, register_response.registration_state.device_id, &data_buffer);
if (az_span_is_empty(azure_iot->config->device_id)) if (is_az_span_empty(azure_iot->config->device_id))
{ {
azure_iot->state = azure_iot_state_error; azure_iot->state = azure_iot_state_error;
LogError("Failed saving device id from provisioning."); LogError("Failed saving device id from provisioning.");
@ -848,7 +859,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
} }
else else
{ {
LogError("No PUBLISH notification expected"); LogError("No PUBLISH notification expected.");
result = RESULT_ERROR; result = RESULT_ERROR;
} }
@ -870,7 +881,7 @@ int azure_iot_send_command_response(azure_iot_t* azure_iot, az_span request_id,
azrc = az_iot_hub_client_commands_response_get_publish_topic( azrc = az_iot_hub_client_commands_response_get_publish_topic(
&azure_iot->iot_hub_client, request_id, response_status, &azure_iot->iot_hub_client, request_id, response_status,
(char*)az_span_ptr(mqtt_message.topic), az_span_size(mqtt_message.topic), &topic_length); (char*)az_span_ptr(mqtt_message.topic), az_span_size(mqtt_message.topic), &topic_length);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed to get the commands response topic"); EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed to get the commands response topic.");
mqtt_message.topic = az_span_slice(mqtt_message.topic, 0, topic_length); mqtt_message.topic = az_span_slice(mqtt_message.topic, 0, topic_length);
mqtt_message.payload = payload; mqtt_message.payload = payload;
@ -903,7 +914,7 @@ static uint32_t get_current_unix_time()
} }
/* /*
* @brief Initializes the Device Provisioning client and generates the config for a MQTT client. * @brief Initializes the Device Provisioning client and generates the config for an MQTT client.
* @param[in] azure_iot A pointer to an initialized instance of azure_iot_t. * @param[in] azure_iot A pointer to an initialized instance of azure_iot_t.
* @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for * @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for
* creating and connecting an MQTT client to Azure Device Provisioning service. * creating and connecting an MQTT client to Azure Device Provisioning service.
@ -912,8 +923,13 @@ static uint32_t get_current_unix_time()
*/ */
static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config) static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config)
{ {
az_span data_buffer_span, client_id_span, username_span, password_span; az_span data_buffer_span;
size_t client_id_length, username_length, password_length; az_span client_id_span;
az_span username_span;
az_span password_span;
size_t client_id_length;
size_t username_length;
size_t password_length;
az_result azrc; az_result azrc;
azrc = az_iot_provisioning_client_init( azrc = az_iot_provisioning_client_init(
@ -926,8 +942,8 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
data_buffer_span = azure_iot->data_buffer; data_buffer_span = azure_iot->data_buffer;
password_span = az_span_split(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span); password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(password_span), RESULT_ERROR, "Failed allocating buffer for password_span."); EXIT_IF_TRUE(is_az_span_empty(password_span), RESULT_ERROR, "Failed reserving buffer for password_span.");
password_length = generate_sas_token_for_dps( password_length = generate_sas_token_for_dps(
&azure_iot->dps_client, &azure_iot->dps_client,
@ -939,14 +955,14 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
&azure_iot->sas_token_expiration_time); &azure_iot->sas_token_expiration_time);
EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for DPS connection."); EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for DPS connection.");
client_id_span = az_span_split(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span); client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); EXIT_IF_TRUE(is_az_span_empty(client_id_span), RESULT_ERROR, "Failed reserving buffer for client_id_span.");
azrc = az_iot_provisioning_client_get_client_id( azrc = az_iot_provisioning_client_get_client_id(
&azure_iot->dps_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length); &azure_iot->dps_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for DPS connection."); EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for DPS connection.");
username_span = az_span_split(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span); username_span = split_az_span(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span);
azrc = az_iot_provisioning_client_get_user_name( azrc = az_iot_provisioning_client_get_user_name(
&azure_iot->dps_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length); &azure_iot->dps_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length);
@ -963,7 +979,7 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
} }
/* /*
* @brief Initializes the Azure IoT Hub client and generates the config for a MQTT client. * @brief Initializes the Azure IoT Hub client and generates the config for an MQTT client.
* @param[in] azure_iot A pointer to an initialized instance of azure_iot_t. * @param[in] azure_iot A pointer to an initialized instance of azure_iot_t.
* @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for * @param[in] mqtt_client_config A pointer to a generic structure to contain the configuration for
* creating and connecting an MQTT client to Azure IoT Hub. * creating and connecting an MQTT client to Azure IoT Hub.
@ -972,8 +988,13 @@ static int get_mqtt_client_config_for_dps(azure_iot_t* azure_iot, mqtt_client_co
*/ */
static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config) static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_client_config_t* mqtt_client_config)
{ {
az_span data_buffer_span, client_id_span, username_span, password_span; az_span data_buffer_span;
size_t client_id_length, username_length, password_length; az_span client_id_span;
az_span username_span;
az_span password_span;
size_t client_id_length;
size_t username_length;
size_t password_length;
az_result azrc; az_result azrc;
azure_iot->iot_hub_client_options = az_iot_hub_client_options_default(); azure_iot->iot_hub_client_options = az_iot_hub_client_options_default();
@ -989,8 +1010,8 @@ static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_clien
data_buffer_span = azure_iot->data_buffer; data_buffer_span = azure_iot->data_buffer;
password_span = az_span_split(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span); password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(password_span), RESULT_ERROR, "Failed allocating buffer for password_span."); EXIT_IF_TRUE(is_az_span_empty(password_span), RESULT_ERROR, "Failed reserving buffer for password_span.");
password_length = generate_sas_token_for_iot_hub( password_length = generate_sas_token_for_iot_hub(
&azure_iot->iot_hub_client, &azure_iot->iot_hub_client,
@ -1002,14 +1023,14 @@ static int get_mqtt_client_config_for_iot_hub(azure_iot_t* azure_iot, mqtt_clien
&azure_iot->sas_token_expiration_time); &azure_iot->sas_token_expiration_time);
EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for IoT Hub connection."); EXIT_IF_TRUE(password_length == 0, RESULT_ERROR, "Failed creating mqtt password for IoT Hub connection.");
client_id_span = az_span_split(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span); client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); EXIT_IF_TRUE(is_az_span_empty(client_id_span), RESULT_ERROR, "Failed reserving buffer for client_id_span.");
azrc = az_iot_hub_client_get_client_id( azrc = az_iot_hub_client_get_client_id(
&azure_iot->iot_hub_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length); &azure_iot->iot_hub_client, (char*)az_span_ptr(client_id_span), az_span_size(client_id_span), &client_id_length);
EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for IoT Hub connection."); EXIT_IF_AZ_FAILED(azrc, RESULT_ERROR, "Failed getting client id for IoT Hub connection.");
username_span = az_span_split(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span); username_span = split_az_span(data_buffer_span, MQTT_USERNAME_BUFFER_SIZE, &data_buffer_span);
azrc = az_iot_hub_client_get_user_name( azrc = az_iot_hub_client_get_user_name(
&azure_iot->iot_hub_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length); &azure_iot->iot_hub_client, (char*)az_span_ptr(username_span), az_span_size(username_span), &username_length);
@ -1064,32 +1085,32 @@ static int generate_sas_token_for_dps(
current_unix_time = get_current_unix_time(); current_unix_time = get_current_unix_time();
EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time."); EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time.");
*expiration_time = current_unix_time + duration_in_minutes * 60; *expiration_time = current_unix_time + duration_in_minutes * NUMBER_OF_SECONDS_IN_A_MINUTE;
// Step 2.a. // Step 2.a.
plain_sas_signature = az_span_split(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(plain_sas_signature), 0, "Failed allocating buffer for plain sas token."); EXIT_IF_TRUE(is_az_span_empty(plain_sas_signature), 0, "Failed reserving buffer for plain sas token.");
rc = az_iot_provisioning_client_sas_get_signature( rc = az_iot_provisioning_client_sas_get_signature(
provisioning_client, *expiration_time, plain_sas_signature, &plain_sas_signature); provisioning_client, *expiration_time, plain_sas_signature, &plain_sas_signature);
EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key"); EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key.");
// Step 2.b. // Step 2.b.
sas_signature = az_span_split(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_signature), 0, "Failed allocating buffer for sas_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_signature), 0, "Failed reserving buffer for sas_signature.");
decoded_sas_key = az_span_split(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key.");
result = data_manipulation_functions.base64_decode( result = data_manipulation_functions.base64_decode(
az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length); az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length);
EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key.");
// Step 2.c. // Step 2.c.
sas_hmac256_signed_signature = az_span_split(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_hmac256_signed_signature), 0, "Failed allocating buffer for sas_hmac256_signed_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_hmac256_signed_signature), 0, "Failed reserving buffer for sas_hmac256_signed_signature.");
result = data_manipulation_functions.hmac_sha512_encrypt( result = data_manipulation_functions.hmac_sha256_encrypt(
az_span_ptr(decoded_sas_key), decoded_sas_key_length, az_span_ptr(decoded_sas_key), decoded_sas_key_length,
az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature), az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature),
az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature)); az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature));
@ -1155,32 +1176,32 @@ static int generate_sas_token_for_iot_hub(
current_unix_time = get_current_unix_time(); current_unix_time = get_current_unix_time();
EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time."); EXIT_IF_TRUE(current_unix_time == 0, 0, "Failed getting current unix time.");
*expiration_time = current_unix_time + duration_in_minutes * 60; *expiration_time = current_unix_time + duration_in_minutes * NUMBER_OF_SECONDS_IN_A_MINUTE;
// Step 2.a. // Step 2.a.
plain_sas_signature = az_span_split(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(plain_sas_signature), 0, "Failed allocating buffer for plain sas token."); EXIT_IF_TRUE(is_az_span_empty(plain_sas_signature), 0, "Failed reserving buffer for plain sas token.");
rc = az_iot_hub_client_sas_get_signature( rc = az_iot_hub_client_sas_get_signature(
iot_hub_client, *expiration_time, plain_sas_signature, &plain_sas_signature); iot_hub_client, *expiration_time, plain_sas_signature, &plain_sas_signature);
EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key"); EXIT_IF_AZ_FAILED(rc, 0, "Could not get the signature for SAS key.");
// Step 2.b. // Step 2.b.
sas_signature = az_span_split(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_signature), 0, "Failed allocating buffer for sas_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_signature), 0, "Failed reserving buffer for sas_signature.");
decoded_sas_key = az_span_split(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key.");
result = data_manipulation_functions.base64_decode( result = data_manipulation_functions.base64_decode(
az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length); az_span_ptr(device_key), az_span_size(device_key), az_span_ptr(decoded_sas_key), az_span_size(decoded_sas_key), &decoded_sas_key_length);
EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key.");
// Step 2.c. // Step 2.c.
sas_hmac256_signed_signature = az_span_split(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span);
EXIT_IF_TRUE(az_span_is_empty(sas_hmac256_signed_signature), 0, "Failed allocating buffer for sas_hmac256_signed_signature."); EXIT_IF_TRUE(is_az_span_empty(sas_hmac256_signed_signature), 0, "Failed reserving buffer for sas_hmac256_signed_signature.");
result = data_manipulation_functions.hmac_sha512_encrypt( result = data_manipulation_functions.hmac_sha256_encrypt(
az_span_ptr(decoded_sas_key), decoded_sas_key_length, az_span_ptr(decoded_sas_key), decoded_sas_key_length,
az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature), az_span_ptr(plain_sas_signature), az_span_size(plain_sas_signature),
az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature)); az_span_ptr(sas_hmac256_signed_signature), az_span_size(sas_hmac256_signed_signature));
@ -1207,32 +1228,45 @@ static int generate_sas_token_for_iot_hub(
return mqtt_password_length; return mqtt_password_length;
} }
/**
* @brief Generates a custom payload for DPS registration request containing the Azure PnP model ID.
* @remark This payload with the model ID is required for Azure IoT Central to properly
* assign the IoT Plug and Play template.
*
* @param[in] mode_id The string with the IoT Plug and Play model ID.
* @param[in] data_buffer Buffer where to write the resulting payload.
* @param[in] remainder The remainder space of `data_buffer` after enough is reserved for
* the resulting payload.
*
* @return az_span An az_span (reserved from `data_buffer`) containing the payload
* for the DPS registration request.
*/
static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder) static az_span generate_dps_register_custom_property(az_span model_id, az_span data_buffer, az_span* remainder)
{ {
az_span custom_property; az_span custom_property;
size_t length = lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN) + az_span_size(model_id) + lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_END); size_t length = lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN) + az_span_size(model_id) + lengthof(DPS_REGISTER_CUSTOM_PAYLOAD_END);
custom_property = az_span_split(data_buffer, length, remainder); custom_property = split_az_span(data_buffer, length, remainder);
EXIT_IF_TRUE(az_span_is_empty(custom_property), AZ_SPAN_EMPTY, "Failed generating DPS register custom property."); EXIT_IF_TRUE(is_az_span_empty(custom_property), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (not enough space).");
data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN)); data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN));
EXIT_IF_TRUE(az_span_is_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (prefix)."); EXIT_IF_TRUE(is_az_span_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (prefix).");
data_buffer = az_span_copy(data_buffer, model_id); data_buffer = az_span_copy(data_buffer, model_id);
EXIT_IF_TRUE(az_span_is_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (model id)."); EXIT_IF_TRUE(is_az_span_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (model id).");
data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_END)); data_buffer = az_span_copy(data_buffer, AZ_SPAN_FROM_STR(DPS_REGISTER_CUSTOM_PAYLOAD_END));
EXIT_IF_TRUE(az_span_is_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (suffix)."); EXIT_IF_TRUE(is_az_span_empty(data_buffer), AZ_SPAN_EMPTY, "Failed generating DPS register custom property (suffix).");
return custom_property; return custom_property;
} }
/* --- az_core extensions --- */ /* --- az_core extensions --- */
az_span az_span_split(az_span span, int32_t size, az_span* remainder) az_span split_az_span(az_span span, int32_t size, az_span* remainder)
{ {
az_span result = az_span_slice(span, 0, size); az_span result = az_span_slice(span, 0, size);
if (remainder != NULL && !az_span_is_empty(result)) if (remainder != NULL && !is_az_span_empty(result))
{ {
*remainder = az_span_slice(span, size, az_span_size(span)); *remainder = az_span_slice(span, size, az_span_size(span));
} }
@ -1240,16 +1274,16 @@ az_span az_span_split(az_span span, int32_t size, az_span* remainder)
return result; return result;
} }
az_span az_span_slice_and_copy(az_span destination, az_span source, az_span* remainder) az_span slice_and_copy_az_span(az_span destination, az_span source, az_span* remainder)
{ {
az_span result = az_span_split(destination, az_span_size(source), remainder); az_span result = split_az_span(destination, az_span_size(source), remainder);
if (az_span_is_empty(*remainder)) if (is_az_span_empty(*remainder))
{ {
result = AZ_SPAN_EMPTY; result = AZ_SPAN_EMPTY;
} }
if (!az_span_is_empty(result)) if (!is_az_span_empty(result))
{ {
(void)az_span_copy(result, source); (void)az_span_copy(result, source);
} }

Просмотреть файл

@ -2,8 +2,10 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
/* /*
* AzureIoT.cpp contains a state machine that implements those steps, plus abstractions to simplify * AzureIoT.cpp contains a state machine that implements the necessary calls to azure-sdk-for-c
* its overall use. Besides the basic configuration needed to access the Azure IoT services, * for aiding to connect and work with Azure IoT services, plus abstractions to
* simplify overall use of azure-sdk-for-c.
* Besides the basic configuration needed to access the Azure IoT services,
* all that is needed is to provide the functions required by that layer to: * all that is needed is to provide the functions required by that layer to:
* - Interact with your MQTT client, * - Interact with your MQTT client,
* - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding), * - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding),
@ -57,13 +59,13 @@ extern log_function_t default_logging_function;
#endif // DISABLE_LOGGING #endif // DISABLE_LOGGING
/* --- Azure Abstraction --- */ /* --- Azure Definitions --- */
#define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net" #define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net"
#define DPS_GLOBAL_ENDPOINT_PORT 8883 #define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define IOT_HUB_ENDPOINT_PORT 8883 #define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT
#define DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES 60 #define DEFAULT_SAS_TOKEN_LIFETIME_IN_MINUTES 60
#define SAS_TOKEN_REFRESH_THRESHOLD_SECS 30 #define SAS_TOKEN_REFRESH_THRESHOLD_IN_SECS 30
/* /*
* The structures below define a generic interface to abstract the interaction of this module, * The structures below define a generic interface to abstract the interaction of this module,
@ -83,12 +85,13 @@ typedef enum mqtt_qos_t_enum
mqtt_qos_t; mqtt_qos_t;
/* /*
* @brief Defines a generic MQTT message to be exchanged between the AzureIoT.h layer * @brief Defines a generic MQTT message to be exchanged between the AzureIoT layer
* and the user application. * and the user application.
* @remark It uses azure-sdk-for-c's az_span construct, which is merely a structure that * @remark It uses azure-sdk-for-c's az_span construct, which is merely a structure that
* has a pointer to a buffer and its size. Messages without a payload will have * has a pointer to a buffer and its size. Messages without a payload will have
* the `payload` member set to AZ_SPAN_EMPTY. * the `payload` member set to AZ_SPAN_EMPTY.
* Please see the az_span.h in azure-sdk-for-c for more details. * Please see the az_span.h in azure-sdk-for-c for more details at
* https://azuresdkdocs.blob.core.windows.net/$web/c/az_core/1.2.0/az__span_8h.html
*/ */
typedef struct mqtt_message_t_struct typedef struct mqtt_message_t_struct
{ {
@ -105,12 +108,12 @@ mqtt_message_t;
typedef struct mqtt_client_config_t_struct typedef struct mqtt_client_config_t_struct
{ {
/* /*
* @brief FQDN address of the broker the MQTT client shall connect to. * @brief FQDN address of the broker that the MQTT client shall connect to.
*/ */
az_span address; az_span address;
/* /*
* @brief Port of the broker the MQTT client shall connect to. * @brief Port of the broker that the MQTT client shall connect to.
*/ */
int port; int port;
@ -133,12 +136,12 @@ mqtt_client_config_t;
/* /*
* @brief Generic pointer to the actual instance of the application MQTT client. * @brief Generic pointer to the actual instance of the application MQTT client.
* @remark set by the user application when the `mqtt_client_init_function_t` calback is invoked. * @remark set by the user application when the `mqtt_client_init_function_t` callback is invoked.
*/ */
typedef void* mqtt_client_handle_t; typedef void* mqtt_client_handle_t;
/* /*
* @brief Function to initialize and connect a MQTT client. * @brief Function to initialize and connect an MQTT client.
* @remark When this function is called, it provides the information necessary to initialize a * @remark When this function is called, it provides the information necessary to initialize a
* specific MQTT client (whichever is used by the user application). In this callback * specific MQTT client (whichever is used by the user application). In this callback
* it is expected that the MQTT client will be created/initialized, started and that it * it is expected that the MQTT client will be created/initialized, started and that it
@ -155,7 +158,7 @@ typedef void* mqtt_client_handle_t;
typedef int (*mqtt_client_init_function_t)(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t* mqtt_client_handle); typedef int (*mqtt_client_init_function_t)(mqtt_client_config_t* mqtt_client_config, mqtt_client_handle_t* mqtt_client_handle);
/* /*
* @brief Function to disconnect and deinitialize a MQTT client. * @brief Function to disconnect and deinitialize an MQTT client.
* @remark When this function is called the MQTT client instance referenced by `mqtt_client_handle` shall disconnect * @remark When this function is called the MQTT client instance referenced by `mqtt_client_handle` shall disconnect
* from the server and any functions of the MQTT client API that destroy the instance shall be called * from the server and any functions of the MQTT client API that destroy the instance shall be called
* (so any allocated memory resources can be released). * (so any allocated memory resources can be released).
@ -193,10 +196,8 @@ typedef int (*mqtt_client_publish_function_t)(mqtt_client_handle_t mqtt_client_h
* `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to subscribe to * `mqtt_client_handle`) to invoke the appropriate function in the MQTT client API to subscribe to
* an MQTT topic. * an MQTT topic.
* *
* @param[in] topic The string containing the complete MQTT topic name to subscribed to. * @param[in] topic The az_span with the string containing the complete MQTT topic name to subscribed to.
* This string is always NULL-terminated. * This string is always NULL-terminated.
* @param[in] topic_length The length of `topic`. It can be used in case the MQTT client takes a
* topic name as a non-NULL-terminated string.
* @param[in] qos MQTT QoS to be used for the topic subscription. * @param[in] qos MQTT QoS to be used for the topic subscription.
* *
* *
@ -204,7 +205,7 @@ typedef int (*mqtt_client_publish_function_t)(mqtt_client_handle_t mqtt_client_h
* Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called once the * Azure IoT client expects `azure_iot_mqtt_client_subscribe_completed` to be called once the
* MQTT client receives a SUBACK. * MQTT client receives a SUBACK.
*/ */
typedef int (*mqtt_client_subscribe_function_t)(mqtt_client_handle_t mqtt_client_handle, const uint8_t* topic, size_t topic_lenght, mqtt_qos_t qos); typedef int (*mqtt_client_subscribe_function_t)(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos);
/* /*
* @brief Structure that consolidates all the abstracted MQTT functions. * @brief Structure that consolidates all the abstracted MQTT functions.
@ -213,13 +214,13 @@ typedef struct mqtt_client_interface_t_struct
{ {
mqtt_client_init_function_t mqtt_client_init; mqtt_client_init_function_t mqtt_client_init;
mqtt_client_deinit_function_t mqtt_client_deinit; mqtt_client_deinit_function_t mqtt_client_deinit;
mqtt_client_subscribe_function_t mqtt_client_subscribe;
mqtt_client_publish_function_t mqtt_client_publish; mqtt_client_publish_function_t mqtt_client_publish;
mqtt_client_subscribe_function_t mqtt_client_subscribe;
} }
mqtt_client_interface_t; mqtt_client_interface_t;
/* /*
* @brief This function must be provided by the user for the AzureIoT.h layer * @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords. * to perform the generation of the SAS tokens used as MQTT passwords.
* *
* @param[in] data Buffer containing the Base64-encoded content. * @param[in] data Buffer containing the Base64-encoded content.
@ -234,14 +235,14 @@ mqtt_client_interface_t;
typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length); typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8_t* decoded, size_t decoded_size, size_t* decoded_length);
/* /*
* @brief This function must be provided by the user for the AzureIoT.h layer * @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords. * to perform the generation of the SAS tokens used as MQTT passwords.
* *
* @param[in] data Buffer containing the Base64-decoded content. * @param[in] data Buffer containing the Base64-decoded content.
* @param[in] data_length Length of `data`. * @param[in] data_length Length of `data`.
* @param[in] decoded Buffer where to write the Base64-encoded content of `data`. * @param[in] encoded Buffer where to write the Base64-encoded content of `data`.
* @param[in] decoded_size Size of `encoded`. * @param[in] encoded_size Size of `encoded`.
* @param[out] decoded_length The final length of the Base64-encoded content written in * @param[out] encoded_length The final length of the Base64-encoded content written in
* the `encoded` buffer. * the `encoded` buffer.
* *
* @return int 0 on success, or non-zero if any failure occurs. * @return int 0 on success, or non-zero if any failure occurs.
@ -249,19 +250,19 @@ typedef int (*base64_decode_function_t)(uint8_t* data, size_t data_length, uint8
typedef int (*base64_encode_function_t)(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length); typedef int (*base64_encode_function_t)(uint8_t* data, size_t data_length, uint8_t* encoded, size_t encoded_size, size_t* encoded_length);
/* /*
* @brief This function must be provided by the user for the AzureIoT.h layer * @brief This function must be provided by the user for the AzureIoT layer
* to perform the generation of the SAS tokens used as MQTT passwords. * to perform the generation of the SAS tokens used as MQTT passwords.
* *
* @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm. * @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm.
* @param[in] key_length Length of `key`. * @param[in] key_length Length of `key`.
* @param[in] payload Buffer containing the data to be encrypted. * @param[in] payload Buffer containing the data to be encrypted.
* @param[in] payload_size Size of `payload`. * @param[in] payload_size Size of `payload`.
* @param[in] encrypted_payload Buffer where to write teh HMAC-SHA256 encrypted content of `payload`. * @param[in] encrypted_payload Buffer where to write the HMAC-SHA256 encrypted content of `payload`.
* @param[in] encrypted_payload_size The size of the `encrypted_payload` buffer. * @param[in] encrypted_payload_size The size of the `encrypted_payload` buffer.
* *
* @return int 0 on success, or non-zero if any failure occurs. * @return int 0 on success, or non-zero if any failure occurs.
*/ */
typedef int (*hmac_sha512_encryption_function_t)(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* encrypted_payload, size_t encrypted_payload_size); typedef int (*hmac_sha256_encryption_function_t)(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* encrypted_payload, size_t encrypted_payload_size);
/* /*
* @brief Structure that consolidates all the data manipulation functions. * @brief Structure that consolidates all the data manipulation functions.
@ -270,7 +271,7 @@ typedef struct data_manipulation_functions_t_struct
{ {
base64_decode_function_t base64_decode; base64_decode_function_t base64_decode;
base64_encode_function_t base64_encode; base64_encode_function_t base64_encode;
hmac_sha512_encryption_function_t hmac_sha512_encrypt; hmac_sha256_encryption_function_t hmac_sha256_encrypt;
} }
data_manipulation_functions_t; data_manipulation_functions_t;
@ -295,7 +296,7 @@ typedef void (*properties_update_completed_t)(uint32_t request_id, az_iot_status
typedef void (*properties_received_t)(az_span properties); typedef void (*properties_received_t)(az_span properties);
/* /*
* @brief Structure containing all the details of a Azure Plug and Play Command. * @brief Structure containing all the details of a IoT Plug and Play Command.
*/ */
typedef struct command_request_t_struct typedef struct command_request_t_struct
{ {
@ -323,7 +324,7 @@ typedef struct command_request_t_struct
command_request_t; command_request_t;
/* /*
* @brief Defines the callback for receiving an Azure Plug-and-Play Command. * @brief Defines the callback for receiving an IoT Plug and Play Command.
* @remark A response for this command MUST be provided to Azure by calling * @remark A response for this command MUST be provided to Azure by calling
* `azure_iot_send_command_response`. * `azure_iot_send_command_response`.
* *
@ -335,7 +336,7 @@ command_request_t;
typedef void (*command_request_received_t)(command_request_t command); typedef void (*command_request_received_t)(command_request_t command);
/* /*
* @brief All the possible status returned by `azure_iot_get_status`. * @brief All the possible statuses returned by `azure_iot_get_status`.
*/ */
typedef enum azure_iot_status_t_struct typedef enum azure_iot_status_t_struct
{ {
@ -407,7 +408,7 @@ azure_iot_client_state_t;
* Also make sure that the instance of `azure_iot_config_t` (and its members) do not * Also make sure that the instance of `azure_iot_config_t` (and its members) do not
* lose scope throughout the lifetime of the Azure IoT client. * lose scope throughout the lifetime of the Azure IoT client.
* Most of the members of this structure use az_span for encapsulating a buffer and * Most of the members of this structure use az_span for encapsulating a buffer and
* its size. For more details on az_span, please explorer the code at * its size. For more details on az_span, please explore the code at
* https://github.com/azure/azure-sdk-for-c. * https://github.com/azure/azure-sdk-for-c.
*/ */
typedef struct azure_iot_config_t_struct typedef struct azure_iot_config_t_struct
@ -447,8 +448,8 @@ typedef struct azure_iot_config_t_struct
az_span device_id; az_span device_id;
/* /*
* @brief Symetric key of the device to authenticate as when connecting to Azure IoT Hub. * @brief Symmetric key of the device to authenticate as when connecting to Azure IoT Hub.
* @remark This key will be used to generate the MQTT client password, is using SAS-token * @remark This key will be used to generate the MQTT client password, if using SAS-token
* authentication (which is used, for example, when connecting to Azure IoT Central). * authentication (which is used, for example, when connecting to Azure IoT Central).
*/ */
az_span device_key; az_span device_key;
@ -456,7 +457,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief The "Registration ID" to authenticate with when connecting to * @brief The "Registration ID" to authenticate with when connecting to
* Azure Device Provisioning service. * Azure Device Provisioning service.
* @remark This information only when performing device-provisioning (which is used, * @remark This information is only needed when performing device-provisioning (which is used,
for example, when connecting to Azure IoT Central). If device-provisioning is for example, when connecting to Azure IoT Central). If device-provisioning is
not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub)
this member MUST be set with AZ_SPAN_EMPTY. this member MUST be set with AZ_SPAN_EMPTY.
@ -468,7 +469,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief The "ID Scope" to authenticate with when connecting to * @brief The "ID Scope" to authenticate with when connecting to
* Azure Device Provisioning service. * Azure Device Provisioning service.
* @remark This information only when performing device-provisioning (which is used, * @remark This information is only needed when performing device-provisioning (which is used,
for example, when connecting to Azure IoT Central). If device-provisioning is for example, when connecting to Azure IoT Central). If device-provisioning is
not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub)
this member MUST be set with AZ_SPAN_EMPTY. this member MUST be set with AZ_SPAN_EMPTY.
@ -476,8 +477,8 @@ typedef struct azure_iot_config_t_struct
az_span dps_id_scope; az_span dps_id_scope;
/* /*
* @brief Model ID of the Azure Plug-and-Play template implemented by the user application. * @brief Model ID of the IoT Plug and Play template implemented by the user application.
* @remark This is used only when the application uses/implements Azure IoT Plug-and-Play. * @remark This is used only when the application uses/implements IoT Plug and Play.
*/ */
az_span model_id; az_span model_id;
@ -533,9 +534,9 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief Amount of minutes for which the MQTT password should be valid. * @brief Amount of minutes for which the MQTT password should be valid.
* @remark If set to zero, Azure Iot client sets it to the default value of 60 minutes. * @remark If set to zero, Azure IoT client sets it to the default value of 60 minutes.
* Once this amount of minutes has passed and the MQTT password is expired, * Once this amount of minutes has passed and the MQTT password is expired,
* Azure IoT client trigers its logic to generate a new password and reconnect with * Azure IoT client triggers its logic to generate a new password and reconnect with
* Azure IoT Hub. * Azure IoT Hub.
*/ */
uint32_t sas_token_lifetime_in_minutes; uint32_t sas_token_lifetime_in_minutes;
@ -543,7 +544,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief Callback handler used by Azure IoT client to inform the user application of * @brief Callback handler used by Azure IoT client to inform the user application of
* a completion of properties update. * a completion of properties update.
* @remark A properties update is trigered by the user application when * @remark A properties update is triggered by the user application when
* `azure_iot_send_properties_update` is called. * `azure_iot_send_properties_update` is called.
*/ */
properties_update_completed_t on_properties_update_completed; properties_update_completed_t on_properties_update_completed;
@ -551,7 +552,7 @@ typedef struct azure_iot_config_t_struct
/* /*
* @brief Callback handler used by Azure IoT client to inform the user application of * @brief Callback handler used by Azure IoT client to inform the user application of
* a writable-properties update received from Azure IoT Hub. * a writable-properties update received from Azure IoT Hub.
* @remark If Azure IoT Plug.-and-Play is used, a response must be sent back to * @remark If IoT Plug and Play is used, a response must be sent back to
* Azure IoT Hub. * Azure IoT Hub.
*/ */
properties_received_t on_properties_received; properties_received_t on_properties_received;
@ -590,7 +591,7 @@ typedef struct azure_iot_t_struct
azure_iot_t; azure_iot_t;
/* /*
* @brief Initialies the azure_iot_t structure that holds the Azure IoT client state. * @brief Initializes the azure_iot_t structure that holds the Azure IoT client state.
* @remark This function must be called only once per `azure_iot_t` instance, * @remark This function must be called only once per `azure_iot_t` instance,
* before any other function can be called using it. * before any other function can be called using it.
* *
@ -598,9 +599,9 @@ azure_iot_t;
* @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the * @param[in] azure_iot_config A pointer to a `azure_iot_config_t` containing all the
* configuration neeeded for the client to connect and work with * configuration neeeded for the client to connect and work with
* the Azure IoT services. * the Azure IoT services.
* @return int 0 on success, or non-zero if any failure occurs. * @return Nothing.
*/ */
int azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config); void azure_iot_init(azure_iot_t* azure_iot, azure_iot_config_t* azure_iot_config);
/* /*
* @brief Starts an Azure IoT client. * @brief Starts an Azure IoT client.
@ -673,23 +674,23 @@ void azure_iot_do_work(azure_iot_t* azure_iot);
int azure_iot_send_telemetry(azure_iot_t* azure_iot, az_span message); int azure_iot_send_telemetry(azure_iot_t* azure_iot, az_span message);
/** /**
* @brief Checks whether `span` is equal AZ_SPAN_EMPTY. * @brief Sends a property update message to Azure IoT Hub.
* *
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client. * @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] message An `az_span` with the message with the reported properties update * @param[in] request_id An unique identification number to correlate the response with when
* (a JSON document formatted according to the DTDL specification). * @param[in] message An `az_span` with the message with the reported properties update
* `message` gets passed as-is to the MQTT client publish function as the payload, so if * (a JSON document formatted according to the DTDL specification).
* your MQTT client expects a null-terminated string for payload, make sure `message` is * `message` gets passed as-is to the MQTT client publish function as the payload, so if
* a null-terminated string. * your MQTT client expects a null-terminated string for payload, make sure `message` is
* @param[in] request_id An unique identification number to correlate the response with when * a null-terminated string.
* `on_properties_update_completed` (set in azure_iot_config_t) is invoked. * `on_properties_update_completed` (set in azure_iot_config_t) is invoked.
* *
* @return int 0 if the function succeeds, or non-zero if any failure occurs. * @return int 0 if the function succeeds, or non-zero if any failure occurs.
*/ */
int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id, az_span message); int azure_iot_send_properties_update(azure_iot_t* azure_iot, uint32_t request_id, az_span message);
/** /**
* @brief Checks whether `span` is equal AZ_SPAN_EMPTY. * @brief Sends a property update message to Azure IoT Hub.
* *
* @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client. * @param[in] azure_iot The pointer to the azure_iot_t instance that holds the state of the Azure IoT client.
* @param[in] request_id The same `request_id` of the device command received from Azure IoT Hub. * @param[in] request_id The same `request_id` of the device command received from Azure IoT Hub.
@ -720,7 +721,7 @@ int azure_iot_mqtt_client_connected(azure_iot_t* azure_iot);
/* /*
* @brief Informs the Azure IoT client that the MQTT client is disconnected. * @brief Informs the Azure IoT client that the MQTT client is disconnected.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit` callback * @remark This must be called after Azure IoT client invokes the `mqtt_client_deinit` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has disconencted * (provided in the azure_iot_config_t instance) so it knows the MQTT client has disconnected
* from the Azure IoT service. * from the Azure IoT service.
* *
* @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller. * @param[in] azure_iot A pointer to the instance of `azure_iot_t` previously initialized by the caller.
@ -746,7 +747,7 @@ int azure_iot_mqtt_client_subscribe_completed(azure_iot_t* azure_iot, int packet
* @brief Informs the Azure IoT client that the MQTT client has completed a PUBLISH. * @brief Informs the Azure IoT client that the MQTT client has completed a PUBLISH.
* @remark This must be called after Azure IoT client invokes the `mqtt_client_publish` callback * @remark This must be called after Azure IoT client invokes the `mqtt_client_publish` callback
* (provided in the azure_iot_config_t instance) so it knows the MQTT client has * (provided in the azure_iot_config_t instance) so it knows the MQTT client has
* completed a MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by * completed an MQTT PUBLISH. If the QoS is 0 (AT MOST ONCE), this shall be called by
* the user application right after `mqtt_client_publish` is invoked. If the QoS of * the user application right after `mqtt_client_publish` is invoked. If the QoS of
* is 1 (AT LEAST ONCE), this shall be called whenever a PUBACK is received. * is 1 (AT LEAST ONCE), this shall be called whenever a PUBACK is received.
* *
@ -776,13 +777,13 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
*/ */
/** /**
* @brief Checks whether `span` is equal AZ_SPAN_EMPTY. * @brief Checks whether `span` is equal to AZ_SPAN_EMPTY.
* *
* @param[in] span A span to be verified. * @param[in] span A span to be verified.
* *
* @return boolean True if `span`'s pointer and size are equal to AZ_SPAN_EMPTY, or false otherwise. * @return boolean True if `span`'s pointer and size are equal to AZ_SPAN_EMPTY, or false otherwise.
*/ */
#define az_span_is_empty(span) az_span_is_content_equal(span, AZ_SPAN_EMPTY) #define is_az_span_empty(span) az_span_is_content_equal(span, AZ_SPAN_EMPTY)
/** /**
* @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to `remainder`. * @brief Slices `span` at position `size`, returns the first slice and assigns the second slice to `remainder`.
@ -793,7 +794,7 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_
* *
* @return az_span A slice of `span` from position zero to `size`. * @return az_span A slice of `span` from position zero to `size`.
*/ */
az_span az_span_split(az_span span, int32_t size, az_span* remainder); az_span split_az_span(az_span span, int32_t size, az_span* remainder);
/** /**
* @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the second through `remainder`. * @brief Slices `destination` to fit `source`, copy `source` into the first slice and returns the second through `remainder`.
@ -804,6 +805,6 @@ az_span az_span_split(az_span span, int32_t size, az_span* remainder);
* *
* @return az_span A slice of `destination` with the same size as `source`, with `source`'s content copied over. * @return az_span A slice of `destination` with the same size as `source`, with `source`'s content copied over.
*/ */
static az_span az_span_slice_and_copy(az_span destination, az_span source, az_span* remainder); static az_span slice_and_copy_az_span(az_span destination, az_span source, az_span* remainder);
#endif // AZURE_IOT_H #endif // AZURE_IOT_H

Просмотреть файл

@ -12,9 +12,9 @@
* It uses our Azure Embedded SDK for C to help interact with Azure IoT. * It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/. * For reference, please visit https://github.com/azure/azure-sdk-for-c and https://azureiotcentral.com/.
* *
* To connect and work with Azure IoT Hub you need a MQTT client, connecting, subscribing * To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub. * and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is a MQTT client support library, helping composing and parsing the * Our azure-sdk-for-c is an MQTT client support library, helping composing and parsing the
* MQTT topic names and messages exchanged with the Azure IoT Hub. * MQTT topic names and messages exchanged with the Azure IoT Hub.
* *
* The additional layers in this sketch provide a structured use of azure-sdk-for-c and * The additional layers in this sketch provide a structured use of azure-sdk-for-c and
@ -28,7 +28,7 @@
* - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding), * - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding),
* - Receive the callbacks for Plug and Play properties and commands. * - Receive the callbacks for Plug and Play properties and commands.
* *
* Azure_IoT_PnP_Template.cpp contains the actual implementation of the Azure Plug-and-Play template * Azure_IoT_PnP_Template.cpp contains the actual implementation of the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board. * specific for the Espressif ESP32 Azure IoT Kit board.
* *
* To properly connect to your Azure IoT services, please fill the information in the `iot_configs.h` file. * To properly connect to your Azure IoT services, please fill the information in the `iot_configs.h` file.
@ -203,13 +203,13 @@ static int mqtt_client_deinit_function(mqtt_client_handle_t mqtt_client_handle)
/* /*
* See the documentation of `mqtt_client_subscribe_function_t` in AzureIoT.h for details. * See the documentation of `mqtt_client_subscribe_function_t` in AzureIoT.h for details.
*/ */
static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handle, const uint8_t* topic, size_t topic_length, mqtt_qos_t qos) static int mqtt_client_subscribe_function(mqtt_client_handle_t mqtt_client_handle, az_span topic, mqtt_qos_t qos)
{ {
LogInfo("MQTT client subscribing to '%s'", topic); LogInfo("MQTT client subscribing to '%.*s'", az_span_size(topic), az_span_ptr(topic));
// As per documentation, `topic` always ends with a null-terminator. // As per documentation, `topic` always ends with a null-terminator.
// esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion is needed. // esp_mqtt_client_subscribe returns the packet id or negative on error already, so no conversion is needed.
int packet_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)topic, (int)qos); int packet_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)mqtt_client_handle, (const char*)az_span_ptr(topic), (int)qos);
return packet_id; return packet_id;
} }
@ -242,7 +242,7 @@ static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle,
/* --- Other Interface functions required by Azure IoT --- */ /* --- Other Interface functions required by Azure IoT --- */
/* /*
* See the documentation of `hmac_sha512_encryption_function_t` in AzureIoT.h for details. * See the documentation of `hmac_sha256_encryption_function_t` in AzureIoT.h for details.
*/ */
static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* signed_payload, size_t signed_payload_size) static int mbedtls_hmac_sha256(const uint8_t* key, size_t key_length, const uint8_t* payload, size_t payload_length, uint8_t* signed_payload, size_t signed_payload_size)
{ {
@ -330,7 +330,7 @@ void setup()
/* /*
* The configuration structure used by Azure IoT must remain unchanged (including data buffer) * The configuration structure used by Azure IoT must remain unchanged (including data buffer)
* throughout the lifetime of the sample. This variable must also not loose context so other * throughout the lifetime of the sample. This variable must also not lose context so other
* components do not overwrite any information within this structure. * components do not overwrite any information within this structure.
*/ */
azure_iot_config.user_agent = AZ_SPAN_FROM_STR(AZURE_SDK_CLIENT_USER_AGENT_WORKAROUND); azure_iot_config.user_agent = AZ_SPAN_FROM_STR(AZURE_SDK_CLIENT_USER_AGENT_WORKAROUND);
@ -347,22 +347,17 @@ void setup()
azure_iot_config.mqtt_client_interface.mqtt_client_deinit = mqtt_client_deinit_function; azure_iot_config.mqtt_client_interface.mqtt_client_deinit = mqtt_client_deinit_function;
azure_iot_config.mqtt_client_interface.mqtt_client_subscribe = mqtt_client_subscribe_function; azure_iot_config.mqtt_client_interface.mqtt_client_subscribe = mqtt_client_subscribe_function;
azure_iot_config.mqtt_client_interface.mqtt_client_publish = mqtt_client_publish_function; azure_iot_config.mqtt_client_interface.mqtt_client_publish = mqtt_client_publish_function;
azure_iot_config.data_manipulation_functions.hmac_sha512_encrypt = mbedtls_hmac_sha256; azure_iot_config.data_manipulation_functions.hmac_sha256_encrypt = mbedtls_hmac_sha256;
azure_iot_config.data_manipulation_functions.base64_decode = base64_decode; azure_iot_config.data_manipulation_functions.base64_decode = base64_decode;
azure_iot_config.data_manipulation_functions.base64_encode = base64_encode; azure_iot_config.data_manipulation_functions.base64_encode = base64_encode;
azure_iot_config.on_properties_update_completed = on_properties_update_completed; azure_iot_config.on_properties_update_completed = on_properties_update_completed;
azure_iot_config.on_properties_received = on_properties_received; azure_iot_config.on_properties_received = on_properties_received;
azure_iot_config.on_command_request_received = on_command_request_received; azure_iot_config.on_command_request_received = on_command_request_received;
if (azure_iot_init(&azure_iot, &azure_iot_config) != 0) azure_iot_init(&azure_iot, &azure_iot_config);
{ azure_iot_start(&azure_iot);
LogError("Failed initializing the Azure IoT client.");
} LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state);
else
{
LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state);
azure_iot_start(&azure_iot);
}
} }
void loop() void loop()
@ -451,7 +446,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
int i, r; int i, r;
case MQTT_EVENT_ERROR: case MQTT_EVENT_ERROR:
LogError("MQTT client in ERROR state."); LogError("MQTT client in ERROR state.");
LogError( LogError(
"esp_tls_stack_err=%d; esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_code=%d", "esp_tls_stack_err=%d; esp_tls_cert_verify_flags=%d;esp_transport_sock_errno=%d;error_type=%d;connect_return_code=%d",
event->error_handle->esp_tls_stack_err, event->error_handle->esp_tls_stack_err,
@ -481,7 +476,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED"); LogError("connect_return_code=MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED");
break; break;
default: default:
LogError("connect_return_code=unknown"); LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code);
break; break;
}; };
@ -543,7 +538,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event)
LogInfo("MQTT client connecting."); LogInfo("MQTT client connecting.");
break; break;
default: default:
LogError("MQTT event UNKNOWN"); LogError("MQTT event UNKNOWN.");
break; break;
} }

Просмотреть файл

@ -86,7 +86,7 @@ static uint32_t telemetry_send_count = 0;
static size_t telemetry_frequency_in_seconds = 10; // With default frequency of once in 10 seconds. static size_t telemetry_frequency_in_seconds = 10; // With default frequency of once in 10 seconds.
static time_t last_telemetry_send_time = INDEFINITE_TIME; static time_t last_telemetry_send_time = INDEFINITE_TIME;
#define OLED_SPLASH_MESSAGE "Espressif ESP32 Azure IoT Kit + Azure IoT Central" #define OLED_SPLASH_MESSAGE "Espressif ESP32 Azure IoT Kit + Central"
static bool led1_on = false; static bool led1_on = false;
static bool led2_on = false; static bool led2_on = false;
@ -109,6 +109,9 @@ void azure_pnp_init()
esp32_azureiotkit_oled_clean_screen(); esp32_azureiotkit_oled_clean_screen();
esp32_azureiotkit_oled_show_message((uint8_t*)OLED_SPLASH_MESSAGE, lengthof(OLED_SPLASH_MESSAGE)); esp32_azureiotkit_oled_show_message((uint8_t*)OLED_SPLASH_MESSAGE, lengthof(OLED_SPLASH_MESSAGE));
esp32_azureiotkit_led1_set_state(LED_STATE_OFF);
esp32_azureiotkit_led2_set_state(LED_STATE_OFF);
} }
const az_span azure_pnp_get_model_id() const az_span azure_pnp_get_model_id()
@ -216,7 +219,7 @@ int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span propertie
size_t length; size_t length;
result = consume_properties_and_generate_response(azure_iot, properties, data_buffer, DATA_BUFFER_SIZE, &length); result = consume_properties_and_generate_response(azure_iot, properties, data_buffer, DATA_BUFFER_SIZE, &length);
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed generating properties ack payload."); EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed consuming/generating properties ack payload.");
result = azure_iot_send_properties_update(azure_iot, request_id, az_span_create(data_buffer, length)); result = azure_iot_send_properties_update(azure_iot, request_id, az_span_create(data_buffer, length));
EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed sending reported properties update."); EXIT_IF_TRUE(result != RESULT_OK, RESULT_ERROR, "Failed sending reported properties update.");
@ -322,7 +325,7 @@ static int generate_telemetry_payload(uint8_t* payload_buffer, size_t payload_bu
if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1) if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1)
{ {
LogError("Insuficient space for telemetry payload null terminator."); LogError("Insufficient space for telemetry payload null terminator.");
return RESULT_ERROR; return RESULT_ERROR;
} }
@ -399,7 +402,7 @@ static int generate_device_info_payload(az_iot_hub_client const* hub_client, uin
if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1) if ((payload_buffer_size - az_span_size(payload_buffer_span)) < 1)
{ {
LogError("Insuficient space for telemetry payload null terminator."); LogError("Insufficient space for telemetry payload null terminator.");
return RESULT_ERROR; return RESULT_ERROR;
} }
@ -497,8 +500,9 @@ static int consume_properties_and_generate_response(
} }
else else
{ {
LogError("Unexpected property received (%.*s)", LogError("Unexpected property received (%.*s).",
az_span_size(jr.token.slice), az_span_ptr(jr.token.slice)); az_span_size(jr.token.slice), az_span_ptr(jr.token.slice));
return RESULT_ERROR;
} }
azrc = az_json_reader_next_token(&jr); azrc = az_json_reader_next_token(&jr);

Просмотреть файл

@ -2,7 +2,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
/* /*
* Azure_IoT_PnP_Template.cpp implements the the Azure Plug-and-Play template * Azure_IoT_PnP_Template.cpp implements the IoT Plug and Play template
* specific for the Espressif ESP32 Azure IoT Kit board. * specific for the Espressif ESP32 Azure IoT Kit board.
*/ */
@ -19,8 +19,8 @@
void azure_pnp_init(); void azure_pnp_init();
/* /*
* @brief Returns the model id of the Azure Plug and Play template implemented by this module. * @brief Returns the model id of the IoT Plug and Play template implemented by this device.
* @remark Every Azure Plug and Play template has a model id that must be informed by the * @remark Every IoT Plug and Play template has a model id that must be informed by the
* device during Azure IoT provisioning and connection with the Azure IoT Hub. * device during Azure IoT provisioning and connection with the Azure IoT Hub.
* @return az_span An `az_span` containing the model id implemented by this module. * @return az_span An `az_span` containing the model id implemented by this module.
*/ */
@ -52,12 +52,12 @@ int azure_pnp_send_device_info(azure_iot_t* azure_iot, uint32_t request_id);
void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds); void azure_pnp_set_telemetry_frequency(size_t frequency_in_seconds);
/* /*
* @brief Sends telemetry implemented by this Azure Plug and Play application to Azure IoT Central. * @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT Central.
* @remark The Azure Plug and Play template implemented by this module is specific to the * @remark The IoT Plug and Play template implemented by this device is specific to the
* Espressif ESP32 Azure IoT Kit board, which contains several sensors. * Espressif ESP32 Azure IoT Kit board, which contains several sensors.
* The template defines telemetry data points for temperature, humidity, * The template defines telemetry data points for temperature, humidity,
* pressure, altitude, luminosity, magnetic field, rolling and pitch angles, * pressure, altitude, luminosity, magnetic field, rolling and pitch angles,
* as well as acceleration. All of these data is read from the board sensors and sent to * as well as acceleration. All of these data are read from the board sensors and sent to
* Azure IoT Central when `azure_pnp_send_telemetry` is called. * Azure IoT Central when `azure_pnp_send_telemetry` is called.
* This function must be called frequently enough, no slower than the frequency set * This function must be called frequently enough, no slower than the frequency set
* with `azure_pnp_set_telemetry_frequency` (or the default frequency of 10 seconds). * with `azure_pnp_set_telemetry_frequency` (or the default frequency of 10 seconds).
@ -72,7 +72,7 @@ int azure_pnp_send_telemetry(azure_iot_t* azure_iot);
/* /*
* @brief Handles a command when it is received from Azure IoT Central. * @brief Handles a command when it is received from Azure IoT Central.
* @remark This function will perform the task requested by the command received * @remark This function will perform the task requested by the command received
* (if the command matches the expected name) and send back a response to * (if the command matches the expected name) and sends back a response to
* Azure IoT Central. * Azure IoT Central.
* *
* @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized * @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized

Просмотреть файл

@ -12,7 +12,7 @@
#define INDEFINITE_TIME ((time_t)-1) #define INDEFINITE_TIME ((time_t)-1)
#define az_span_is_empty(x) (az_span_size(x) == az_span_size(AZ_SPAN_EMPTY) && az_span_ptr(x) == az_span_ptr(AZ_SPAN_EMPTY)) #define is_az_span_empty(x) (az_span_size(x) == az_span_size(AZ_SPAN_EMPTY) && az_span_ptr(x) == az_span_ptr(AZ_SPAN_EMPTY))
static uint32_t getSasTokenExpiration(const char* sasToken) static uint32_t getSasTokenExpiration(const char* sasToken)
{ {
@ -242,7 +242,7 @@ int AzIoTSasToken::Generate(unsigned int expiryTimeInMinutes)
expiryTimeInMinutes, expiryTimeInMinutes,
this->sasTokenBuffer); this->sasTokenBuffer);
if (az_span_is_empty(this->sasToken)) if (is_az_span_empty(this->sasToken))
{ {
Logger.Error("Failed generating SAS token"); Logger.Error("Failed generating SAS token");
return 1; return 1;

Просмотреть файл

@ -6,9 +6,9 @@
* It uses our Azure Embedded SDK for C to help interact with Azure IoT. * It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c. * For reference, please visit https://github.com/azure/azure-sdk-for-c.
* *
* To connect and work with Azure IoT Hub you need a MQTT client, connecting, subscribing * To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub. * and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is a MQTT client support library, helping composing and parsing the * Our azure-sdk-for-c is an MQTT client support library, helping composing and parsing the
* MQTT topic names and messages exchanged with the Azure IoT Hub. * MQTT topic names and messages exchanged with the Azure IoT Hub.
* *
* This sample performs the following tasks: * This sample performs the following tasks:
@ -64,7 +64,7 @@ static const char* password = IOT_CONFIG_WIFI_PASSWORD;
static const char* host = IOT_CONFIG_IOTHUB_FQDN; static const char* host = IOT_CONFIG_IOTHUB_FQDN;
static const char* mqtt_broker_uri = "mqtts://" IOT_CONFIG_IOTHUB_FQDN; static const char* mqtt_broker_uri = "mqtts://" IOT_CONFIG_IOTHUB_FQDN;
static const char* device_id = IOT_CONFIG_DEVICE_ID; static const char* device_id = IOT_CONFIG_DEVICE_ID;
static const int mqtt_port = 8883; static const int mqtt_port = AZ_IOT_DEFAULT_MQTT_CONNECT_PORT;
// Memory allocated for the sample's variables and structures. // Memory allocated for the sample's variables and structures.
static esp_mqtt_client_handle_t mqtt_client; static esp_mqtt_client_handle_t mqtt_client;

Просмотреть файл

@ -6,7 +6,7 @@
* It uses our Azure Embedded SDK for C to help interact with Azure IoT. * It uses our Azure Embedded SDK for C to help interact with Azure IoT.
* For reference, please visit https://github.com/azure/azure-sdk-for-c. * For reference, please visit https://github.com/azure/azure-sdk-for-c.
* *
* To connect and work with Azure IoT Hub you need a MQTT client, connecting, subscribing * To connect and work with Azure IoT Hub you need an MQTT client, connecting, subscribing
* and publishing to specific topics to use the messaging features of the hub. * and publishing to specific topics to use the messaging features of the hub.
* Our azure-sdk-for-c is an MQTT client support library, helping to compose and parse the * Our azure-sdk-for-c is an MQTT client support library, helping to compose and parse the
* MQTT topic names and messages exchanged with the Azure IoT Hub. * MQTT topic names and messages exchanged with the Azure IoT Hub.

Просмотреть файл

@ -36,7 +36,7 @@
static const char* ssid = IOT_CONFIG_WIFI_SSID; static const char* ssid = IOT_CONFIG_WIFI_SSID;
static const char* password = IOT_CONFIG_WIFI_PASSWORD; static const char* password = IOT_CONFIG_WIFI_PASSWORD;
static const char* host = IOT_CONFIG_IOTHUB_FQDN; static const char* host = IOT_CONFIG_IOTHUB_FQDN;
static const int mqtt_port = 8883; static const int mqtt_port = AZ_IOT_DEFAULT_MQTT_CONNECT_PORT;
// Memory allocated for the sample's variables and structures. // Memory allocated for the sample's variables and structures.
static WiFiUDP ntp_udp_client; static WiFiUDP ntp_udp_client;