一、简介
OTA 是英文全称『Over-the-Air Technology』的缩写,翻译过来的中文含义也就是『空中下载技术』的意思。可支持通过 Wi-Fi 从云端下载新版本 ESP8266 固件,进行升级。
二、资料准备
2.1 下载SDK
下载 ESP8266_NONOS_SDK-3.0【1xl4】
2.2 复制工程
将待编译的 ESP8266_NONOS_SDK\examples\IoT_Demo 文件夹复制到 \ESP8266_NONOS_SDK 根目录下
2.3 修改用户参数区位置
根据实际使用的 ESP8266 硬件模块 Flash 大小,修改的用户参数区位置
以使用 2048 KB Flash,512+512 map 为例
在 IoT_Demo\user\user_main.c 中
#define SPI_FLASH_SIZE_MAP 4
修改为4
其中
SYSTEM_PARTITION_CUSTOMER_PRIV_PARAM_ADDR 0x7c000
为0x7c
三、工作流程
搭建TCP客户端
↓
接收服务器升级请求
↓
向服务器返回响应
↓
获取升级版本号
↓
升级开始
↓
获取服务器信息
↓
检查当前运行的bin文件
↓
下载升级固件
↓
下载完成,重启
四、代码修改
接入乐鑫云查看 ESP8266学习笔记(14)——接入乐鑫云Iot·Espressif
在文章 2.8.1 处理GET请求URL
中 configSystemUpgrade(pStr); // 配置系统升级
函数
4.1 configSystemUpgrade
/**
@brief 配置系统升级
@param pStr -[in] 待比较字符串
@return 无
*/
static void ICACHE_FLASH_ATTR
configSystemUpgrade(char *pStr)
{
struct upgrade_server_info *pServerInfo = NULL;
sendResponse(s_receiveData);
pServerInfo = (struct upgrade_server_info *) os_zalloc(sizeof(struct upgrade_server_info));
os_memcpy(pServerInfo->upgrade_version, pStr + 12, 16);
pServerInfo->upgrade_version[15] = '\0';
os_sprintf(pServerInfo->pre_version,"%s%d.%d.%dt%d(%s)", VERSION_TYPE, IOT_VERSION_MAJOR,\
IOT_VERSION_MINOR, IOT_VERSION_REVISION, device_type, UPGRADE_FALG);
espPlatformUpgradeBegin(pServerInfo);
}
创建升级结构体 struct upgrade_server_info *pServerInfo = NULL;
回复服务器响应 sendResponse(s_receiveData);
获取升级版本号 os_memcpy(pServerInfo->upgrade_version, pStr + 12, 16);
升级开始 espPlatformUpgradeBegin(pServerInfo);
4.2 sendResponse
/**
@brief 发送响应
@param pRecvData -[in] 接收的数据
@return 无
*/
static void ICACHE_FLASH_ATTR
sendResponse(uint8 *pRecvData)
{
int nonce = 0;
char *pSendData = (char *) os_zalloc(SEND_DATA_SIZE);
nonce = parseNonceFromReceiveData(pRecvData);
if(pSendData != NULL)
{
os_sprintf(pSendData, TCP_SERVER_RESPONSE_FRAME, nonce);
os_printf("%s\n", pSendData);
espconn_sent(&s_espPlatformTcpEspconn, pSendData, os_strlen(pSendData));
os_free(pSendData);
pSendData = NULL;
}
}
4.2.1 parseNonceFromReceiveData
/**
@brief 解析随机数
@param pRecvData -[in] 接收的数据
@return 随机数值
*/
static int ICACHE_FLASH_ATTR
parseNonceFromReceiveData(char *pRecvData)
{
char *pStr = NULL;
char *pParse = NULL;
char nonceStr[11] = {0};
int nonce = 0;
pStr = (char *) os_strstr(pRecvData, "\"nonce\": ");
if(pStr != NULL)
{
pStr += 9;
pParse = (char *) os_strstr(pStr, ",");
if(pParse != NULL)
{
os_memcpy(nonceStr, pStr, pParse - pStr);
}
else
{
pParse = (char *) os_strstr(pStr, "}");
if(pParse != NULL)
{
os_memcpy(nonceStr, pStr, pParse - pStr);
}
else
{
pParse = (char *) os_strstr(pStr, "]");
if (pParse != NULL)
{
os_memcpy(nonceStr, pStr, pParse - pStr);
}
else
{
return 0;
}
}
}
nonce = atoi(nonceStr);
}
return nonce;
}
4.3 espPlatformUpgradeBegin
/**
@brief ESP平台系统升级开始
@param pServerInfo -[in] 服务器信息
@return 无
*/
static void ICACHE_FLASH_ATTR
espPlatformUpgradeBegin(struct upgrade_server_info *pServerInfo)
{
uint8 userBin[9] = {0};
uint8 deviceKey[41] = {0};
GetDeviceKey(deviceKey);
pServerInfo->pespconn = &s_espPlatformTcpEspconn;
os_memcpy(pServerInfo->ip, s_espPlatformTcpEspconn.proto.tcp->remote_ip, 4);
pServerInfo->port = 80;
pServerInfo->check_cb = espPlatformUpgradeResponse;
pServerInfo->check_times = 120000;
if(pServerInfo->url == NULL)
{
pServerInfo->url = (uint8 *) os_zalloc(512);
}
if(system_upgrade_userbin_check() == UPGRADE_FW_BIN1)
{
os_memcpy(userBin, "user2.bin", 10);
}
else if(system_upgrade_userbin_check() == UPGRADE_FW_BIN2)
{
os_memcpy(userBin, "user1.bin", 10);
}
os_sprintf(pServerInfo->url,
"GET /v1/device/rom/?action=download_rom&version=%s&filename=%s HTTP/1.0\r\nHost: "IPSTR":%d\r\n"pheadbuffer"",
pServerInfo->upgrade_version, userBin, IP2STR(pServerInfo->ip),
pServerInfo->port, deviceKey);
os_printf("%s\n",pServerInfo->url);
if(system_upgrade_start(pServerInfo) == false)
{
os_printf("upgrade is already started\n");
}
}
获取连接句柄 pServerInfo->pespconn = &s_espPlatformTcpEspconn;
获取服务器IP os_memcpy(pServerInfo->ip, s_espPlatformTcpEspconn.proto.tcp->remote_ip, 4);
获取服务器端口 pServerInfo->port = 80;
升级完成后回调函数 pServerInfo->check_cb = espPlatformUpgradeResponse;
定时回调时间 pServerInfo->check_times = 120000;
获取系统的目前加载的是哪个bin文件 system_upgrade_userbin_check()
获取服务器URL os_sprintf(pServerInfo->url, "GET /v1/device/rom/?action=download_rom&version=%s&filename=%s HTTP/1.0\r\nHost: "IPSTR":%d\r\n"pheadbuffer"", pServerInfo->upgrade_version, userBin, IP2STR(pServerInfo->ip), pServerInfo->port, deviceKey);
开始下载升级固件 system_upgrade_start()
4.3.1 GetDeviceKey
/**
@brief 获取设备密码
@param pToken -[in&out] 密钥
@return 无
*/
void ICACHE_FLASH_ATTR
GetDeviceKey(uint8_t *pDeviceKey)
{
if(!pDeviceKey)
{
return ;
}
os_memcpy(pDeviceKey, s_flahSavedParam.devkey, sizeof(s_flahSavedParam.devkey));
}
4.3.2 espPlatformUpgradeResponse
/**
@brief ESP平台系统升级响应
@param arg -[in] 指向传递给这个回调函数来使用的参数
@return 无
*/
static void ICACHE_FLASH_ATTR
espPlatformUpgradeResponse(void *arg)
{
struct upgrade_server_info *pServerInfo = arg;
struct espconn *pEspconn = pServerInfo->pespconn;
uint8 deviceKey[41] = {0};
char *pAction = NULL;
GetDeviceKey(deviceKey);
uint8 *pSendData = (char *) os_zalloc(SEND_DATA_SIZE);
if(pServerInfo->upgrade_flag == true)
{
os_printf("user_esp_platform_upgarde_successfully\n");
pAction = "device_upgrade_success";
os_sprintf(pSendData, UPGRADE_FRAME, deviceKey, pAction,
pServerInfo->pre_version, pServerInfo->upgrade_version);
os_printf("%s\n", pSendData);
espconn_sent(pEspconn, pSendData, os_strlen(pSendData));
system_upgrade_reboot(); // 升级后重启
if(pSendData != NULL)
{
os_free(pSendData);
pSendData = NULL;
}
}
else
{
os_printf("user_esp_platform_upgrade_failed\n");
pAction = "device_upgrade_failed";
os_sprintf(pSendData, UPGRADE_FRAME, deviceKey, pAction,
pServerInfo->pre_version, pServerInfo->upgrade_version);
os_printf("%s\n", pSendData);
espconn_sent(pEspconn, pSendData, os_strlen(pSendData));
if(pSendData != NULL)
{
os_free(pSendData);
pSendData = NULL;
}
}
os_free(pServerInfo->url);
pServerInfo->url = NULL;
os_free(pServerInfo);
pServerInfo = NULL;
}
五、烧录
例如4M的Flash
• 由 Leung 写于 2019 年 10 月 11 日
• 参考:ESP8266 Non-OS SDK API参考[7qq6]
ESP8266 Non-OS SDK IoT Demo指南[kvle]
ESP8266云端升级指南[5oh3]
Esp8266进阶之路18 esp8266 基于NONOS实现 OTA 远程升级