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;
}
}
}