Address CR comments for ESP32 Azure IoT Central samples

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

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

@ -15,8 +15,8 @@
log_function_t default_logging_function = NULL;
#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;
@ -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;
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);
}

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

@ -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

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

@ -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;
}

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

@ -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));
}

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

@ -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

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

@ -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;
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);
}

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

@ -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

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

@ -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;
}

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

@ -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);

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

@ -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

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

@ -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;

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

@ -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;

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

@ -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.

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

@ -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;