http文件传输

对于Linux设备,OTA、文件上传以及下载都是通过http短连接实现的。AC的联网固件会创建一个线程WRTnode_HttpThread(Sample/ac_hal.c中),在线程中进行http环境的初始化,OTA的处理等逻辑。

http环境初始化

Linux设备的http环境初始化,主要是进行设备的http连接激活。初始化时需要调用APIAC_HttpEnvironmentInit

接口说明: int AC_HttpEnvironmentInit(T_AC_HttpInitInfoB *ptACHttpInitInfoB)

字段 类型 说明
ptACHttpInitInfoB T_AC_HttpInitInfoB AC_HttpEnvironmentInit函数入参结构体

T_AC_HttpInitInfoB的定义如下:


    /*This struct define all info needed by http environment initial*/
    typedef struct 
    {
        int   cloudAddrType;
        int   domainID;     /*ID or Name, second, choose one*/
        int   subdomainID;
        char  DomainName[32];   /*ID or Name, second, choose one*/
        char  subDomainName[32];
        char  deviceID[64];
        char  equipmentVersion[20];
        char *privateKey;
    } T_AC_HttpInitInfoB;
字段 类型 说明
cloudAddrType int 设备连接的云端服务器环境类型开发准备-配置设备连接的云端服务器环境
domainID int 产品的主域ID
subdomainID int 产品的子域ID
DomainName[] char 产品的主域名称(超过32Byte会被截断)
subDomainName[] char 产品的子域名称(超过32Byte会被截断)
deviceID[] char 设备ID(超过64Byte会被截断)
equipmentVersion[] char 设备的固件版本号(超过20Byte会被截断)
privateKey char * 设备的私钥

注意:
domainID,subdomainID或者DomainName、subDomainName二者可以二选一填写

返回值(int) 说明
0 初始化成功
非0 初始化失败

如果http环境初始化失败,可以选择尝试多次。初始化成功前,不能使用OTA功能和文件上传下载的功能。 初始化失败的原因有多种,包括:

(1)主子域ID和主子域名称均未填写
(2)设备私钥```privatekey```字段为空
(3)cloudAddrType、主子域信息和设备私钥不匹配
(4)系统时间未设置
(5)网络连接异常

OTA

OTA即空中下载技术,对于设备端开发者,即是通过云端连接对WiFi固件进行升级的功能。

Linux设备OTA用于对Linux设备上的应用程序及开发者需要的其他服务程序、组件的升级替换。

对于Linux设备,由于升级的文件较大,Ablecloud提供了http的升级方式,以加快升级时间。

Ablecloud提供了两种触发OTA的方式:轮询和云端触发。这两种触发方式都在线程WRTnode_HttpThread处理。

注意:
由于云端linux设备默认只支持HTTP方式下载OTA文件,如果需要支持该方式,需要在[注册开发者账号和注册产品]过程中选择设备的操作系统时,选择Linux,windows等Linux系或Windows系操作系统。

轮询触发

线程WRTnode_HttpThread会每隔一段时间(3600s)轮询一次,调用OTA文件下载API去云端查询是否有新的OTA版本需要下载,如果有,则将文件下载到本地,如果没有,则继续休眠,直到下一次轮训时间超时。

云端推送

当开发者在Ablecloud云端控制台上传了新的OTA固件版本后,云端后台会在适当时间通知设备端,设备端处理后会将特定的标志位g_LinuxToHttpOTAFlag置位。线程WRTnode_HttpThread会每隔一段时间(3600s)轮询一次,在休眠期间,会每隔10s查询一次所述的标志位,如果该标志位被置位,则线程WRTnode_HttpThread会提前结束3600s的休眠,直接调用OTA文件下载API去云端下载OTA文件。

注意:
开发者在查询到g_LinuxToHttpOTAFlag被置位后,可以添加自己的处理逻辑,选择马上进行OTA,或者在其他合适的时间进行OTA

固件升级及切换

使用Ablecloud的Linux SDK编译出来的固件AbcloudFirmware,在Linux设备上是以进程的形式运行的,开发者需要自己修改Linux设备的守护进程,在守护进程中执行AbcloudFirmware。AbcloudFirmware的存放路径是/tmp/AbcloudFirmware,执行路径是/usr/bin/AbcloudFirmware,执行时,需要先判断存储路径下是否存在AbcloudFirmware,如果存在,将其拷贝到执行路径并运行。

进行OTA时,OTA下载得到的文件会放在存储目录中,之后在AbcloudFirmware进程会返回,开发者在守护进程中需要检测该返回值,如果是正常放回,守护进程需要将存储路径中的新的OTA股价拷贝到执行路径下并执行新的固件。

固件执行及切换脚本可以参考开发示例API文档中的11.1 固件切换脚本参考。

注意:
1. 应用程序的版本号需要由开发者维护,版本号的填写详见开发准备中的版本号部分描述
2. 设备要进行OTA,需要在Ablecloud的控制台上传用于OTA的固件版本并填写版本号
3. 设备云端激活时会将当前的设备固件版本号上报给云端,云端会比较该版本号和用于OTA的固件版本号,如果一致,则无动作,如果不一致,则触发OTA升级

升级方式

升级方式可以为用户确认的升级、静默升级和强制升级三种。

  • 用户确认的升级:在控制台发布OTA后,设备或者APP端会收到新的升级通知,用户确认之后才进行升级。
  • 静默升级:在控制台发布OTA后,设备会自动下载升级文件并完成升级。
  • 强制升级:在控制台发布OTA后,设备或者APP端会收到新的升级通知,且用户只能确认进行升级不能取消。

注意
对于使用http进行OTA的Linux设备,这三种升级方式对OTA都没有影响。

AbleCloud提供了OTA的高级设置。

高级设置中,可以选择升级的源版本、渠道和批次。其中渠道和批次需要在控制台入库或者通过设备/APP上报到云端才可以使用。

为方便测试,高级设置中提供定向发布。新版OTA开发完成后可以先针对特定几台设备进行升级测试。

HTTP OTA 升级开发示例

要使用HTTP OTA,首先要调用API AC_HttpEnvironmentInit初始化Ablecloud的HTTP环境。之后调用接口AC_OtaUpdate获取OTA文件。

接口说明: int AC_OtaUpdate(T_AC_OtaUpadateInParameter *pstruAc_OtaInParameter);

字段 类型 说明
pstruAc_OtaInParameter T_AC_OtaUpadateInParameter AC_OtaUpdate函数入参结构体

T_AC_OtaUpadateInParameter的定义如下:


    typedef struct 
    {
        int   OTAMode;
        int   OTAFileNum;
        char *DownloadFilePath;
        char *OTADescription;
        char *OTATargetVersion;
        unsigned short OTAFileLocalCheckSum[MAX_OTAFILENUM];
        AC_OtaFileInfo *DownloadOtaFileInfo;
    } T_AC_OtaUpadateInParameter;
字段 类型 说明
OTAMode int ota升级模式,mode:1代表系统升级,mode:2代表通信模组升级
OTAFileNum int ota文件数目
DownloadFilePath char * 下载的ota文件在本地的存储路径
OTADescription char * ota描述
OTATargetVersion char * 目标版本号
OTAFileLocalCheckSum[] unsigned short OTA下载的每个文件的校验值
DonwloadOtaFileInfo AC_OtaFileInfo * 存储ota文件信息数组

AC_OtaFileInfo定义如下:


    typedef struct
    {
        char chName[64];
        char chDownloadUrl[512];
        int IntFileType;
        int IntChecksum;
    }AC_OtaFileInfo;
字段 类型 说明
chName const char * ota升级文件名
chDownloadUrl char * 下载的ota文件url
IntFileType int * ota文件类型
IntChecksum char * ota文件校验值

开发示例


    int g_OTAFinished = 0;
    static void WRTnode_HttpThread(void* arg) 
    {
        int ret =0;
        u32 i = 0;
        AC_OtaFileInfo fileInfo[MAX_OTAFILENUM];
        char otadescription[64];
        char otatargetverion[32];
        int OTAFailedCnt = 0;
        int TryOTAAgainImmediately = 0;

        int OTADownloadFileNum = 0;
        int HaveNewFirmwareFlag = 0;

        T_AC_HttpInitInfoB tACHttpInitInfoB = {0};
        T_AC_OtaUpadateInParameter struAc_OtaInParameter = {0};

        sleep(20);  /*20 seconds*/

        /*init http environment*/
        tACHttpInitInfoB.cloudAddrType = CLOUD_ADDR;
        tACHttpInitInfoB.domainID      = MAJOR_DOMAIN_ID;
        tACHttpInitInfoB.subdomainID   = SUB_DOMAIN_ID;
        memcpy(tACHttpInitInfoB.deviceID, g_u8DeviceId, sizeof(g_u8DeviceId));
        memcpy(tACHttpInitInfoB.equipmentVersion, g_u8EqVersion, sizeof(g_u8EqVersion));
        printf("tACHttpInitInfoB.equipmentVersion is %s\n",tACHttpInitInfoB.equipmentVersion);
        tACHttpInitInfoB.privateKey    = (char *)g_u8ModuleKey;
        while (1)
        {
            ret = AC_HttpEnvironmentInit(&tACHttpInitInfoB);
            if (0 != ret)
            {
                ZC_Printf("AC_HttpEnvironmentInit failed, try again 30s later\n");
                AC_GetNtpTime();  //get ntp time and Calibration hw clock each 10 minutes
                sleep(30);
                continue;
            }
            ZC_Printf("AC_HttpEnvironmentInit success\n");
            break;
        }

        /*the Inparameter must be setted value*/
        struAc_OtaInParameter.OTAMode = eOTAMode_SystemUpdate;  /*OTA mode, do not modify*/
        struAc_OtaInParameter.DownloadFilePath = "/tmp";       /*path to store OTA file*/
        struAc_OtaInParameter.OTADescription = otadescription;
        struAc_OtaInParameter.OTATargetVersion = otatargetverion;
        struAc_OtaInParameter.DownloadOtaFileInfo = fileInfo;
        while(1)
        {
            TryOTAAgainImmediately = 0;
            ret = AC_OtaUpdate(&struAc_OtaInParameter);
            if (0 == ret)
            {
                OTADownloadFileNum = struAc_OtaInParameter.OTAFileNum;

                for (i = 0; i < OTADownloadFileNum; i++)
                {
                    printf("ota filename =%s\n",    fileInfo[i].chName);
                    printf("ota IntFileType =%d\n", fileInfo[i].IntFileType);
                    printf("ota IntChecksum =%d\n", fileInfo[i].IntChecksum);
                    if (fileInfo[i].IntChecksum != struAc_OtaInParameter.OTAFileLocalCheckSum[i])
                    {
                        printf("OTA get file CRC error!\n");
                        OTAFailedCnt++;
                        if (OTAFailedCnt <= 3)
                        {
                            TryOTAAgainImmediately = 1;
                        }
                        continue;
                    }
                    else
                    {
                        OTAFailedCnt = 0;
                        printf("OTA get file CRC OK!\n");
                    }
                    if (0 == i)
                    {
                        HaveNewFirmwareFlag = 1;
                    }
                }

                printf("ota Description = %s,ota target version = %s\n", otadescription, otatargetverion);

                if (1 == HaveNewFirmwareFlag)  /*application's logic. Those code are just an example.*/
                {
                    HaveNewFirmwareFlag = 0;

                    char cpCmd[200] = {0};

                    sprintf(cpCmd, "mv /tmp/%s /tmp/AbcloudFirmware.tar.gz", fileInfo[0].chName);
                    if (-1 == system(cpCmd))
                    {
                        printf("system cmd mv failed\n");
                        continue;
                    }

                    printf("to exit AbcloudFirmware\n");

                    /*resource free begin*/
                    ZC_Sleep();
                    /*resource free end*/

                    g_OTAFinished = 1;
                    exit(0);
                }
            }
            else
            {
                printf("AC_OtaUpdate Failed\n");
            }

            if (1 == TryOTAAgainImmediately)
            {
                sleep(10);  /*sleep and try OTA again 10s later*/
                printf("Try OTA again\n");
                continue;
            }

            int sleepCnt = 360;
            while (sleepCnt--)  /*sleep 3600s and check for OTA version again*/
            {
                if (1 == g_LinuxToHttpOTAFlag)
                {
                    g_LinuxToHttpOTAFlag = 0;
                    printf("to OTA, trigged by cloud\n");

                    /*todo @developer
                     @developer
                     If thread run here, means that someone upload a new OTA version and 
                     the cloud has inform the device, developer should determine whether and when to 
                     execute the OTA.*/
                    break;
                }
                sleep(10);  /*10 seconds*/
            }

            AC_GetNtpTime();  //get ntp time and Calibration hw clock each 10 minutes
            printf("OTA thread\n");
        }
    }

OTA的更多信息请参考《功能介绍》

多文件OTA

开发者可能会需要在OTA时上传下载多个文件,Ablecloud的建议是将多个待下载的文件打成压缩包(如.tar.gz格式)后进行上传和下载,下砸完成后,对压缩包进行解压,然后对不同的文件执行不同的操作。

文件存储

文件存储是AbleCloud提供的非结构化存储功能。可以用来存储头像、文件等大的数据块。单个文件最大支持4G。

注意:
文件存储的前提是http环境初始化成功,也就是调用AC_HttpEnvironmentInit成功。

下载文件

API:
int AC_DownloadFile(const char *bucketName,char *remotefilename,char *localfilepath);

字段 类型 说明
bucketName const char * 云端bucket名,不能填写为“OTA”,其他都可以。建议为有意义的名字
remotefilename char * 上传到云端的文件名
localfilename char * 存储本地文件绝对路径名或相对路径名

上传文件

API:
int AC_UploadFile(const char *bucketName, char *remotefilename, char *localfilepath);

字段 类型 说明
bucketName const char * 云端bucket名,不能填写为“OTA”,其他都可以。建议为有意义的名字
remotefilename char * 上传到云端的文件名
localfilename char * 存储本地文件绝对路径名或相对路径名

开发示例


    void main()
    {

        int ret =0;
        AC_OtaFileInfo fileInfo[MAX_OTAFILENUM];
        char otadescription[64];
        int otamode = 1;//system update
        int otadowloadfilenum = 0;
        int  i= 0;
        char deviceid[]="6666666666666666";//建议开发者采用mac地址,前面补0000,一共16个字节
        char privatekey[] = DEFAULT_IOT_PRIVATE_KEY; 
        ret = AC_DeviceServiceInit(MAJOR_DOMAIN,SUB_DOMAIN,deviceid,privatekey,deviceversion); VICE_VERSION); //初始化环境变量

        if(0 != ret)
        {
            printf("AC_DeviceServiceInit errror=%d\n",ret);
        }
        else
        {
           ret = AC_UploadFile("CompanyName","configBackup","config");
           if(0 != ret)
           {
               printf("AC_UploadFile errror=%d\n",ret);
               return;
           }
           ret =  AC_DownloadFile("CompanyName","configBackup","configBackup");
           if(0 != ret)
           {
               printf("AC_DownloadFile errror=%d\n",ret);
               return;
           }
        }
    }