首先会检查通讯网络中通讯的繁忙情况,以便不阻塞正常通讯,主控通过4G从FTP服务器下载固件文件,主控将分控固件文件分成128字节一个数据包,每发一个包分控都会向主控反回确认,主控重启或分控重启都能继续固件的下发也就是断点续传,可以485与lora双线备份通讯或485、lora单独通讯都不受影响,当然2种通讯方式都断开就没法了,这部分需要依赖通讯层的处理
/**
* @file update.c
* @brief 分控升级.
* @details 将固件代码分帧发送给分控.
* @author kun
* @date 2018-05-24
* @version A001
* @par Copyright (c):
* @par History:
* version: kun, 2018-05-24, 建立\n
*/
#include "update.h"
#include "freertosinclude.h"
#include "freertos_user_config.h"
#include "slave_poll.h"
#include "mid_fs.h"
#include "slave_cmd.h"
#include "slave_poll.h"
#include "sys.h"
#include "master_config.h"
#include "daemon.h"
#include "dbg.h"
#include "debug.h"
UPDATE_T update;
UPDATE_BUF_T update_buf;
TaskHandle_t update_task_handle;
#undef UPDATE_DEBUG
#ifdef UPDATE_DEBUG
#define update_log(...) do{if(DEBUG(DEBUG_PROTOCAL)){DBG_LOG("[UPDATE](%ld) ",__LINE__);DBG_LOG(__VA_ARGS__);}}while(0)
#define update_usr(...) do{if(DEBUG(DEBUG_PROTOCAL)){DBG_LOG("[UPDATE] ");DBG_USR(__VA_ARGS__);}}while(0)
#define update_err(...) do{if(DEBUG(DEBUG_PROTOCAL)){DBG_LOG("[UPDATE] ");DBG_ERR(__VA_ARGS__);}}while(0)
#define update_dump(...) if(DEBUG(DEBUG_PROTOCAL)){DBG_DUMP(__VA_ARGS__);}
#define update_progress(...) do{if(DEBUG(DEBUG_PROTOCAL)){SEGGER_RTT_printf(0,__VA_ARGS__);}}while(0)
#else
#define update_log(...)
#define update_usr(...)
#define update_err(...)
#define update_dump(...)
#endif
/**
* slave_poll线程返回发送状态.
* 向所有在线分控发送升级文件.
* @param[in] value:邮箱消息.
* @param[out] 无.
* @retval 无
* @par 标识符
* 保留
* @par 其它
* 无
* @par 修改日志
* kun于2018-05-24创建
*/
void update_send_mailbox( uint32_t value ){
if( update_task_handle!=NULL )
xTaskNotify(update_task_handle,value,eSetValueWithOverwrite);
}
/**
* 升级任务线程.
* 各个分控文件断点续传.
* @param[in] 无.
* @param[out] 无.
* @retval 无
* @par 标识符
* 保留
* @par 其它
* 无
* @par 修改日志
* kun于2018-05-24创建
* 2018-08-15 kun:添加队列中等待发送数据帧数小于20%才允许升级条件,以便不阻塞正常通讯
* 2018-09-05 kun:添加分控的固件版本与升级版本比较
*/
void update_task(void * pvParameters){
FILE_HANDLER fd;
int res;
master_config_read_update();
// FREMOVE(update.file_name);
while(1){
if( (update.last_version < master_working.board_para.secondary_minor_version) && (slave_poll_queue_num() < SEND_QUEUE_LENGTH*0.2) ){
update_log("recv new slave version %05u\r\n",master_working.board_para.secondary_minor_version);
///<分控升级新开始
if( update.curr_version < master_working.board_para.secondary_minor_version){
update.curr_version = master_working.board_para.secondary_minor_version;
update.total_seg = 0;
snprintf( update.file_name, UPDATE_FILE_NAME_LEN, "%05u-%05u.bin", SECONDARY_HARDWARE_VERSION, update.curr_version );
///<计算总分帧数
uint32_t file_len;
if( master_config_file_size(update.file_name,&file_len) == RTN_OK){
update.total_seg = file_len/UPDATE_SEG_BYTE;
if( file_len%UPDATE_SEG_BYTE ){
update.total_seg += 1;
}
update_log("total segment %d\r\n",update.total_seg);
update.success_num = 0;
memset(update.slave_state,0,sizeof(UPDATE_SLAVE_STATE_T)*SLAVE_POLL_MAX);
master_config_write_update();
}
else{
update_buf.curr_seg = 0;
update_buf.curr_slave_no = 0;
switch( update_buf.fail_reason ){
case FAIL_OPEN_FILE: ///<打开固件文件失败
break;
case FAIL_QUEUE_FULL: ///<主控的发送缓冲区满
break;
default:
break;
}
}
}
res = FOPEN( &fd, update.file_name, "r" );
if( res<0 ){
update_buf.fail_reason = FAIL_OPEN_FILE;
update_log("can not open firmware\r\n");
master_working.board_para.secondary_minor_version = update.last_version;
memset(&update_buf,0,sizeof(UPDATE_BUF_T));
update.success_num = 0;
update.curr_version = update.last_version;
memset(update.slave_state,0,sizeof(UPDATE_SLAVE_STATE_T));
goto update_exit;
}
update_buf.curr_slave_no = 0;
///<指向第一个分控或最近升级后的分控
SLAVE_WORKING_T **slave_working_ptr;
slave_working_ptr = &master_working.slave_working[update_buf.curr_slave_no];
///<分别对个分控进行文件发送
while( update_buf.curr_slave_no<master_working.slave_num ){
///<当前分控升级成功,跳到下一台分控
if( update.slave_state[update_buf.curr_slave_no].update_sta==UPDATE_STA_OK ){
update_buf.curr_slave_no++;
slave_working_ptr++;
continue;
}
update_log("start slave %d update\r\n",(*slave_working_ptr)->addr);
///上次中断的段码
update_buf.curr_seg = update.slave_state[update_buf.curr_slave_no].curr_seg;
update_buf.send.total_seg = update.total_seg;
update.slave_state[update_buf.curr_slave_no].update_sta = UPDATE_STA_PROCESS;
///<分段发送文件
update_buf.fail_reason = FAIL_NONE;
///<段数还没发完
while( update_buf.curr_seg < update.total_seg &&
///<分控已经初始化完成
(*slave_working_ptr)->state == STATE_INIT &&
update_buf.fail_reason==FAIL_NONE &&
///<分控的固件版本与升级版本比较
(*slave_working_ptr)->slave_para.software_ver < update.curr_version ){
uint32_t len;
update_buf.send.curr_seg = update_buf.curr_seg;
///<不清楚同时打开多个文件会有什么问题
FSEEK( &fd, update_buf.curr_seg*UPDATE_SEG_BYTE, SEEK_SET );
len = FREAD( update_buf.send.buf, 1, UPDATE_SEG_BYTE, &fd );
if( len>0 ){
///<如果队列或内存池满,等待
uint8_t i=0;
update_log("send slave %d segment %d \r\n",(*slave_working_ptr)->addr,update_buf.curr_seg);
daemon_refresh();
while( slave_cmd_write_data((*slave_working_ptr)->addr, 0, CMD_FILE, len+4, (uint8_t*)&update_buf.send)!=RTN_OK && i<10 ){
i++;
daemon_refresh();
vTaskDelay(1000);
}
///<发送不成功,退出升级
if( i==10 ){
update_buf.fail_reason = FAIL_QUEUE_FULL;
FCLOSE(&fd);
update.slave_state[update_buf.curr_slave_no].update_sta = UPDATE_STA_ERR;
goto update_exit;
}
///<发送,等待分控回复
else{
BaseType_t xResult;
uint32_t mailbox_value;
uint8_t cnt=0;
update_buf.fail_reason = FAIL_NONE;
do
{
daemon_refresh();
xResult = xTaskNotifyWait(0x00000000, 0xFFFFFFFF,&mailbox_value,1000);
cnt++;
daemon_refresh();
if( xResult == pdPASS ){
///<收到分控确认回应,比较段号码
if( mailbox_value==update_buf.curr_seg ){
update_log("slave %d success %d of [%d]",(*slave_working_ptr)->addr,update_buf.curr_seg+1,update.total_seg);
update_buf.curr_seg++;
update.slave_state[update_buf.curr_slave_no].curr_seg = update_buf.curr_seg;
master_config_write_update();
}
///<段序号不正确,重发当前段
else{
update_buf.fail_reason = FAIL_SEG;
update_log("resend segment %d\r\n",update_buf.curr_seg);
}
}
}while(xResult==pdFAIL && cnt<30);
if( cnt>=30 ){
update_buf.fail_reason = FAIL_NO_RESPONSE;
}
}
}
}
///<当前分控的所有段发送成功
if( update.slave_state[update_buf.curr_slave_no].curr_seg==update.total_seg ){
update.slave_state[update_buf.curr_slave_no].update_sta = UPDATE_STA_OK;
update.success_num++;
master_config_write_update();
}
///<指向后下一个分控
slave_working_ptr++;
update_buf.curr_slave_no++;
update_buf.curr_seg = 0;
daemon_refresh();
}
update_buf.curr_slave_no = 0;
FCLOSE(&fd);
if( update.success_num==master_working.slave_num ){
update.last_version = update.curr_version;
///<保存已经成功升级所有分控
master_config_write_update();
// FREMOVE(update.file_name);
memset(update.file_name,0,UPDATE_FILE_NAME_LEN);
}
}
update_exit:
daemon_refresh();
vTaskDelay(1000);
}
}
/**
* 分控升级线程初始化.
* 建立升级线程,由其它线程调用.
* @param[in] 无.
* @param[out] 无.
* @retval 无
* @par 标识符
* 保留
* @par 其它
* 无
* @par 修改日志
* kun于2018-05-24创建
*/
void update_int(void){
if( master_config_read_update()==RTN_ERR ){
memset(&update,0,sizeof(UPDATE_T));
update.last_version = FACTORY_SLAVE_SW_VERSION;
master_config_write_update();
// master_config_addition( "03002-00082.bin", NULL, 4123 );
}
xTaskCreate(update_task, "update", UPDATE_STACK_SIZE, ( void * )NULL,UPDATE_TASK_PRIORITY, &update_task_handle);
daemon_from_value = update_task_handle;
}