Baixe um pacote de atualização over-the-air (OTA) com um único arquivo via HTTPS e atualize um dispositivo. Este tópico usa o arquivo de código de exemplo ./demo/fota_posix_demo.c.
Informações básicas
Visão geral do recurso de atualização OTA: Visão geral.
usa conexões MQTT. Para exemplos de código relacionados, consulte Conexão MQTT.
Etapa 1: Inicializar um cliente
-
Adicione os arquivos de cabeçalho.
... …… #include "aiot_ota_api.h" …… -
Configure as dependências subjacentes e a saída de log.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb); -
Chame a operação aiot_ota_init para criar uma instância OTA.
ota_handle = aiot_ota_init(); if (NULL == ota_handle) { printf("aiot_ota_init failed\r\n"); aiot_mqtt_deinit(&mqtt_handle); return -2; }
Etapa 2: Configurar os recursos necessários
Chame aiot_ota_setopt para configurar os itens a seguir.
-
Associe um identificador de conexão MQTT.
ImportanteAntes de definir os parâmetros OTA, garanta que a autenticação do dispositivo esteja configurada. Consulte Exemplo.
-
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_MQTT_HANDLE, mqtt_handle); -
Parâmetro
Exemplo
Descrição
AIOT_OTAOPT_MQTT_HANDLE
mqtt_handle
As solicitações TSL usam esta conexão.
-
-
Configure um callback para processar comandos de atualização OTA.
-
aiot_ota_setopt(ota_handle, AIOT_OTAOPT_RECV_HANDLER, demo_ota_recv_handler); -
Parâmetro
Exemplo
Descrição
AIOT_OTAOPT_MQTT_HANDLER
demo_ota_recv_handler
Invocado quando o dispositivo recebe um comando de atualização OTA do IoT Platform.
-
Etapa 3: Enviar o número de versão do dispositivo
Após o dispositivo estabelecer uma conexão MQTT, chame aiot_ota_report_version para enviar o número de versão do dispositivo. O IoT Platform determina se uma atualização é necessária com base nesse número de versão.
Este exemplo envia a versão 1.0.0. Em ambiente de produção, obtenha o número de versão nas configurações do dispositivo e implemente a lógica de envio adequadamente.
Envie o número de versão pelo menos uma vez antes de executar uma atualização 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);
}
Etapa 4: Receber comandos de atualização
-
Ao adicionar um pacote de atualização e iniciar uma tarefa de atualização, o IoT Platform envia um comando de atualização para o dispositivo.
O dispositivo chama a operação aiot_mqtt_recv para receber a mensagem. Quando o dispositivo reconhece a mensagem como um comando de atualização OTA, o callback
demo_ota_recv_handleré invocado.-
Especifique a lógica de processamento do callback.
Ao definir a lógica do callback, observe os seguintes itens:
-
O IoT Platform usa o tópico
/ota/device/upgrade/${ProductKey}/${DeviceName}para enviar o comando de atualização OTA ao dispositivo.${ProductKey} e ${DeviceName} são explicados em Obter informações de verificação do dispositivo.
-
AIOT_OTARECV_FOTA indica o tipo de mensagem.
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 dados Alink dos comandos de atualização OTA: IoT Platform envia informações do pacote de atualização OTA.
aiot_ota_recv_t indica o formato dos dados. O Link SDK analisa automaticamente a mensagem recebida.
Defina a lógica de processamento do callback com base no código de exemplo em Etapa 5: Baixar o pacote de atualização e executar uma atualização OTA.
-
Etapa 5: Baixar o pacote de atualização e executar uma atualização OTA
O dispositivo não baixa automaticamente o pacote de atualização após receber o comando. Chame a API do Link SDK para baixá-lo.
Após a invocação de demo_ota_recv_handler, o downloader inicia uma solicitação HTTPS para o pacote de atualização OTA.
-
Inicialize o downloader.
Chame aiot_download_init para criar uma sessão de
download.dl_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); -
Defina os parâmetros.
Chame aiot_download_setopt para definir os parâmetros da tarefa de download.
/* 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 uma solicitação de download.
-
Inicie a thread de download
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); } -
Com a thread
demo_ota_download_threadhabilitada, chame a operação aiot_download_send_request para iniciar uma solicitação HTTPS GET e baixar o pacote de atualização do servidor de armazenamento.-
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 downloads segmentados, defina AIOT_DLOPT_RANGE_START e AIOT_DLOPT_RANGE_END.
Exemplo: para baixar um pacote de atualização de 1.024 bytes em dois segmentos:
Primeiro segmento:
AIOT_DLOPT_RANGE_START=0,AIOT_DLOPT_RANGE_END=511Segundo segmento:
AIOT_DLOPT_RANGE_START=512,AIOT_DLOPT_RANGE_END=1023
-
-
-
Receba o pacote de atualização.
-
Após enviar a solicitação de download, chame aiot_download_recv na thread
demo_ota_download_threadpara receber o pacote de atualização. O callbackdemo_download_recv_handleré acionado após o recebimento. Salve o pacote baixado no armazenamento 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 o callback
demo_download_recv_handlerpara armazenar o pacote de atualização baixado e executar a atualização.NotaEste exemplo apenas imprime a resposta. Em produção, armazene o pacote de atualização e instale-o para concluir a atualização 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; } …… …… }
-
-
Envie o progresso do download.
Após a invocação de
demo_download_recv_handler, chame aiot_download_report_progress para enviar o progresso do download e quaisquer erros (como falha de gravação ou desconexão de rede) ao IoT Platform.-
Visualize o progresso enviado:
O progresso é exibido no console do IoT Platform. Visualizar status da atualização.
-
Envie o progresso em condições normais ou anormais:
Em caso de sucesso, o Link SDK calcula e envia automaticamente o valor de percent ao IoT Platform por meio do callback.
Em caso de falha (erro de download ou falha de gravação), relate o erro ao IoT Platform. Códigos de erro: 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; } } } -
-
Encerre o downloader.
Após a conclusão do download, chame aiot_download_deinit para destruir a sessão de
downloade encerrar a thread de download.aiot_download_deinit(&dl_handle); printf("download thread exit\n");
Etapa 6: Enviar o número de versão após a atualização
Etapa 3: Enviar o número de versão do dispositivo.
Após a atualização, envie o número de versão mais recente. Caso contrário, o IoT Platform marcará a tarefa OTA como falha.
Se o dispositivo reiniciar após a atualização, envie o número de versão depois da reinicialização.
Este exemplo não inclui a lógica de envio de versão. Implemente-a conforme seus requisitos.
Etapa 7: Desconectar
O MQTT é normalmente usado para dispositivos que exigem uma conexão persistente. Portanto, o programa geralmente não chega a este ponto.
No programa de exemplo, a thread principal configura os parâmetros e estabelece a conexão. Após o estabelecimento da conexão, a thread principal pode entrar em hibernação.
Chame aiot_mqtt_disconnect para enviar uma mensagem de desconexão ao IoT Platform e desconectar-se da rede.
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;
}
Etapa 8: Sair do programa
Chame aiot_ota_deinit para destruir a instância OTA.
aiot_ota_deinit(&ota_handle);
Próximos passos
-
Neste exemplo, o arquivo executável
./output/fota-posix-demoé gerado.Para mais informações, consulte Compilar e executar.