/*****************************************************************************
* file lib/process/pd_upgrade.c
* author WangBo
* version 1.0.0
* date 07-Feb-2023
* brief This file provides all the softwave upgrade related operation functions.
******************************************************************************
* Attention
*
*
© COPYRIGHT(c) 2024 LandPower
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of LandPower nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef CFG_DEV_TYPE_LAND_PD
/* 标准 C 库头文件 */
#include
#include
#include
#include
#include
#include
#include
/* 第三方头文件 */
/* 私有头文件 */
#include "main.h"
#include "pd_upgrade.h"
#include "pd_dau.h"
#include "pd_csg.h"
#include "pd_dbg.h"
/* Private define ------------------------------------------------------------*/
#define PD_UPG_READ_SIZE (1024*1024)
#define PD_UPG_HARDWARE_VERSON "GIS6.0"
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
typedef void (*pd_upg_sighandler)(int);
/* Private variables ---------------------------------------------------------*/
static pd_upg_ctrl_t pd_upg_ctrl;
static const char *pd_upg_type_str[PD_UPG_SEL_MAX] =
{
"all",
"cmu",
"dau"
};
/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/* description: 调用 system 下发 shell 命令
param: cmd_line -- 需要执行的命令
return: */
int _pd_upg_system(const char *cmd_line)
{
int ret = 0;
pd_upg_sighandler old_handler;
old_handler = signal(SIGCHLD, SIG_DFL);
ret = system(cmd_line);
signal(SIGCHLD, old_handler);
return ret;
}
/* description: 提取升级数据写成文件
param: addr -- 起始地址
len -- 大小
name -- 文件名字
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_write_file(int32_t addr, int32_t size, const char *name)
{
int fp_wr = -1;
int fp_rd = -1;
char *buf = NULL;
int32_t len = 0;
int32_t len_wr = 0;
int32_t len_rd = 0;
int32_t rv = E_NONE;
/* 打开文件 */
fp_wr = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fp_wr <= 0)
{
DBG(DBG_M_PD_UPGRADE, "Open %s failed!\n", name);
return E_SYS_CALL;
}
fp_rd = open(PD_UPG_SOFTWARE, O_RDONLY);
if (fp_rd <= 0)
{
close(fp_wr);
DBG(DBG_M_PD_UPGRADE, "Open " PD_UPG_SOFTWARE " failed!\n");
return E_SYS_CALL;
}
/* 偏移到读取位置 */
if (lseek(fp_rd, addr, SEEK_SET) < 0)
{
close(fp_wr);
close(fp_rd);
rv = E_SYS_CALL;
DBG(DBG_M_PD_UPGRADE, "Fseek %d failed!\n", addr);
return E_SYS_CALL;
}
/* 申请 buf */
buf = (char*)XMALLOC_Q(MTYPE_UPGRADE, PD_UPG_READ_SIZE);
if (!buf)
{
close(fp_wr);
close(fp_rd);
DBG(DBG_M_PD_UPGRADE, "Malloc failed!\n");
return E_MEM;
}
while (len < size)
{
len_rd = read(fp_rd, buf, PD_UPG_READ_SIZE);
if (len_rd > 0)
{
len_wr = write(fp_wr, buf, len_rd);
if(len_wr != len_rd)
{
DBG(DBG_M_PD_UPGRADE, "Write %s error!\n", name);
rv = E_SYS_CALL;
break;
}
}
else if(0 == len_rd)
{
break;
}
else
{
DBG(DBG_M_PD_UPGRADE, "Read " PD_UPG_SOFTWARE " error!\n");
rv = E_SYS_CALL;
break;
}
len += len_rd;
}
close(fp_rd);
close(fp_wr);
XFREE(MTYPE_UPGRADE, buf);
_pd_upg_system("sync");
sleep(1);
return rv;
}
/* description: 升级 CMU
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_upgrade_dau(void)
{
uint8_t i = 0;
int32_t offset = 0;
int32_t lenth = 0;
int32_t rv = E_ERROR;
/* 查找升级文件 */
for (i = 0; i < PD_UPG_AREA_MAX; i++)
{
if (0 == pd_upg_ctrl.head.arr_info[i].len)
{
continue;
}
if (PD_UPG_TYPE_DAU == pd_upg_ctrl.head.arr_info[i].type)
{
offset = pd_upg_ctrl.head.arr_info[i].start;
lenth = pd_upg_ctrl.head.arr_info[i].len;
break;
}
}
/* 没有找到 */
if (0 == lenth)
{
snprintf(pd_upg_ctrl.msg, 128, "DAU file is not found.");
DBG(DBG_M_PD_UPGRADE, "DAU file is not found.\n");
return E_NOT_FOUND;
}
/* 读取并写升级文件 */
rv = _pd_upg_write_file(offset, lenth, DEBUG_DAU_FILE);
if (rv != E_NONE)
{
snprintf(pd_upg_ctrl.msg, 128, "DAU write file error.");
return E_NOT_FOUND;
}
return E_NONE;
}
/* description: 升级 CMU
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_upgrade_cmu(void)
{
char cmd[128] = {0};
uint8_t i = 0;
int32_t offset = 0;
int32_t lenth = 0;
int32_t rv = E_ERROR;
/* 查找升级文件 */
for (i = 0; i < PD_UPG_AREA_MAX; i++)
{
if (0 == pd_upg_ctrl.head.arr_info[i].len)
{
continue;
}
if (PD_UPG_TYPE_CMU == pd_upg_ctrl.head.arr_info[i].type)
{
offset = pd_upg_ctrl.head.arr_info[i].start;
lenth = pd_upg_ctrl.head.arr_info[i].len;
break;
}
}
/* 没有找到 */
if (0 == lenth)
{
snprintf(pd_upg_ctrl.msg, 128, "CMU file is not found.");
DBG(DBG_M_PD_UPGRADE, "CMU file is not found.\n");
return E_NOT_FOUND;
}
/* 先备份原始文件 */
snprintf(cmd, 128, "cp -rf %s bak", PD_UPG_CMU_FILE);
_pd_upg_system(cmd);
_pd_upg_system("sync");
sleep(1);
/* 读取并写升级文件 */
rv = _pd_upg_write_file(offset, lenth, PD_UPG_CMU_FILE_BAK);
if (rv != E_NONE)
{
snprintf(pd_upg_ctrl.msg, 128, "CMU write file error.");
return E_NOT_FOUND;
}
if (rename(PD_UPG_CMU_FILE_BAK, PD_UPG_CMU_FILE) != 0)
{
snprintf(pd_upg_ctrl.msg, 128, "CMU file rename error.");
DBG(DBG_M_PD_UPGRADE, "Can't rename file %s!\n", PD_UPG_CMU_FILE_BAK);
return E_SYS_CALL;
}
DBG(DBG_M_PD_UPGRADE, "Upgrade CMU Ok.\n");
return E_NONE;
}
/* description: 升级系统
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_upgrade(void)
{
if (PD_UPG_SEL_ALL == pd_upg_ctrl.upg_type || PD_UPG_SEL_CMU == pd_upg_ctrl.upg_type)
{
LD_E_RETURN(DBG_M_PD_UPGRADE, _pd_upg_upgrade_cmu());
}
if (PD_UPG_SEL_ALL == pd_upg_ctrl.upg_type || PD_UPG_SEL_DAU == pd_upg_ctrl.upg_type)
{
LD_E_RETURN(DBG_M_PD_UPGRADE, _pd_upg_upgrade_dau());
}
return E_NONE;
}
/* description: 检测硬件版本号是否匹配
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_hardware_check(void)
{
if (strncmp(pd_upg_ctrl.head.hard_ver, PD_UPG_HARDWARE_VERSON, strlen(PD_UPG_HARDWARE_VERSON)))
{
DBG(DBG_M_PD_UPGRADE, "Hardware version(%s) not match\n", pd_upg_ctrl.head.hard_ver);
return E_ERROR;
}
return E_NONE;
}
/* description: 验证升级文件, CRC 校验升级文件并对比每段分区确定是否需要升级
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_verify_file(void)
{
int32_t rv = 0;
int fd = 0;
unsigned int crc = 0;
char *buf = NULL;
/*读取升级文件头信息*/
fd = open(PD_UPG_SOFTWARE, O_RDONLY);
if (fd < 0)
{
DBG(DBG_M_PD_UPGRADE, "Open file "PD_UPG_SOFTWARE" failed!\n");
return E_SYS_CALL;
}
rv = read(fd, &pd_upg_ctrl.head, sizeof(pd_upg_head_t));
if (rv != sizeof(pd_upg_head_t) || pd_upg_ctrl.head.magic != PD_UPG_MAGICNUM)
{
close(fd);
DBG(DBG_M_PD_UPGRADE, "Read len %d(%d), magic %x(%x)\n",
rv, sizeof(pd_upg_head_t), pd_upg_ctrl.head.magic, PD_UPG_MAGICNUM);
return E_NOT_IDENTIFY;
}
/*crc校验*/
buf = (char*)XMALLOC_Q(MTYPE_UPGRADE, PD_UPG_BLOCK_SIZE);
if (!buf)
{
close(fd);
DBG(DBG_M_PD_UPGRADE, "Malloc error!\n");
return E_MEM;
}
while (1)
{
rv = read(fd, buf, PD_UPG_BLOCK_SIZE);
if (rv < 0)
{
DBG(DBG_M_PD_UPGRADE, "Read failed!\n");
rv = E_SYS_CALL;
break;
}
else if(rv == 0)
{
rv = E_NONE;
break;
}
crc = crc32(crc, buf, (unsigned long)rv);
}
if (E_NONE == rv)
{
if (crc != pd_upg_ctrl.head.crc)
{
DBG(DBG_M_PD_UPGRADE, "CRC error!\n");
rv = E_ERROR;;
}
}
/* 释放资源 */
XFREE(MTYPE_UPGRADE, buf);
close(fd);
DBG(DBG_M_PD_UPGRADE, "Verfiy upgrade success.\n");
return rv;
}
/* description: 检测是否存在满足升级的条件
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_file_check(void)
{
int32_t rv = 0;
/* 读取升级文件并校验 */
rv = _pd_upg_verify_file();
if (rv != E_NONE)
{
snprintf(pd_upg_ctrl.msg, 128, "App CRC verify error.");
return rv;
}
/* 硬件版本号检查 */
rv = _pd_upg_hardware_check();
if (rv != E_NONE)
{
snprintf(pd_upg_ctrl.msg, 128, "Hardware is not match.");
return rv;
}
return rv;
}
/* description: 软件升级处理线程
param: parm -- 控制结构体
return: */
void *_pd_upg_handle(void *parm)
{
char cmd[128] = {0};
int32_t rv = E_ERROR;
while(1)
{
/* 文件检查 */
rv = _pd_upg_file_check();
if (rv != E_NONE)
{
break;
}
/* 升级系统 */
rv = _pd_upg_upgrade();
if (rv != E_NONE)
{
break;
}
break;
}
/* 保存升级原始文件 */
snprintf(cmd, 128, "mv " PD_UPG_SOFTWARE " bak");
_pd_upg_system(cmd);
_pd_upg_system("sync");
sleep(1);
/* 处理升级结果 */
if (E_NONE == rv)
{
DBG(DBG_M_PD_UPGRADE, "Upgrade ok.\n");
if (pd_upg_ctrl.upgrade_result)
{
pd_upg_ctrl.upgrade_result(1, "App and dua update successful.");
}
/* 升级成功, 主动重启 */
log_notice(LOG_UPGRADE, "Upgrade %s ok.", pd_upg_type_str[pd_upg_ctrl.upg_type]);
reboot_system(LOG_UPGRADE, REBOOT_UPGRADE_ALL);
}
else
{
DBG(DBG_M_PD_UPGRADE, "Upgrade failed.\n");
if (pd_upg_ctrl.upgrade_result)
{
pd_upg_ctrl.upgrade_result(0, pd_upg_ctrl.msg);
}
}
pd_upg_ctrl.is_start = FALSE;
pthread_exit(NULL);
return NULL;
}
/* description: 启动升级线程
param:
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t _pd_upg_start(void)
{
struct sched_param param;
pthread_attr_t attr;
pthread_t pid;
int32_t rv = 0;
/* 创建线程 配置线程 RR 调度, 优先级 50 */
pthread_attr_init(&attr);
param.sched_priority = 50;
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedparam(&attr, ¶m);
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
rv = pthread_create(&pid, &attr, _pd_upg_handle, NULL);
if (rv != 0)
{
log_err(LOG_UPGRADE, "PD can't create pthread %d!", rv);
return E_SYS_CALL;
}
else
{
thread_m_add("UPGRADE", pid);
}
pthread_attr_destroy(&attr);
return E_NONE;
}
/* Interface functions -------------------------------------------------------*/
/* description: 软件升级开始
param: from -- 来自谁的升级 PD_UPG_FROM_xxx
type -- 升级类型 PD_UPG_SEL_xxx
return: E_NONE - 成功, E_XXXX - 失败 */
int32_t pd_upg_start(uint8_t from, uint8_t type)
{
int32_t rv = E_NONE;
if (pd_upg_ctrl.is_start == FALSE)
{
DBG(DBG_M_PD_UPGRADE, "Start upgrade system.\n");
pd_upg_ctrl.is_start = TRUE;
pd_upg_ctrl.upg_from = from;
pd_upg_ctrl.upg_type = type;
if (PD_UPG_FROM_CSG == from)
{
pd_upg_ctrl.upgrade_result = csg_upgrade_result_send;
}
else if(PD_UPG_FROM_DBG == from)
{
//pd_upg_ctrl.upgrade_result = debug_upgrade_result_send;
}
else
{
pd_upg_ctrl.upgrade_result = NULL;
}
/* 初始化模块. */
LD_E_RETURN(DBG_M_PD_UPGRADE, _pd_upg_start());
}
else
{
DBG(DBG_M_PD_UPGRADE, "Upgrade is busy!\n");
rv = E_TIMEOUT;
}
return rv;
}
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/