1.五元组信息
(1)初始状态
初始化状态(表示升级处于空闲状态,等待用户下发升级命令)
(2)状态集合:
初始化状态(表示升级处于空闲状态,等待用户下发升级命令)、
准备状态(收到升级命令。进一步的准备处理,校验升级包、读取分区信息等)、
擦除状态(升级准备成功完成,可以开始升级擦除flash)、
写入状态(成功擦除flash,可以开始把升级包内容写入flash中)、
完成状态(写入flash完成,可以进行主备分区切换)、
失败状态(创建配置文件失败、更新版本信息失败、升级包校验不通过、分区信息读取失败、擦除flash失 败、写flash失败、分区切换失败)、
成功状态 (主备分区成功切换,整个升级流程完成)
(3)输入字母表(输入事件)
用户下达升级命令
校验升级包内容
擦除flash设备
升级包写入flash设备
主备分区切换
(4)转移函数
创建系统配置文件失败、读取分区信息失败,则由初始化状态转为失败状态
成功接受到用户升级命令,则由初始化状态转为准备状态
升级包校验失败,则由准备状态转为失败状态
升级包校验成功,则由准备状态转为擦除状态
擦除flash设备失败,则由擦除状态转为失败状态
擦除flash设备成功,则由擦除状态转为写入状态
写入flash设备失败,则由写入状态转为失败状态
写入flash设备成功,则由写入状态转为完成状态
主备分区切换成功,则由完成状态转为成功状态
(5)终止状态集合
失败状态(记录上报升级失败原因)
成功状态(重启,新固件生效)
2.完整代码实现
test.cpp
/*******************************************************************************
* Copyright (C), 2020-2023, hkzy Co., Ltd.:
* FileName :
* Author : 王梓涵
* Description :
* Others :
* Function List:
* LastEditTime : 2024-03-08 15:02:46
* FilePath : \fsm\.vscode\fsm_test\fsm_test.cpp
******************************************************************************/
#include <iostream>
#include <vector>
#include <malloc.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <thread>
#include <chrono>
#include <stdio.h>
#include "test.h"
using namespace std;
static size_t length = 1;
/* 文件隔离 or xml */
//static void set_upgrade_state(int status);/* 数据保存文件中 */
//static void get_upgrade_state(int status);/* 文件中获取数据 */
//
//static void set_upgrade_progress(int progress);/* 数据保存文件中 */
//static void get_upgrade_progress(int progress);/* 文件中获取数据 */
//
//static void set_upgrade_file_name(char* file_name);/* 数据保存文件中 */
//static void get_upgrade_file_name(char* file_name);/* 文件中获取数据 */
//static int get_upgrade_state(int state) //获取状态,包括正常和异常状态
//{
// //获取当前状态操作
// state = get_data_json(UPGRADE_FILE_PATH, state); //例如:文件中获取 or xml中获取
// return state;
//}
/**************************升级状态枚举*******************************/
//typedef enum {
// UPDATE_INIT, // 升级初始化状态
// UPDATE_PREPARATION, // 升级准备状态
// UPDATE_ERASING, // 擦除状态
// UPDATE_WRITING, // 写入状态
// UPDATE_CONPELET // 完成状态
// UPDATE_SUCCESS, // 成功完成
// UPDATE_FAIL, // 失败状态
//} upgrade_state_list_e;
/****************************升级状态机 结构体*******************************/
typedef struct {
upgrade_state_e up_state; /**< 状态记录 */
fw_upgrade_init init_interface; /**< 初始化接口 */
read_upgrade_state read_state; /**< 读取当前升级状态*/
upgrade_sys_part_e sys_part; /**< 系统分区 */
upgrade_fw_type_e fw_type_e; /**< 升级固件类型 */
bool verificationPassed; /**< 升级包校验 */
const char* dev_name; /**< 设备flash路径 */
int upgrade_pogress; /**< 升级进度 */
const char* upgrade_file_name; /**< 升级包路径名称 */
} io_upgrade_dev_st;
/*************************升级状态机 结构体************************************/
/*****************************************************************
* 创建系统配置文件操作
******************************************************************/
int create_file(std::string file_name)
{
int tmp;
printf("请输入1创建成功,其他为创建失败:");
scanf_s("%d", &tmp, sizeof(tmp), &length);
if (tmp == 1)
{
printf("已创建文件:%s", file_name.c_str());
return 1;
}
else
{
printf("error!!!");
return 0;
}
}
/*****************************************************************
* 更新版本信息
******************************************************************/
void update_fw_version(std::vector<int> bmc_version_num)
{
std::cout << "当前固件版本:";
for (int elem : bmc_version_num) {
std::cout << elem << ".0";
}
std::cout << std::endl;
}
/*****************************************************************
* 固件初始化
******************************************************************/
static void up_init(void) //初始状态
{
std::vector<int> bmc_version_num = { FW_VERSION_MAIN, FW_VERSION_SUB }; //固件版本信息
update_fw_version(bmc_version_num);//更新版本信息(同时把版本信息写入文件中)
//...........
}
/*****************************************************************
* (文件中或者xml中)获取状态信息
******************************************************************/
static int get_upgrade_state(int state)
{
//printf("\n读取到的状态为:state = %d", state);
return state;
}
/*****************************************************************
* 状态机结构体定义
******************************************************************/
static io_upgrade_dev_st dev_ice =
{
.init_interface = up_init,
.read_state = get_upgrade_state,
};
/*****************************************************************
* 配置文件是否创建成功
******************************************************************/
int file_exit(std::string file_name)
{
if (create_file(file_name))
{
printf("配置文件存在\n");
return 0;
}
else
{
printf("配置文件创建失败\n");
}
}
/*****************************************************************
* 延时函数
******************************************************************/
static void delay(int seconds) //延时
{
std::this_thread::sleep_for(std::chrono::seconds(seconds));
//printf("延时时间:%d\n", seconds);
return;
}
/*****************************************************************
* 文件中写入数据
******************************************************************/
void set_data_config(io_upgrade_dev_st* device, std::string file_name)
{
if (!file_name.empty())
{
printf("成功向配置文件中写入数据:%s\n", file_name.c_str());
}
}
/*****************************************************************
* 读取系统分区信息
******************************************************************/
void read_sys_partment(io_upgrade_dev_st* device)
{
upgrade_sys_part_e part;
printf("读取当前运行的分区0为主分区,1为备份分区:");
scanf_s("%d", &part, sizeof(part), &length);
device->sys_part = part;
if (device->sys_part = MAIN_PARAT)
{
printf("选择主分区\n");
}
else
{
printf("选择备份分区\n");
}
}
/*****************************************************************
* 擦除操作
******************************************************************/
int erase_action(io_upgrade_dev_st* device)
{
printf("upgrade_file 擦除操作 \n");
if (device->upgrade_file_name != NULL)
{
printf("擦除flash成功\n");
return 1;
}
else
{
printf("擦除flash失败\n");
return 0;
}
}
int write_action(io_upgrade_dev_st* device)
{
if (device->upgrade_file_name != NULL)
{
printf("写flash成功\n");
return 1;
}
else
{
printf("写flash失败\n");
return 0;
}
}
/*****************************************************************
* 校验操作
******************************************************************/
bool verify(io_upgrade_dev_st* device, std::string key)
{
printf("校验通过\n");
return true;
}
/**********************************************************
*状态改变函数
**********************************************************/
void io_upgrade_change_state(io_upgrade_dev_st* device, upgrade_state_e newstate)
{
device->up_state = newstate;
switch (device->up_state)
{
case UPDATE_INIT:
printf("当前状态:启动升级状态\n");
break;
case UPDATE_IDLE:
printf("当前状态:空闲状态\n");
break;
case UPDATE_PREPARATION:
printf("准备状态!\n");
break;
case UPDATE_ERASING:
printf("擦除状态!!\n");
break;
case UPDATE_WRITING:
printf("写状态!!\n");
break;
case UPDATE_CONPELET:
printf("完成状态!!\n");
break;
case UPDATE_SUCCESS:
printf("成功状态!!\n");
break;
default:
printf("error\n");
break;
}
//set_upgrade_state(device->up_state); //状态存入文件中 or 存到xml
printf("状态存入文件!\n");
}
/**********************************************************
*flash设备选择
**********************************************************/
static void Choose_Dev_Address(io_upgrade_dev_st* device, upgrade_flash_name_e falsh_name)
{
switch (falsh_name)
{
case FLASH_CONFIG:
device->dev_name = "/dev/mtd4";
printf("选择/dev/mtd4\n");
break;
case FLASH_RO:
if (device->sys_part == MAIN_PARAT)
{
device->dev_name = "/dev/mtd5"; //注:此处字符串应使用宏定义
printf("选择/dev/mtd5\n");
}
else if (device->sys_part == SUB_PART)
{
device->dev_name = "/dev/mtd7";
printf("选择/dev/mtd7\n");
}
break;
case FLASH_RW:
if (device->sys_part == MAIN_PARAT)
{
device->dev_name = "/dev/mtd6"; //注:此处字符串应使用宏定义
printf("选择/dev/mtd6\n");
}
else if (device->sys_part == SUB_PART)
{
device->dev_name = "/dev/mtd8";
printf("选择/dev/mtd8\n");
}
break;
default:
device->dev_name = NULL;
printf("choose flash error!");
break;
}
}
/**********************************************************
*读取当前系统运行分区
**********************************************************/
int io_upgrade_read_part(io_upgrade_dev_st* device)
{
Choose_Dev_Address(device, FLASH_CONFIG); // 系统配置文件设备地址
read_sys_partment(device); //读取分区操作
if (device->sys_part == MAIN_PARAT || device->sys_part == SUB_PART)
{
set_data_config(device, "/home/sys_start.config"); //分区信息写入配置文件
return 1;
}
else
{
printf("读取当前系统运行分区失败\n");
io_upgrade_change_state(device, RET_UP_PARTMENT);
return 0;
}
}
/**********************************************************
* 初始化升级功能
**********************************************************/
void io_upgrade_init(io_upgrade_dev_st* device)
{
if ((device != NULL) && (device->init_interface != NULL))
{
/* 初始化 */
device->init_interface();
if (!file_exit("/home/sys_start.config") && io_upgrade_read_part(device)) //字符串使用宏定义
{
printf("升级初始化成功!\n");
io_upgrade_change_state(device, UPDATE_INIT);
}
else
{
printf("创建系统配置文件失败 or 读取分区信息失败!");
io_upgrade_change_state(device, RET_UP_CONFIG); //状态设置为错误状态
}
}
}
/**********************************************************
*切换系统分区
**********************************************************/
void io_upgrade_change_part(io_upgrade_dev_st* device, upgrade_sys_part_e part)
{
device->sys_part = part;
printf("主备分区切换\n");
set_data_config(device, "/home/sys_start.config"); //宏定义
Choose_Dev_Address(device, FLASH_CONFIG); //设置config 设备地址
if (write_action(device))
{
io_upgrade_change_state(device, UPDATE_SUCCESS); //成功
}
else
{
io_upgrade_change_state(device, RET_UP_SW_PART); //失败
}
}
/**********************************************************
*解析升级包内容选择升级固件类型
**********************************************************/
void io_upgrade_fw_choose(io_upgrade_dev_st* device)
{
upgrade_fw_type_e type;
printf("输入升级的固件类型,选择升级通道1为bmc,2为cpld:");
scanf_s("%d", &type, sizeof(type), &length);
device->fw_type_e = type;//解析升级包操作
device->upgrade_file_name = "/tmp/image-bmc";//解析升级包操作
//get_upgrade_file_name(device->upgrade_file_name);
// type = //解析升级包操作
// switch (type)
// {
// case 1:
// device->fw_type_e = EXU_BMC;
// break;
// case 2:
// device->fw_type_e = EXU_CPLD;
// break;
// case 3:
// //................
// break;
// default:
// break;
// }
//io_upgrade_change_state(device, UPDATE_PREPARATION); //切换为升级准备状态
}
/**********************************************************
*校验升级包内容
**********************************************************/
void io_upgrade_verify_package(io_upgrade_dev_st* device)
{
device->upgrade_file_name = "";
/* 校验通过为true 没有则为false */
device->verificationPassed = verify(device, "publickey");//校验操作
if (device->verificationPassed == true)
{
printf("升级包校验通过!\n");
io_upgrade_change_state(device, UPDATE_ERASING);
}
else
{
printf("升级包校验失败!\n");
io_upgrade_change_state(device, RET_UP_VERIFY_ERR);
}
}
/**********************************************************
*升级擦除操作
**********************************************************/
int io_upgrade_erase(io_upgrade_dev_st* device)
{
switch (device->fw_type_e)
{
case EXU_BMC:
Choose_Dev_Address(device, FLASH_RO); //设置ro 设备地址
if (erase_action(device))
{
io_upgrade_change_state(device, UPDATE_WRITING);//设为写入状态
}
else
{
io_upgrade_change_state(device, RET_UP_ERASE_ERR); //失败
}
break;
case EXU_CPLD:
/* 升级cpld操作 */
break;
default:
break;
}
return 0;
}
/**********************************************************
*异常状态处理
**********************************************************/
void io_upgrade_handle_wrong_state(io_upgrade_dev_st* device)
{
switch (device->up_state)
{
case RET_UP_CONFIG:
//异常处理1
printf("系统配置文件错误"); //异常原因日志记录
break;
case RET_UP_PARTMENT:
//异常处理2
printf("读取分区信息错误");
break;
case RET_UP_FILE:
//异常处理3
printf("升级文件不存在");
break;
case RET_UP_READ_FLASH:
//异常处理4
printf("读取系统flash失败");
break;
case RET_UP_GET_SOURCE:
//异常处理5
printf("获取源文件失败");
break;
case RET_UP_VERIFY_ERR:
//异常处理6
printf("升级文件校验失败");
break;
//................
default:
break;
}
}
/**********************************************************
*升级进度改变
**********************************************************/
void io_upgrade_change_progress(io_upgrade_dev_st* device, int upgrade_pogress)
{
if (upgrade_pogress >= 0 && upgrade_pogress <= 100)
{
device->upgrade_pogress = upgrade_pogress;
printf("当前升级进度:%d\n", device->upgrade_pogress);
//set_upgrade_progress(device->upgrade_pogress); //写入文件中
}
else
{
printf("进度设置失败");
}
}
/**********************************************************
*升级写入操作
**********************************************************/
int io_upgrade_write(io_upgrade_dev_st* device)
{
switch (device->fw_type_e)
{
case EXU_BMC:
Choose_Dev_Address(device, FLASH_RO); //设置ro 设备地址
if (write_action(device))
{
io_upgrade_change_state(device, UPDATE_CONPELET);//设为完成状态
}
else
{
io_upgrade_change_state(device, RET_UP_WRITE_ERR); //失败
}
break;
case EXU_CPLD:
/* 升级cpld操作 */
break;
default:
break;
}
return 0;
}
/**********************************************************
*状态机运行
**********************************************************/
void io_upgrade_loop(io_upgrade_dev_st* device)
{
int current_state = 0;
if ((device == NULL))
{
return;
}
device->read_state(current_state);
while (1)
{
switch (device->up_state)
{
case UPDATE_INIT:
//接收升级命令后
io_upgrade_change_state(device, UPDATE_PREPARATION);//成功收到命令后转为准备状态
io_upgrade_change_progress(&dev_ice, 20);
printf("UPDATE_INIT\n");
break;
case UPDATE_PREPARATION:
io_upgrade_fw_choose(&dev_ice);
io_upgrade_verify_package(device); //校验
io_upgrade_change_progress(&dev_ice, 30);
printf("UPDATE_PREPARATION\n");
break;
case UPDATE_ERASING:
io_upgrade_erase(device);//擦除
io_upgrade_change_progress(&dev_ice, 55);
printf("UPDATE_ERASING\n");
break;
case UPDATE_WRITING:
io_upgrade_write(device);//写入
io_upgrade_change_progress(&dev_ice, 80);
printf("UPDATE_WRITING\n");
break;
case UPDATE_CONPELET:
if (device->sys_part == MAIN_PARAT)
{
io_upgrade_change_part(device, SUB_PART); //主切备
}
else
{
io_upgrade_change_part(device, MAIN_PARAT); //备切主
}
io_upgrade_change_progress(&dev_ice, 90);
printf("UPDATE_CONPELET\n");
break;
case UPDATE_SUCCESS:
io_upgrade_change_progress(&dev_ice, 100);
printf("升级成功! UPDATE_SUCCESS\n");
return;
default:
io_upgrade_handle_wrong_state(device); //异常处理,日志上报
return;
}
delay(2); //2s读一次状态
}
}
/*主函数*/
void main(int argc, char* argv[])
{
dev_ice.dev_name = (char*)malloc(12 * sizeof(char));
dev_ice.upgrade_file_name = (char*)malloc(64 * sizeof(char));
dev_ice.dev_name = 0;
dev_ice.upgrade_file_name = 0;
io_upgrade_init(&dev_ice);
io_upgrade_change_progress(&dev_ice, 10);
io_upgrade_loop(&dev_ice);
//int i = 6;
/*while (i)
{
io_upgrade_loop(&dev_ice);
delay(2);
i--;
}*/
}
test.h
#pragma once
#define FW_VERSION_MAIN 1 // Firmware_Revision
#define FW_VERSION_SUB 1
typedef unsigned char guint8;
typedef unsigned short guint16;
typedef unsigned int guint32;
typedef unsigned long long guint64;
typedef signed char gint8;
typedef signed short gint16;
typedef signed int gint32;
typedef signed long long gint64;
typedef void (*fw_upgrade_init)(void);
typedef int (*read_upgrade_state)(int);
typedef enum {
UPDATE_INIT, // 升级初始化状态
UPDATE_SATRT, // 启动升级功能
UPDATE_IDLE, // 升级空闲状态
UPDATE_PREPARATION, // 升级准备状态
UPDATE_ERASING, // 擦除程序状态
UPDATE_WRITING, // 写程序状态
UPDATE_CONPELET, // 升级完成
UPDATE_SUCCESS, // 升级成功
RET_UP_CONFIG, // 系统配置文件错误
RET_UP_PARTMENT, // 读取分区信息错误
RET_UP_FILE, // 升级文件不存在
RET_UP_READ_FLASH, // 读取系统flash失败
RET_UP_GET_SOURCE, // 获取源文件失败
RET_UP_VERIFY_ERR, // 升级文件校验失败
RET_UP_ERASE_ERR, // 擦除分区文件失败
RET_UP_WRITE_ERR, // 写文件失败
RET_UP_SW_PART, // 分区切换失败
RET_UP_NPU_NO, // NPU载板不在位
}upgrade_state_e;
typedef enum {
NONE_TYPE,
EXU_BMC,
EXU_CPLD,
NPU_CPLD,
NPU_MCU,
}upgrade_fw_type_e; //升级固件类型
typedef enum {
MAIN_PARAT,
SUB_PART,
//......
} upgrade_sys_part_e; //系统分区
typedef enum {
FLASH_CONFIG,
FLASH_RO,
FLASH_RW,
} upgrade_flash_name_e; //flash设备地址