Address CR comments for ESP32 Azure IoT Central samples
This commit is contained in:
Родитель
041de369dc
Коммит
ffa12ad78a
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче