diff --git a/examples/Azure_IoT_Central_ESP32/AzureIoT.cpp b/examples/Azure_IoT_Central_ESP32/AzureIoT.cpp index 6b5b5a0..dbe7320 100644 --- a/examples/Azure_IoT_Central_ESP32/AzureIoT.cpp +++ b/examples/Azure_IoT_Central_ESP32/AzureIoT.cpp @@ -15,8 +15,8 @@ log_function_t default_logging_function = NULL; #endif // DISABLE_LOGGING -/* --- Azure Abstractions --- */ -#define IOT_HUB_MQTT_PORT 8883 +/* --- Azure Definitions --- */ +#define IOT_HUB_MQTT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT #define MQTT_PROTOCOL_PREFIX "mqtts://" #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) @@ -45,6 +45,8 @@ log_function_t default_logging_function = NULL; #define EXIT_IF_AZ_FAILED(azresult, retcode, message, ...) \ EXIT_IF_TRUE(az_result_failed(azresult), retcode, message, ##__VA_ARGS__ ) +#define NUMBER_OF_SECONDS_IN_A_MINUTE 60 + /* --- Internal function prototypes --- */ 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); #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 --- */ -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_config); if (azure_iot_config->use_device_provisioning) { - _az_PRECONDITION(az_span_is_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->iot_hub_fqdn)); + _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_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->device_id, 1, false); - _az_PRECONDITION(az_span_is_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_id_scope)); + _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->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_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_deinit); _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; } - - return RESULT_OK; } 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; mqtt_client_config_t mqtt_client_config; 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) { @@ -250,7 +251,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot) { // This seems harmless, but... // 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, // 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 @@ -277,6 +278,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot) { azure_iot->state = azure_iot_state_error; LogError("Failed initializing MQTT client."); + return; } break; @@ -287,15 +289,15 @@ void azure_iot_do_work(azure_iot_t* azure_iot) azure_iot->state = azure_iot_state_subscribing_to_dps; packet_id = azure_iot->config->mqtt_client_interface.mqtt_client_subscribe( - azure_iot->mqtt_client_handle, - (const uint8_t*)AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC, - lengthof(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC), + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC), mqtt_qos_at_most_once); if (packet_id < 0) { azure_iot->state = azure_iot_state_error; LogError("Failed subscribing to Azure Device Provisioning respose topic."); + return; } break; @@ -314,19 +316,19 @@ void azure_iot_do_work(azure_iot_t* azure_iot) 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; - LogError("Failed allocating memory for DPS register payload."); + LogError("Failed reserving memory for DPS register payload."); return; } dps_register_custom_property = generate_dps_register_custom_property( 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; 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; LogError("Failed publishing to DPS registration topic"); + return; } break; @@ -405,6 +408,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot) { azure_iot->state = azure_iot_state_error; LogError("Failed publishing to DPS status query topic"); + return; } 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) { azure_iot->state = azure_iot_state_error; - LogError("Failed initializing MQTT client."); + LogError("Failed initializing MQTT client for IoT Hub connection."); + return; } 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; 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, - lengthof(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC), + mqtt_qos_at_least_once); if (packet_id < 0) { 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; @@ -463,30 +470,33 @@ void azure_iot_do_work(azure_iot_t* azure_iot) azure_iot->state = azure_iot_state_subscribing_to_pnp_props; 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, - lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC), + mqtt_qos_at_least_once); if (packet_id < 0) { 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: break; case azure_iot_state_subscribed_to_pnp_props: azure_iot->state = azure_iot_state_subscribing_to_pnp_writable_props; 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, - lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC), + mqtt_qos_at_least_once); if (packet_id < 0) { 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; @@ -501,13 +511,14 @@ void azure_iot_do_work(azure_iot_t* azure_iot) azure_iot->state = azure_iot_state_error; 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; if (azure_iot->config->mqtt_client_interface.mqtt_client_deinit(&azure_iot->mqtt_client_handle) != 0) { azure_iot->state = azure_iot_state_error; LogError("Failed de-initializing MQTT client."); + return; } } 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( &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.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: // - 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. 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))) { - 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)); result = RESULT_ERROR; } @@ -789,14 +800,14 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_ { 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; - LogError("Failed allocating memory for DPS operation id."); + LogError("Failed reserving memory for DPS operation id."); 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. 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; 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 { - 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; 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 { - LogError("No PUBLISH notification expected"); + LogError("No PUBLISH notification expected."); 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( &azure_iot->iot_hub_client, request_id, response_status, (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.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] 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. @@ -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) { - az_span data_buffer_span, client_id_span, username_span, password_span; - size_t client_id_length, username_length, password_length; + az_span data_buffer_span; + 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; 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; - password_span = az_span_split(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."); + password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_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( &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); 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); - EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); + client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_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( &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."); - 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( &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] mqtt_client_config A pointer to a generic structure to contain the configuration for * 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) { - az_span data_buffer_span, client_id_span, username_span, password_span; - size_t client_id_length, username_length, password_length; + az_span data_buffer_span; + 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; 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; - password_span = az_span_split(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."); + password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_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( &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); 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); - EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); + client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_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( &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."); - 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( &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(); 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. - plain_sas_signature = az_span_split(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."); + plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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( 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. - sas_signature = az_span_split(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."); + sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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); - EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); + decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); + EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key."); 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); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); // Step 2.c. - sas_hmac256_signed_signature = az_span_split(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."); + sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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(plain_sas_signature), az_span_size(plain_sas_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(); 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. - plain_sas_signature = az_span_split(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."); + plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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( 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. - sas_signature = az_span_split(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."); + sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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); - EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); + decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); + EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key."); 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); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); // Step 2.c. - sas_hmac256_signed_signature = az_span_split(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."); + sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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(plain_sas_signature), az_span_size(plain_sas_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; } +/** + * @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) { az_span custom_property; 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); - EXIT_IF_TRUE(az_span_is_empty(custom_property), AZ_SPAN_EMPTY, "Failed generating DPS register custom property."); + custom_property = split_az_span(data_buffer, length, remainder); + 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)); - 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); - 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)); - 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; } /* --- 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); - 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)); } @@ -1240,16 +1274,16 @@ az_span az_span_split(az_span span, int32_t size, az_span* remainder) 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; } - if (!az_span_is_empty(result)) + if (!is_az_span_empty(result)) { (void)az_span_copy(result, source); } diff --git a/examples/Azure_IoT_Central_ESP32/AzureIoT.h b/examples/Azure_IoT_Central_ESP32/AzureIoT.h index a7a48e4..4cf5221 100644 --- a/examples/Azure_IoT_Central_ESP32/AzureIoT.h +++ b/examples/Azure_IoT_Central_ESP32/AzureIoT.h @@ -2,8 +2,10 @@ // SPDX-License-Identifier: MIT /* - * AzureIoT.cpp contains a state machine that implements those steps, plus abstractions to simplify - * its overall use. Besides the basic configuration needed to access the Azure IoT services, + * AzureIoT.cpp contains a state machine that implements the necessary calls to azure-sdk-for-c + * 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: * - Interact with your MQTT client, * - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding), @@ -57,13 +59,13 @@ extern log_function_t default_logging_function; #endif // DISABLE_LOGGING -/* --- Azure Abstraction --- */ +/* --- Azure Definitions --- */ #define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net" -#define DPS_GLOBAL_ENDPOINT_PORT 8883 -#define IOT_HUB_ENDPOINT_PORT 8883 +#define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT +#define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT #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, @@ -83,12 +85,13 @@ typedef enum mqtt_qos_t_enum 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. * @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 * 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 { @@ -105,12 +108,12 @@ mqtt_message_t; 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; /* - * @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; @@ -133,12 +136,12 @@ mqtt_client_config_t; /* * @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; /* - * @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 * 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 @@ -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); /* - * @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 * 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). @@ -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 * 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. - * @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. * * @@ -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 * 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. @@ -213,13 +214,13 @@ typedef struct mqtt_client_interface_t_struct { mqtt_client_init_function_t mqtt_client_init; 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_subscribe_function_t mqtt_client_subscribe; } 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. * * @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); /* - * @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. * * @param[in] data Buffer containing the Base64-decoded content. * @param[in] data_length Length of `data`. - * @param[in] decoded Buffer where to write the Base64-encoded content of `data`. - * @param[in] decoded_size Size of `encoded`. - * @param[out] decoded_length The final length of the Base64-encoded content written in + * @param[in] encoded Buffer where to write the Base64-encoded content of `data`. + * @param[in] encoded_size Size of `encoded`. + * @param[out] encoded_length The final length of the Base64-encoded content written in * the `encoded` buffer. * * @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); /* - * @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. * * @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm. * @param[in] key_length Length of `key`. * @param[in] payload Buffer containing the data to be encrypted. * @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. * * @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. @@ -270,7 +271,7 @@ typedef struct data_manipulation_functions_t_struct { base64_decode_function_t base64_decode; 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; @@ -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); /* - * @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 { @@ -323,7 +324,7 @@ typedef struct command_request_t_struct 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 * `azure_iot_send_command_response`. * @@ -335,7 +336,7 @@ command_request_t; 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 { @@ -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 * 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 - * 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. */ typedef struct azure_iot_config_t_struct @@ -447,8 +448,8 @@ typedef struct azure_iot_config_t_struct az_span device_id; /* - * @brief Symetric 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 + * @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, if using SAS-token * authentication (which is used, for example, when connecting to Azure IoT Central). */ 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 * 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 not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) 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 * 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 not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) 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; /* - * @brief Model ID of the Azure Plug-and-Play template implemented by the user application. - * @remark This is used only when the application uses/implements Azure IoT Plug-and-Play. + * @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 IoT Plug and Play. */ 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. - * @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, - * 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. */ 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 * 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. */ 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 * 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. */ properties_received_t on_properties_received; @@ -590,7 +591,7 @@ typedef struct azure_iot_t_struct 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, * 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 * configuration neeeded for the client to connect and work with * 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. @@ -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); /** - * @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] message An `az_span` with the message with the reported properties update - * (a JSON document formatted according to the DTDL specification). - * `message` gets passed as-is to the MQTT client publish function as the payload, so if - * your MQTT client expects a null-terminated string for payload, make sure `message` is - * a null-terminated string. - * @param[in] request_id An unique identification number to correlate the response with when - * `on_properties_update_completed` (set in azure_iot_config_t) is invoked. + * @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 An unique identification number to correlate the response with when + * @param[in] message An `az_span` with the message with the reported properties update + * (a JSON document formatted according to the DTDL specification). + * `message` gets passed as-is to the MQTT client publish function as the payload, so if + * your MQTT client expects a null-terminated string for payload, make sure `message` is + * a null-terminated string. + * `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); /** - * @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] 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. * @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. * * @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. * @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 - * 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 * 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. * * @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`. @@ -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`. */ -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`. @@ -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. */ -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 diff --git a/examples/Azure_IoT_Central_ESP32/Azure_IoT_Central_ESP32.ino b/examples/Azure_IoT_Central_ESP32/Azure_IoT_Central_ESP32.ino index e5b383a..c6e264f 100644 --- a/examples/Azure_IoT_Central_ESP32/Azure_IoT_Central_ESP32.ino +++ b/examples/Azure_IoT_Central_ESP32/Azure_IoT_Central_ESP32.ino @@ -6,9 +6,9 @@ * 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/. * - * 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. - * 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. * * 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), * - 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 - * specific for the Espressif ESP32 Azure IoT Kit board. + * Azure_IoT_PnP_Template.cpp contains the actual implementation of the IoT Plug and Play template + * specific for the Espressif ESP32 board. * * 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. */ -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. // 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; } @@ -236,7 +236,7 @@ static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle, /* --- 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) { @@ -324,7 +324,7 @@ void setup() /* * 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. */ 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_subscribe = mqtt_client_subscribe_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_encode = base64_encode; azure_iot_config.on_properties_update_completed = on_properties_update_completed; azure_iot_config.on_properties_received = on_properties_received; azure_iot_config.on_command_request_received = on_command_request_received; - if (azure_iot_init(&azure_iot, &azure_iot_config) != 0) - { - LogError("Failed initializing the Azure IoT client."); - } - else - { - LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state); - azure_iot_start(&azure_iot); - } + azure_iot_init(&azure_iot, &azure_iot_config); + azure_iot_start(&azure_iot); + + LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state); } void loop() @@ -445,7 +440,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event) int i, r; case MQTT_EVENT_ERROR: - LogError("MQTT client in ERROR state."); + LogError("MQTT client in ERROR state."); LogError( "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, @@ -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"); break; default: - LogError("connect_return_code=unknown"); + LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code); break; }; @@ -537,7 +532,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event) LogInfo("MQTT client connecting."); break; default: - LogError("MQTT event UNKNOWN"); + LogError("MQTT event UNKNOWN."); break; } diff --git a/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.cpp b/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.cpp index ce3123b..b98ce42 100644 --- a/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.cpp +++ b/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.cpp @@ -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) { - LogError("Insuficient space for telemetry payload null terminator."); + LogError("Insufficient space for telemetry payload null terminator."); 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) { - LogError("Insuficient space for telemetry payload null terminator."); + LogError("Insufficient space for telemetry payload null terminator."); return RESULT_ERROR; } @@ -526,7 +526,7 @@ static int consume_properties_and_generate_response( } else { - LogError("Unexpected property received (%.*s)", + LogError("Unexpected property received (%.*s).", az_span_size(jr.token.slice), az_span_ptr(jr.token.slice)); } diff --git a/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.h b/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.h index b9db855..c8e5284 100644 --- a/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.h +++ b/examples/Azure_IoT_Central_ESP32/Azure_IoT_PnP_Template.h @@ -2,7 +2,7 @@ // 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. */ @@ -19,8 +19,8 @@ void azure_pnp_init(); /* - * @brief Returns the model id of the Azure Plug and Play template implemented by this module. - * @remark Every Azure Plug and Play template has a model id that must be informed by the + * @brief Returns the model id of the IoT Plug and Play template implemented by this device. + * @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. * @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); /* - * @brief Sends telemetry implemented by this Azure Plug and Play application to Azure IoT Central. - * @remark The Azure Plug and Play template implemented by this module is specific to the + * @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT Central. + * @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. * The template defines telemetry data points for temperature, humidity, * 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. * 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). @@ -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. * @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. * * @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized diff --git a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.cpp b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.cpp index 6b5b5a0..cc5ab2a 100644 --- a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.cpp +++ b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.cpp @@ -15,8 +15,8 @@ log_function_t default_logging_function = NULL; #endif // DISABLE_LOGGING -/* --- Azure Abstractions --- */ -#define IOT_HUB_MQTT_PORT 8883 +/* --- Azure Definitions --- */ +#define IOT_HUB_MQTT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT #define MQTT_PROTOCOL_PREFIX "mqtts://" #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) @@ -32,6 +32,8 @@ log_function_t default_logging_function = NULL; #define DPS_REGISTER_CUSTOM_PAYLOAD_BEGIN "{\"modelId\":\"" #define DPS_REGISTER_CUSTOM_PAYLOAD_END "\"}" +#define NUMBER_OF_SECONDS_IN_A_MINUTE 60 + #define EXIT_IF_TRUE(condition, retcode, message, ...) \ 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); #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 --- */ -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_config); if (azure_iot_config->use_device_provisioning) { - _az_PRECONDITION(az_span_is_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->iot_hub_fqdn)); + _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_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->device_id, 1, false); - _az_PRECONDITION(az_span_is_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_id_scope)); + _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->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_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_deinit); _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; } - - return RESULT_OK; } 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; mqtt_client_config_t mqtt_client_config; 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) { @@ -250,7 +251,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot) { // This seems harmless, but... // 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, // 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 @@ -277,6 +278,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot) { azure_iot->state = azure_iot_state_error; LogError("Failed initializing MQTT client."); + return; } 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( azure_iot->mqtt_client_handle, - (const uint8_t*)AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC, - lengthof(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC), + AZ_SPAN_FROM_STR(AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC), mqtt_qos_at_most_once); if (packet_id < 0) { azure_iot->state = azure_iot_state_error; LogError("Failed subscribing to Azure Device Provisioning respose topic."); + return; } break; @@ -314,19 +316,19 @@ void azure_iot_do_work(azure_iot_t* azure_iot) 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; - LogError("Failed allocating memory for DPS register payload."); + LogError("Failed reserving memory for DPS register payload."); return; } dps_register_custom_property = generate_dps_register_custom_property( 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; 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; LogError("Failed publishing to DPS registration topic"); + return; } break; @@ -405,6 +408,7 @@ void azure_iot_do_work(azure_iot_t* azure_iot) { azure_iot->state = azure_iot_state_error; LogError("Failed publishing to DPS status query topic"); + return; } 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) { azure_iot->state = azure_iot_state_error; - LogError("Failed initializing MQTT client."); + LogError("Failed initializing MQTT client for IoT Hub connection."); + return; } 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; 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, - lengthof(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_COMMANDS_SUBSCRIBE_TOPIC), + mqtt_qos_at_least_once); if (packet_id < 0) { 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; @@ -463,30 +470,33 @@ void azure_iot_do_work(azure_iot_t* azure_iot) azure_iot->state = azure_iot_state_subscribing_to_pnp_props; 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, - lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_MESSAGE_SUBSCRIBE_TOPIC), + mqtt_qos_at_least_once); if (packet_id < 0) { 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: break; case azure_iot_state_subscribed_to_pnp_props: azure_iot->state = azure_iot_state_subscribing_to_pnp_writable_props; 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, - lengthof(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC), mqtt_qos_at_least_once); + azure_iot->mqtt_client_handle, + AZ_SPAN_FROM_STR(AZ_IOT_HUB_CLIENT_PROPERTIES_WRITABLE_UPDATES_SUBSCRIBE_TOPIC), + mqtt_qos_at_least_once); if (packet_id < 0) { 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; @@ -501,13 +511,14 @@ void azure_iot_do_work(azure_iot_t* azure_iot) azure_iot->state = azure_iot_state_error; 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; if (azure_iot->config->mqtt_client_interface.mqtt_client_deinit(&azure_iot->mqtt_client_handle) != 0) { azure_iot->state = azure_iot_state_error; LogError("Failed de-initializing MQTT client."); + return; } } 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( &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.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: // - 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. 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))) { - 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)); result = RESULT_ERROR; } @@ -789,14 +800,14 @@ int azure_iot_mqtt_client_message_received(azure_iot_t* azure_iot, mqtt_message_ { 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; - LogError("Failed allocating memory for DPS operation id."); + LogError("Failed reserving memory for DPS operation id."); 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. 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; 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 { - 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; 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 { - LogError("No PUBLISH notification expected"); + LogError("No PUBLISH notification expected."); 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( &azure_iot->iot_hub_client, request_id, response_status, (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.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] 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. @@ -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) { - az_span data_buffer_span, client_id_span, username_span, password_span; - size_t client_id_length, username_length, password_length; + az_span data_buffer_span; + 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; 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; - password_span = az_span_split(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."); + password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_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( &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); 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); - EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); + client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_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( &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."); - 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( &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] mqtt_client_config A pointer to a generic structure to contain the configuration for * 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) { - az_span data_buffer_span, client_id_span, username_span, password_span; - size_t client_id_length, username_length, password_length; + az_span data_buffer_span; + 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; 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; - password_span = az_span_split(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."); + password_span = split_az_span(data_buffer_span, MQTT_PASSWORD_BUFFER_SIZE, &data_buffer_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( &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); 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); - EXIT_IF_TRUE(az_span_is_empty(client_id_span), RESULT_ERROR, "Failed allocating buffer for client_id_span."); + client_id_span = split_az_span(data_buffer_span, MQTT_CLIENT_ID_BUFFER_SIZE, &data_buffer_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( &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."); - 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( &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(); 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. - plain_sas_signature = az_span_split(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."); + plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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( 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. - sas_signature = az_span_split(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."); + sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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); - EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); + decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); + EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key."); 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); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); // Step 2.c. - sas_hmac256_signed_signature = az_span_split(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."); + sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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(plain_sas_signature), az_span_size(plain_sas_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(); 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. - plain_sas_signature = az_span_split(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."); + plain_sas_signature = split_az_span(data_buffer_span, PLAIN_SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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( 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. - sas_signature = az_span_split(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."); + sas_signature = split_az_span(data_buffer_span, SAS_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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); - EXIT_IF_TRUE(az_span_is_empty(decoded_sas_key), 0, "Failed allocating buffer for decoded_sas_key."); + decoded_sas_key = split_az_span(data_buffer_span, DECODED_SAS_KEY_BUFFER_SIZE, &data_buffer_span); + EXIT_IF_TRUE(is_az_span_empty(decoded_sas_key), 0, "Failed reserving buffer for decoded_sas_key."); 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); EXIT_IF_TRUE(result != 0, 0, "Failed decoding SAS key."); // Step 2.c. - sas_hmac256_signed_signature = az_span_split(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."); + sas_hmac256_signed_signature = split_az_span(data_buffer_span, SAS_HMAC256_ENCRIPTED_SIGNATURE_BUFFER_SIZE, &data_buffer_span); + 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(plain_sas_signature), az_span_size(plain_sas_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; } +/** + * @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) { az_span custom_property; 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); - EXIT_IF_TRUE(az_span_is_empty(custom_property), AZ_SPAN_EMPTY, "Failed generating DPS register custom property."); + custom_property = split_az_span(data_buffer, length, remainder); + 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)); - 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); - 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)); - 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; } /* --- 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); - 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)); } @@ -1240,16 +1274,16 @@ az_span az_span_split(az_span span, int32_t size, az_span* remainder) 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; } - if (!az_span_is_empty(result)) + if (!is_az_span_empty(result)) { (void)az_span_copy(result, source); } diff --git a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.h b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.h index a7a48e4..4cf5221 100644 --- a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.h +++ b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/AzureIoT.h @@ -2,8 +2,10 @@ // SPDX-License-Identifier: MIT /* - * AzureIoT.cpp contains a state machine that implements those steps, plus abstractions to simplify - * its overall use. Besides the basic configuration needed to access the Azure IoT services, + * AzureIoT.cpp contains a state machine that implements the necessary calls to azure-sdk-for-c + * 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: * - Interact with your MQTT client, * - Perform data manipulations (HMAC SHA256 encryption, Base64 decoding and encoding), @@ -57,13 +59,13 @@ extern log_function_t default_logging_function; #endif // DISABLE_LOGGING -/* --- Azure Abstraction --- */ +/* --- Azure Definitions --- */ #define DPS_GLOBAL_ENDPOINT_FQDN "global.azure-devices-provisioning.net" -#define DPS_GLOBAL_ENDPOINT_PORT 8883 -#define IOT_HUB_ENDPOINT_PORT 8883 +#define DPS_GLOBAL_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT +#define IOT_HUB_ENDPOINT_PORT AZ_IOT_DEFAULT_MQTT_CONNECT_PORT #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, @@ -83,12 +85,13 @@ typedef enum mqtt_qos_t_enum 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. * @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 * 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 { @@ -105,12 +108,12 @@ mqtt_message_t; 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; /* - * @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; @@ -133,12 +136,12 @@ mqtt_client_config_t; /* * @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; /* - * @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 * 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 @@ -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); /* - * @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 * 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). @@ -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 * 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. - * @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. * * @@ -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 * 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. @@ -213,13 +214,13 @@ typedef struct mqtt_client_interface_t_struct { mqtt_client_init_function_t mqtt_client_init; 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_subscribe_function_t mqtt_client_subscribe; } 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. * * @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); /* - * @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. * * @param[in] data Buffer containing the Base64-decoded content. * @param[in] data_length Length of `data`. - * @param[in] decoded Buffer where to write the Base64-encoded content of `data`. - * @param[in] decoded_size Size of `encoded`. - * @param[out] decoded_length The final length of the Base64-encoded content written in + * @param[in] encoded Buffer where to write the Base64-encoded content of `data`. + * @param[in] encoded_size Size of `encoded`. + * @param[out] encoded_length The final length of the Base64-encoded content written in * the `encoded` buffer. * * @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); /* - * @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. * * @param[in] key Encryption key to be used in the HMAC-SHA256 algorithm. * @param[in] key_length Length of `key`. * @param[in] payload Buffer containing the data to be encrypted. * @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. * * @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. @@ -270,7 +271,7 @@ typedef struct data_manipulation_functions_t_struct { base64_decode_function_t base64_decode; 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; @@ -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); /* - * @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 { @@ -323,7 +324,7 @@ typedef struct command_request_t_struct 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 * `azure_iot_send_command_response`. * @@ -335,7 +336,7 @@ command_request_t; 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 { @@ -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 * 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 - * 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. */ typedef struct azure_iot_config_t_struct @@ -447,8 +448,8 @@ typedef struct azure_iot_config_t_struct az_span device_id; /* - * @brief Symetric 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 + * @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, if using SAS-token * authentication (which is used, for example, when connecting to Azure IoT Central). */ 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 * 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 not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) 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 * 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 not being used (i.e., Azure IoT client is connecting directly to Azure IoT Hub) 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; /* - * @brief Model ID of the Azure Plug-and-Play template implemented by the user application. - * @remark This is used only when the application uses/implements Azure IoT Plug-and-Play. + * @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 IoT Plug and Play. */ 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. - * @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, - * 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. */ 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 * 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. */ 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 * 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. */ properties_received_t on_properties_received; @@ -590,7 +591,7 @@ typedef struct azure_iot_t_struct 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, * 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 * configuration neeeded for the client to connect and work with * 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. @@ -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); /** - * @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] message An `az_span` with the message with the reported properties update - * (a JSON document formatted according to the DTDL specification). - * `message` gets passed as-is to the MQTT client publish function as the payload, so if - * your MQTT client expects a null-terminated string for payload, make sure `message` is - * a null-terminated string. - * @param[in] request_id An unique identification number to correlate the response with when - * `on_properties_update_completed` (set in azure_iot_config_t) is invoked. + * @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 An unique identification number to correlate the response with when + * @param[in] message An `az_span` with the message with the reported properties update + * (a JSON document formatted according to the DTDL specification). + * `message` gets passed as-is to the MQTT client publish function as the payload, so if + * your MQTT client expects a null-terminated string for payload, make sure `message` is + * a null-terminated string. + * `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); /** - * @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] 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. * @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. * * @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. * @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 - * 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 * 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. * * @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`. @@ -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`. */ -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`. @@ -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. */ -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 diff --git a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_Central_ESP32_AzureIoTKit.ino b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_Central_ESP32_AzureIoTKit.ino index 92df1b9..f096627 100644 --- a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_Central_ESP32_AzureIoTKit.ino +++ b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_Central_ESP32_AzureIoTKit.ino @@ -12,9 +12,9 @@ * 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/. * - * 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. - * 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. * * 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), * - 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. * * 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. */ -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. // 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; } @@ -242,7 +242,7 @@ static int mqtt_client_publish_function(mqtt_client_handle_t mqtt_client_handle, /* --- 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) { @@ -330,7 +330,7 @@ void setup() /* * 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. */ 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_subscribe = mqtt_client_subscribe_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_encode = base64_encode; azure_iot_config.on_properties_update_completed = on_properties_update_completed; azure_iot_config.on_properties_received = on_properties_received; azure_iot_config.on_command_request_received = on_command_request_received; - if (azure_iot_init(&azure_iot, &azure_iot_config) != 0) - { - LogError("Failed initializing the Azure IoT client."); - } - else - { - LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state); - azure_iot_start(&azure_iot); - } + azure_iot_init(&azure_iot, &azure_iot_config); + azure_iot_start(&azure_iot); + + LogInfo("Azure IoT client initialized (state=%d)", azure_iot.state); } void loop() @@ -451,7 +446,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event) int i, r; case MQTT_EVENT_ERROR: - LogError("MQTT client in ERROR state."); + LogError("MQTT client in ERROR state."); LogError( "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, @@ -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"); break; default: - LogError("connect_return_code=unknown"); + LogError("connect_return_code=unknown (%d)", event->error_handle->connect_return_code); break; }; @@ -543,7 +538,7 @@ static esp_err_t esp_mqtt_event_handler(esp_mqtt_event_handle_t event) LogInfo("MQTT client connecting."); break; default: - LogError("MQTT event UNKNOWN"); + LogError("MQTT event UNKNOWN."); break; } diff --git a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.cpp b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.cpp index d62922a..fe378aa 100644 --- a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.cpp +++ b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.cpp @@ -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 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 led2_on = false; @@ -109,6 +109,9 @@ void azure_pnp_init() esp32_azureiotkit_oled_clean_screen(); 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() @@ -216,7 +219,7 @@ int azure_pnp_handle_properties_update(azure_iot_t* azure_iot, az_span propertie size_t 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)); 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) { - LogError("Insuficient space for telemetry payload null terminator."); + LogError("Insufficient space for telemetry payload null terminator."); 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) { - LogError("Insuficient space for telemetry payload null terminator."); + LogError("Insufficient space for telemetry payload null terminator."); return RESULT_ERROR; } @@ -497,8 +500,9 @@ static int consume_properties_and_generate_response( } else { - LogError("Unexpected property received (%.*s)", + LogError("Unexpected property received (%.*s).", az_span_size(jr.token.slice), az_span_ptr(jr.token.slice)); + return RESULT_ERROR; } azrc = az_json_reader_next_token(&jr); diff --git a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.h b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.h index b9db855..c8e5284 100644 --- a/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.h +++ b/examples/Azure_IoT_Central_ESP32_AzureIoTKit/Azure_IoT_PnP_Template.h @@ -2,7 +2,7 @@ // 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. */ @@ -19,8 +19,8 @@ void azure_pnp_init(); /* - * @brief Returns the model id of the Azure Plug and Play template implemented by this module. - * @remark Every Azure Plug and Play template has a model id that must be informed by the + * @brief Returns the model id of the IoT Plug and Play template implemented by this device. + * @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. * @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); /* - * @brief Sends telemetry implemented by this Azure Plug and Play application to Azure IoT Central. - * @remark The Azure Plug and Play template implemented by this module is specific to the + * @brief Sends telemetry implemented by this IoT Plug and Play application to Azure IoT Central. + * @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. * The template defines telemetry data points for temperature, humidity, * 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. * 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). @@ -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. * @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. * * @param[in] azure_iot A pointer to a azure_iot_t instance, previously initialized diff --git a/examples/Azure_IoT_Hub_ESP32/AzIoTSasToken.cpp b/examples/Azure_IoT_Hub_ESP32/AzIoTSasToken.cpp index 2541539..3cdc2f7 100644 --- a/examples/Azure_IoT_Hub_ESP32/AzIoTSasToken.cpp +++ b/examples/Azure_IoT_Hub_ESP32/AzIoTSasToken.cpp @@ -12,7 +12,7 @@ #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) { @@ -242,7 +242,7 @@ int AzIoTSasToken::Generate(unsigned int expiryTimeInMinutes) expiryTimeInMinutes, this->sasTokenBuffer); - if (az_span_is_empty(this->sasToken)) + if (is_az_span_empty(this->sasToken)) { Logger.Error("Failed generating SAS token"); return 1; diff --git a/examples/Azure_IoT_Hub_ESP32/Azure_IoT_Hub_ESP32.ino b/examples/Azure_IoT_Hub_ESP32/Azure_IoT_Hub_ESP32.ino index fd47ba9..9cd0a60 100644 --- a/examples/Azure_IoT_Hub_ESP32/Azure_IoT_Hub_ESP32.ino +++ b/examples/Azure_IoT_Hub_ESP32/Azure_IoT_Hub_ESP32.ino @@ -6,9 +6,9 @@ * 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. * - * 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. - * 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. * * 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* mqtt_broker_uri = "mqtts://" IOT_CONFIG_IOTHUB_FQDN; 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. static esp_mqtt_client_handle_t mqtt_client; diff --git a/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino b/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino index 72ca043..6916850 100644 --- a/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino +++ b/examples/Azure_IoT_Hub_ESP8266/Azure_IoT_Hub_ESP8266.ino @@ -6,7 +6,7 @@ * 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. * - * 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. * 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. diff --git a/examples/Azure_IoT_Hub_RealtekAmebaD/Azure_IoT_Hub_RealtekAmebaD.ino b/examples/Azure_IoT_Hub_RealtekAmebaD/Azure_IoT_Hub_RealtekAmebaD.ino index 71f1ecb..c7831b5 100644 --- a/examples/Azure_IoT_Hub_RealtekAmebaD/Azure_IoT_Hub_RealtekAmebaD.ino +++ b/examples/Azure_IoT_Hub_RealtekAmebaD/Azure_IoT_Hub_RealtekAmebaD.ino @@ -36,7 +36,7 @@ static const char* ssid = IOT_CONFIG_WIFI_SSID; static const char* password = IOT_CONFIG_WIFI_PASSWORD; 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. static WiFiUDP ntp_udp_client;