设备OTA开发

阿里云物联网平台为设备提供OTA升级与管理服务。本文介绍设备如何通过物联网平台完成远程升级功能。

前提条件

使用流程

如下功能时序图,以设备的应用程序./demos/ota_basic_demo.c为例,介绍设备升级过程。

image

步骤1: 设备初始化

  1. 创建设备句柄,完成设备建连。

    static void* demo_device_init(char *product_key, char *device_name, char *device_secret, char *host, uint16_t port)
    {
        int32_t res = STATE_SUCCESS;
        /* 创建设备 */
        void *device = aiot_device_create(product_key, device_name);
        if (device == NULL) {
            printf("device create failed\n");
            return NULL;
        }
        /* 设置设备密钥 */
        aiot_device_set_device_secret(device, device_secret);
    
        /* 连接配置参数初始化 */
        aiot_linkconfig_t* config = aiot_linkconfig_init(protocol);
        /* 设置服务器的host、port */
        aiot_linkconfig_host(config, host, port);
    
        /* 设置设备连接参数 */
        aiot_device_set_linkconfig(device, config);
        
        /* 设备建连 */
        res = aiot_device_connect(device);
        if (res < STATE_SUCCESS) {
            /* 尝试建立连接失败, 销毁MQTT实例, 回收资源 */
            aiot_linkconfig_deinit(&config);
            aiot_device_delete(&device);
            printf("aiot_device_connect failed: -0x%04X\n\r\n", -res);
            return NULL;
        }
    
        /* 建连成功返回设备对象 */
        aiot_linkconfig_deinit(&config);
        return device;
    }
  2. 设置OTA消息回调。

    memset(&ota_task, 0, sizeof(ota_task));
        ota_task.device = device;
        ota_task.ota_process_flag = 0;
        ota_task.filename = "fireware.bin";
        /* 设置OTA回调函数 */
        aiot_device_ota_set_callback(device, demo_ota_msg_callback, &ota_task);

步骤2: 上报设备版本号

物联网平台可根据上报的设备版本号决定是否推送升级。

  /* 上报设备版本号 */
    aiot_device_ota_report_version(device, NULL, "4.0.0");

步骤3: 请求固件信息

物联网平台部署升级固件后,会推送升级消息。当有升级任务时,设备可以主动请求升级信息。

  /* 设备主动请求升级包,如果有升级任务,会下发 */
    aiot_device_ota_request_firmware(device, NULL);

步骤4: 处理固件信息

步骤1中已设置OTA消息回调,在接收到消息后,会执行该回调函数。回调函数不能长时间阻塞,新建线程用于处理固件下载及升级动作。

static void demo_ota_msg_callback(void *device, const aiot_ota_msg_t *ota_msg, void *userdata)
{
    int32_t res = STATE_SUCCESS;
    pthread_t ota_process_thread;
    demo_ota_task_t *task = (demo_ota_task_t *)userdata;
    if(ota_msg != NULL && ota_msg->http_url != NULL) {
        /* 判断设备是否已经在执行升级,避免重复升级 */
        if(task->ota_process_flag != 0) {
            return;
        }

        /* 回调中不能长时间阻塞,拷贝消息用于异步处理, 拷贝的对象需要删除 */
        task->ota_msg = aiot_ota_msg_clone(ota_msg);
        res = pthread_create(&ota_process_thread, NULL, demo_ota_process_thread, task);
        if (res < 0) {
            aiot_ota_msg_free(task->ota_msg);
            task->ota_msg = NULL;
            printf("pthread_create demo_ota_process_thread failed: %d\n", res);
            return;
        } else {
            /* 设置线程为detach状态,用于自动资源回收 */
            pthread_detach(ota_process_thread);
        }
    } else {
        printf("ota invalid message \r\n");
    }
}

步骤5: 下载固件

下载固件会在下载完成时退出,也可设置接收固件的超时时间,超时也可退出。

    /* 下载文件 */
    res = core_http_download_request(task->ota_msg->http_url, params, task->filename, save_file, NULL);

步骤6: 固件校验

固件校验是为了确保固件是否完整,示例中采用的是MD5校验,如果校验出错,不再执行升级动作,上报校验失败的状态并退出升级。

 res = file_md5_check(task->filename, task->ota_msg->expect_digest);
    if(STATE_SUCCESS != res ) {
        /* 校验固件失败,上报状态 */
        aiot_device_ota_report_state(task->device, NULL, -3);
    }

步骤7: 上报升级状态

上报升级状态可在升级过程表示升级的进度,如下示例在固件下载完成后上报进度100%,用户可自行定义升级进度。

/* 写文件系统或者flash成功,上报升级进度 */
    aiot_device_ota_report_state(task->device, NULL, 100);

步骤8: 上报新的版本号

只有上报的版本号与新固件的版本号相同,物联网平台才会认为升级完成,建议设备重启后再上报。

 /* 更新新版本号表示升级完成,建议是重启后再上报 */
    /*
    aiot_device_ota_report_version(task->device, NULL, ota_msg->version);
    */

步骤9:设备反初始化

  /* 断开设备连接,并回收设备资源 */
    demo_device_deinit(device_client);