分布式系统下,主控向分控通过485或lora下发升级固件,支持断点续传

23 篇文章 1 订阅
17 篇文章 5 订阅

首先会检查通讯网络中通讯的繁忙情况,以便不阻塞正常通讯,主控通过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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵向深耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值