Descargue un paquete de actualización over-the-air (OTA) que contiene un solo archivo mediante HTTPS y realice una actualización en un dispositivo. Para ello, se utiliza el archivo de código de ejemplo ./demo/fota_posix_demo.c.
Contexto
Descripción general de la función de actualización OTA: Overview.
utiliza conexiones MQTT. Para consultar ejemplos de código relacionados, consulte MQTT connection.
Paso 1: Inicializar un cliente
-
Agregue los archivos de encabezado.
... …… #include "aiot_ota_api.h" …… -
Configure las dependencias subyacentes y la salida de registros.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb); -
Llame a la operación aiot_ota_init para crear un elemento OTA
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { printf("aiot_ota_init failed\r\n"); aiot_mqtt_deinit(&mqtt_handle); return -2; }
Paso 2: Configurar las funciones obligatorias
Llame a aiot_ota_setopt para configurar los siguientes elementos.
-
Asocie un identificador de conexión MQTT.
ImportanteAntes de establecer los parámetros de OTA, asegúrese de que la autenticación del dispositivo esté configurada. Consulte Example.
-
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle); -
Parámetro
Ejemplo
Descripción
AIOT_OTAOPT_MQTT_HANDLE
mqtt_handle
Las solicitudes TSL utilizan esta conexión.
-
-
Configure una devolución de llamada para procesar comandos de actualización OTA.
-
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, demo_ota_recv_handler); -
Parámetro
Ejemplo
Descripción
AIOT_OTAOPT_MQTT_HANDLER
demo_ota_recv_handler
Se invoca cuando el dispositivo recibe un comando de actualización OTA desde IoT Platform.
-
Paso 3: Enviar el número de versión del dispositivo
Una vez que el dispositivo establece una conexión MQTT, llame a aiot_ota_report_version para enviar el número de versión del dispositivo. IoT Platform determina si es necesaria una actualización basándose en este número de versión.
Este ejemplo envía la versión 1.0.0. En un entorno de producción, obtenga el número de versión desde la configuración del dispositivo e implemente la lógica de envío correspondiente.
Envíe el número de versión como mínimo una vez antes de realizar una actualización OTA.
cur_version = "1.0.0";
res = aiot_ota_report_version(ota_handle, cur_version);
if (res < STATE_SUCCESS) {
printf("aiot_ota_report_version failed: -0x%04X\r\n", -res);
}
Paso 4: Recibir comandos de actualización
-
Después de agregar un paquete de actualización e iniciar una tarea de actualización, IoT Platform envía un comando de actualización al dispositivo.
El dispositivo llama a la operación aiot_mqtt_recv para recibir el mensaje. Cuando el dispositivo identifica el mensaje como un comando de actualización OTA, se invoca la devolución de llamada
demo_ota_recv_handler.-
Especifique la lógica de procesamiento de la devolución de llamada.
Al definir la lógica de la devolución de llamada, tenga en cuenta los siguientes puntos:
-
IoT Platform utiliza el tema
/ota/device/upgrade/${ProductKey}/${DeviceName}para enviar el comando de actualización OTA al dispositivo.${ProductKey} y ${DeviceName} se explican en Obtain device verification information.
-
AIOT_OTARECV_FOTA indica el tipo de mensaje.
void demo_ota_recv_handler(void *ota_handle, aiot_ota_recv_t *ota_msg, void *userdata) { switch (ota_msg->type) { case AIOT_OTARECV_FOTA: { uint32_t res = 0; uint16_t port = 443; uint32_t max_buffer_len = (8 * 1024); aiot_sysdep_network_cred_t cred; void *dl_handle = NULL; void *last_percent = NULL; if (NULL == ota_msg->task_desc) { break; } …… …… } Formato de datos Alink de los comandos de actualización OTA: IoT Platform pushes OTA upgrade package information.
aiot_ota_recv_t indica el formato de datos. Link SDK analiza sintácticamente de forma automática el mensaje recibido.
Especifique la lógica de procesamiento de la devolución de llamada basándose en el código de ejemplo de Step 5: Download the update package and perform an OTA update.
-
Paso 5: Descargar el paquete de actualización y realizar una actualización OTA
El dispositivo no descarga automáticamente el paquete de actualización tras recibir el comando. Debe llamar a la API de Link SDK para descargarlo.
Después de invocar demo_ota_recv_handler, el descargador inicia una solicitud HTTPS para obtener el paquete de actualización OTA.
-
Inicialice el descargador.
Llame a aiot_download_init para crear una sesión de
downloaddl_handle = aiot_download_init(); if (NULL == dl_handle) { break; } printf("OTA target firmware version: %s, size: %u Bytes \r\n", ota_msg->task_desc->version, ota_msg->task_desc->size_total); if (NULL != ota_msg->task_desc->extra_data) { printf("extra data: %s\r\n", ota_msg->task_desc->extra_data); } memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t)); cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; cred.max_tls_fragment = 16384; cred.x509_server_cert = ali_ca_cert; cred.x509_server_cert_len = strlen(ali_ca_cert); -
Establezca los parámetros.
Llame a aiot_download_setopt para establecer los parámetros de la tarea de descarga.
/* Set the TLS protocol for downloading. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_CRED, (void *)(&cred)); /* Set the port number of the server to be accessed. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_NETWORK_PORT, (void *)(&port)); /* Specify the information of the download task, which can be obtained from the task_desc member in the ota_msg input parameter. The information includes the download URL, firmware size, and firmware signature. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_TASK_DESC, (void *)(ota_msg->task_desc)); /* Set the callback that the SDK calls when the downloaded content is received. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_RECV_HANDLER, (void *)(demo_download_recv_handler)); /* Set the maximum buffer length for a single download. Users are notified if the limit is reached. */ aiot_download_setopt(dl_handle, AIOT_DLOPT_BODY_BUFFER_MAX_LEN, (void *)(&max_buffer_len)); /* Specify the information that is shared among different calls of AIOT_DLOPT_RECV_HANDLER. In this example, the progress information is stored. */ last_percent = malloc(sizeof(uint32_t)); if (NULL == last_percent) { aiot_download_deinit(&dl_handle); break; } memset(last_percent, 0, sizeof(uint32_t)); aiot_download_setopt(dl_handle, AIOT_DLOPT_USERDATA, (void *)last_percent); -
Inicie una solicitud de descarga.
-
Inicie el hilo de descarga
demo_ota_download_thread.res = pthread_create(&g_download_thread, NULL, demo_ota_download_thread, dl_handle); if (res != 0) { printf("pthread_create demo_ota_download_thread failed: %d\r\n", res); aiot_download_deinit(&dl_handle); free(last_percent); } else { /* Set the type of the downloading thread to detach. After the firmware is obtained, the downloading thread automatically exits. */ pthread_detach(g_download_thread); } -
Una vez habilitado el hilo
demo_ota_download_thread, llame a la operación aiot_download_send_request para iniciar una solicitud HTTPS GET y descargar el paquete de actualización desde el servidor de almacenamiento.-
void *demo_ota_download_thread(void *dl_handle) { int32_t ret = 0; printf("starting download thread in 2 seconds ......\n"); sleep(2); /* Initiate a request to download the update package from the storage server. */ /* * TODO: In this example, a single request is initiated to obtain all the content of the update package. * If the device has limited resources or the network connection is in poor condition, you can implement a segmented download. * * aiot_download_setopt(dl_handle, AIOT_DLOPT_RANGE_START, ...); * aiot_download_setopt(dl_handle, AIOT_DLOPT_RANGE_END, ...); * aiot_download_send_request(dl_handle); * * If you implement a segmented download, specify the preceding three statements in a loop. In this case, multiple requests are sent and multiple responses are received. * */ …… …… } -
Para descargas segmentadas, establezca AIOT_DLOPT_RANGE_START y AIOT_DLOPT_RANGE_END.
Ejemplo: para descargar un paquete de actualización de 1,024 bytes en dos segmentos:
Primer segmento:
AIOT_DLOPT_RANGE_START=0,AIOT_DLOPT_RANGE_END=511Segundo segmento:
AIOT_DLOPT_RANGE_START=512,AIOT_DLOPT_RANGE_END=1023
-
-
-
Reciba el paquete de actualización.
-
Después de enviar la solicitud de descarga, llame a aiot_download_recv en el hilo
demo_ota_download_threadpara recibir el paquete de actualización. La devolución de llamadademo_download_recv_handlerse activa al recibirlo. Guarde el paquete descargado en el almacenamiento local.void *demo_ota_download_thread(void *dl_handle) { …… …… while (1) { /* Receive the firmware that is sent from the server. */ ret = aiot_download_recv(dl_handle); /* After the firmware is downloaded, the return value of aiot_download_recv() is STATE_DOWNLOAD_FINISHED. Otherwise, the value is the number of bytes that are obtained. */ */ if (STATE_DOWNLOAD_FINISHED == ret) { printf("download completed\n"); break; } } …… …… } -
Defina la devolución de llamada
demo_download_recv_handlerpara almacenar el paquete de actualización descargado y realizar la actualización.NotaEste ejemplo solo imprime la respuesta. En un entorno de producción, debe almacenar el paquete de actualización e instalarlo para completar la actualización OTA.
void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata) { uint32_t data_buffer_len = 0; uint32_t last_percent = 0; int32_t percent = 0; /* You can set packet->type only to AIOT_DLRECV_HTTPBODY. */ if (!packet || AIOT_DLRECV_HTTPBODY != packet->type) { return; } percent = packet->data.percent; /* userdata can store the data that needs to be shared between different calls of demo_download_recv_handler(). */ /* In this example, the percentage of the firmware download progress is stored. */ if (userdata) { last_percent = *((uint32_t *)(userdata)); } data_buffer_len = packet->data.len; /* A negative value of percent indicates that an exception occurs during data receiving or the digest authentication fails. */ if (percent < 0) { printf("exception: percent = %d\r\n", percent); if (userdata) { free(userdata); } return; } …… …… }
-
-
Envíe el progreso de la descarga.
Después de invocar
demo_download_recv_handler, llame a aiot_download_report_progress para enviar el progreso de la descarga y cualquier error (como fallos de grabación o desconexiones de red) a IoT Platform.-
Consulte el progreso enviado:
El progreso se muestra en la consola de IoT Platform. View update status.
-
Envíe el progreso en condiciones normales o anómalas:
En caso de éxito, Link SDK calcula y envía automáticamente el valor de percent a IoT Platform mediante la devolución de llamada.
En caso de fallo (error de descarga o de grabación), reporte el error a IoT Platform. Códigos de error: aiot_ota_protocol_errcode_t.
void demo_download_recv_handler(void *handle, const aiot_download_recv_t *packet, void *userdata) { …… …… /* * TODO: * After you download the update package, save the memory whose initial position is packet->data.buffer and length is packet->data.len to the local storage location or file system of the device. * * If the burning fails, you must call the aiot_download_report_progress(handle, -4) operation to submit the error message to IoT Platform. */ /* If the value of percent is 100, all the content of the update package is downloaded. */ if (percent == 100) { /* * TODO: Burn the firmware, save the configurations, restart the device, and then switch to the new firmware to boot the device. The device must submit the version number of the new firmware to IoT Platform after the update. aiot_ota_report_version(ota_handle, new_version); For example, if the version is updated from 1.0.0 to 1.1.0, the value of new_version is 1.1.0 must be submitted to IoT Platform. IoT Platform determines that the update is successful after it receives the version number of the new firmware. Otherwise, IoT Platform determines that the update fails. */ } /* Simplify the output. Each time the download progress increases by at least 5%, the progress is printed and submitted to IoT Platform. */ if (percent - last_percent >= 5 || percent == 100) { printf("download %03d%% done, +%d bytes\n", percent, data_buffer_len); aiot_download_report_progress(handle, percent); if (userdata) { *((uint32_t *)(userdata)) = percent; } } } -
-
Salga del descargador.
Una vez completada la descarga, llame a aiot_download_deinit para destruir la sesión de
downloady cerrar el hilo de descarga.aiot_download_deinit(&dl_handle); printf("download thread exit\n");
Paso 6: Enviar el número de versión después de la actualización
Step 3: Submit the version number of the device.
Después de la actualización, envíe el número de versión más reciente. De lo contrario, IoT Platform marcará la tarea OTA con errores.
Si el dispositivo se reinicia después de la actualización, envíe el número de versión tras el reinicio.
Este ejemplo no incluye la lógica de envío de versión. Impleméntela según sus requisitos.
Paso 7: Desconectarse
MQTT se utiliza normalmente en dispositivos que requieren una conexión persistente. Por lo tanto, el programa generalmente no llega a este punto.
En el programa de ejemplo, el hilo principal se encarga de configurar los parámetros y establecer la conexión. Una vez establecida la conexión, el hilo principal puede entrar en hibernación.
Puede llamar a aiot_mqtt_disconnect para enviar un mensaje de desconexión a IoT Platform y desconectarse de la red.
res = aiot_mqtt_disconnect(mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_disconnect failed: -0x%04X\n", -res);
return -1;
}
Paso 8: Salir del programa
Llame a aiot_ota_deinit para destruir la sesión OTA
aiot_ota_deinit(&ota_handle);
Siguientes pasos
-
. En este ejemplo, se genera el archivo ejecutable
./output/fota-posix-demo.Para obtener más información, consulte Compile and run.