lora 与 485 双线备份式通讯

无线有有无线的便利快捷,有线有有线的可靠,两种方式同时使用或只使用其中一种,都很大便利的系统的施工
在FreeRTOS中建立消息队列,通过在内存池申请内存存放发送消息

typedef struct{
	
	void 		*data;				///<发送数据地址
	uint8_t		len;				///<发送数据长度
	uint16_t	seq;				///<当前发送帧的序号,用于等待485与lora回复时,过滤重复帧
	uint8_t		wait_reply;			///<发送数据是否需要等待分控回复
	uint8_t		type;				///<发送类型,0同时发送,1 485发送,2 lora发送
}CMD_MSG_T;

消息结构体,定义这帧消息是否需要回复,消息序号等。

RTN_T slave_cmd_send_segment(uint16_t addr, uint8_t point, uint8_t cmd, uint16_t send_len, uint8_t *send_data, uint8_t front, uint8_t send_type){
	
	uint8_t *data;
	uint16_t seg_len;
	uint8_t iseq=0;
	
	///<设置分控缓冲中的发送状态
	uint8_t i;
	for(i=0; iaddr ){
			master_working.slave_working[i]->send_state = SENDING;
		}
	}
	
	do
	{
		seg_len = send_len>SEND_DATA_MAX?SEND_DATA_MAX:send_len;
		send_len -= seg_len;
		///<数据长度超出最大范围分帧
		if( send_len>0 ){
			iseq++;
			if( iseq==0x0f )
				iseq = 1;
		}
		///<分帧最后一帧
		else if( iseq!=0 ){
			iseq = 0x0f;
		}
		///数据长度小于最大范围不用分帧
		else{
			iseq = 0;
		}
		
		data = NULL;
		data = (uint8_t*)malloc(protocol_total_len(seg_len));
		if( data!=NULL ){
						
			PROTOCOL_T 	*proto_ptr;
			uint16_t 	*data_ptr;
			proto_ptr = (PROTOCOL_T *)data;
			CMD_MSG_T	cmd_msg;
						
			data_ptr = (uint16_t *)&proto_ptr->data;
			
			//填充引导码
			proto_ptr->leader = PROTOCOL_LEADER;
			
			//填充头部
			proto_ptr->header.slave_addr = addr;
			proto_ptr->header.master_addr = master_working.sys_public.master_addr;
			proto_ptr->header.seq = (++master_working.frames_seq)<<4|iseq;
			proto_ptr->header.cmd = cmd;
			proto_ptr->header.point = point;
			proto_ptr->header.len = seg_len;
			
			//填充数据区
			memcpy(data_ptr,send_data,seg_len);
			send_data += seg_len;
			
			//计算校验码
			data[protocol_checksum_pos(seg_len)] = Crc8(data,protocol_checksum_pos(seg_len));
			//填充结束码
			data[protocol_ender_pos(seg_len)] = PROTOCOL_ENDER;
						
			cmd_msg.data = data;
			cmd_msg.len = protocol_total_len(seg_len);
			cmd_msg.seq = proto_ptr->header.seq;
			cmd_msg.type = send_type;
			//广播地址不用等待回复
			if( addr==BROADCAST_ADDR )
				cmd_msg.wait_reply = 0;
			else
				cmd_msg.wait_reply = 1;
			
			portBASE_TYPE xStatus;
			if( front==INSERT_FIRST )
				xStatus = xQueueSendToFront(master_working.slave_send_queue,&cmd_msg,0);
			else if( slave_poll_queue_num() < SEND_QUEUE_LENGTH-SEND_QUEUE_RETAIN )
				xStatus = xQueueSend(master_working.slave_send_queue,&cmd_msg,0);
			else
				xStatus = pdFAIL;
			if( xStatus != pdPASS ){
				//队列满,发送不成功
				free(data);
				slave_cmd_err("send queue full		[ERR]\r\n");
				return RTN_ERR;
			}
			else{
				if( cmd&CMD_READ){					///>读参数状态
					
					slave_cmd_log("==> read %02x slave %d point parameter		[OK]\r\n",addr,point);
				}
				else if( cmd&CMD_WRITE){					///>写参数
					
					slave_cmd_log("==> write %02x slave %d point parameter		[OK]\r\n",addr,point);
				}
				else if( cmd&CMD_FILE){					///>下发文件
					
					slave_cmd_log("==> download %02x slave file					[OK]\r\n",addr);
				}

				return RTN_OK;
			}
		}
		else{
			slave_cmd_err("can not malloc to send data		[ERR]\r\n");
			return RTN_ERR;
		}
	}
	while(send_len>0);
}

定义发送地址,接收的端口,是否需优先发送,直接在内存当申请空间,消息头发给消息队列,。

void slave_poll_task(void *argument ){

//	daemon_disable( xTaskGetCurrentTaskHandle() );
	
	static REPLY_MSG_T		reply_msg;
	static uint8_t			slave;
		
	TickType_t ticks = xTaskGetTickCount();
	
	memset(&reply_msg,0,sizeof(REPLY_MSG_T));
	reply_msg.recv_485_pro = (PROTOCOL_T*)&reply_msg.recv_485_data;
	reply_msg.recv_lora_pro = (PROTOCOL_T*)&reply_msg.recv_lora_data;
	
//	master_working.init_step = 2;
	
	
//	daemon_enable( xTaskGetCurrentTaskHandle() );
//	cpustate_init();
	
	//进入正常工作轮询分机
	while(1){
		
		CMD_MSG_T	cmd_msg;
		while( xQueueReceive(master_working.slave_send_queue,&cmd_msg,0)==pdPASS ){
			
//			if( master_working.slave_working[slave]->slave_send.enable && master_working.slave_working[slave]->state == STATE_LINK ){
			
			if( master_working.production_test.opeation&PT_DEBUG_MODE || master_working.production_test.opeation&PT_TEST_MODE )
				continue;
			
			//获取发送数据的分机存储编号
			uint8_t i;
			PROTOCOL_T *proto_ptr = (PROTOCOL_T *)cmd_msg.data;
			for(i=0; iheader.slave_addr==master_working.slave_working[i]->addr ){
					slave = i;
					break;
				}
			}
			
			///<检查队列中的控制命令是否与设备保存的控制命令一致
			///<不一致,丢弃
			if( slave_cmd_check_ctrl(proto_ptr)==RTN_ERR ){
				
				free(cmd_msg.data);
				continue;
			}
			
			///<需发送数据的分控已经断开,非获取分控命令,丢弃
			if( slave_poll_link_status_from_addr(proto_ptr->header.slave_addr)==STATE_DISCONNECT ){
				uint16_t *data_code;
				data_code = (uint16_t *)&proto_ptr->data;
				if( *data_code != SYS_STUS_ALL ){
					free(cmd_msg.data);
					continue;
				}
			}
			
			master_working.retry_times = 0;
			master_working.sys_run_para.send_cnt_total++;
			slave_poll_log( "send new %d\r\n",master_working.sys_run_para.send_cnt_total);
			master_working.slave_working[slave]->last_send_time.hour = master_working.time_ymdhms.tm_hour;
			master_working.slave_working[slave]->last_send_time.minute = master_working.time_ymdhms.tm_min;
			master_working.slave_working[slave]->last_send_time.second = master_working.time_ymdhms.tm_sec;
			do
			{	//while(master_working.wait_reply);
				
				//发送前清空485及loara的接收缓冲区
//				slave_485_uart_clr();
//				slave_lora_uart_clr();
				
				slave_poll_send(cmd_msg.data, cmd_msg.len, cmd_msg.type);
				slave_poll_log( "sending\r\n");
				master_working.wait_reply = cmd_msg.wait_reply;
				
				//等待分机回复
				master_working.poll_time = 0;
				//使能串口接收
	//			slave_485_uart_recv_trigger();
	//			slave_lora_uart_recv_trigger();
				
				reply_msg.recv_485_ptr = 0;
				reply_msg.recv_lora_ptr = 0;
				reply_msg.start_485_recv = 0;
				reply_msg.start_lora_recv = 0;
				
				while(master_working.poll_timeheader.master_addr==master_working.sys_public.master_addr && 
								recv_pro->header.seq==cmd_msg.seq ){
								
								uint16_t *data_code;
								data_code = (uint16_t *)&recv_pro->data;
								switch( recv_pro->header.cmd ){

									case CMD_READ|CMD_REPLY:
										
										break;
									case CMD_FILE|CMD_REPLY:
										update_send_mailbox(*data_code);
										break;
									default:
									{
										break;
									}
								}
								if( recv_pro->header.cmd&CMD_REPLY ){
									if( master_working.slave_working[slave]->state==STATE_DISCONNECT )
										log_file_write("No. %d slave resume\r\n",master_working.slave_working[slave]->addr);
									if( master_working.slave_working[slave]->state < STATE_LINK )
										master_working.slave_working[slave]->state = STATE_LINK;
									master_working.slave_working[slave]->timeout_num = 0;
									master_working.wait_reply = 0;
								}
								
								master_working.slave_working[slave]->reply_time_avg += master_working.poll_time;// + master_working.retry_times*SLAVE_POLL_TIME;
								master_working.slave_working[slave]->reply_time_avg /= 2;
								master_working.slave_working[slave]->reply_type = reply_type;
								if( master_working.poll_time > master_working.slave_working[slave]->reply_time_max )
									master_working.slave_working[slave]->reply_time_max = master_working.poll_time;
							}
							if( master_working.wait_reply == 0 ){
								free(cmd_msg.data);
//								master_working.slave_working[slave]->send_state = SEND_OK;
								slave_poll_comm_send_sta(slave,SEND_OK);
								//slave = 2;
								//((SLAVE_COMM_STA_T*)(master_working.slave_comm_sta+slave))->comm_sta = SEND_TO;
							}
						}
						else{
							slave_poll_log( "crc checksum error\r\n");
						}
					}
				}
				//没有收到消息回复,超过计数
				if( master_working.wait_reply ){
					
					if( ++master_working.retry_times>SLAVE_RETRY_NUM ){
						slave_poll_log( "-----timeout\r\n");
						master_working.sys_run_para.send_timeout++;
						//已经超出最大重发次数,关闭当前分机的发送,切换下一台分机
						master_working.retry_times = 0;
						master_working.wait_reply = 0;
						free(cmd_msg.data);
//						master_working.slave_working[slave]->send_state = SEND_TO;
						slave_poll_comm_send_sta(slave,SEND_TO);
//						slave_poll_log( "\r\nFreeHeapSize:%u\r\n", xPortGetFreeHeapSize() );
						
						master_working.slave_working[slave]->timeout_num++;
					
						if( master_working.slave_working[slave]->timeout_num>=SLAVE_TIMEOUT_NUM ){
							master_working.slave_working[slave]->state = STATE_DISCONNECT;
							log_file_write("No.%d slave disconnect\r\n",master_working.slave_working[slave]->addr);
						}
						
						master_working.slave_working[slave]->reply_time_avg = 0xffff;
					}
					//如果当前分机已经处于连接断状态,不进行多次重发,直接清空发送区,防止阻塞轮询其它分机
					else if( master_working.slave_working[slave]->state == STATE_DISCONNECT ){
						master_working.retry_times = 0;
						master_working.wait_reply = 0;
						free(cmd_msg.data);
//						master_working.slave_working[slave]->send_state = SEND_TO;
						slave_poll_comm_send_sta(slave,SEND_TO);
						master_working.sys_run_para.send_disconnect_cnt++;
						
						master_working.slave_working[slave]->reply_time_avg = 0xffff;
					}
				}
				else{
					///<广播地址直接丢弃数据包
					if( proto_ptr->header.slave_addr==BROADCAST_ADDR ){
						free(cmd_msg.data);
					}
				}
				daemon_refresh();
			}while(master_working.wait_reply);
			
			vTaskDelayUntil( &ticks, 10 );
		}
		
		//100ms一个周期轮询所有分机
		vTaskDelayUntil( &ticks, 100 );
		daemon_refresh();
	
	}
}

通讯处理线程,等待消息队列,从内存池中读取发送的数据帧,等待对方回复,处理重发,计算通讯质量,对方回复消息 处理

你可能感兴趣的:(FreeRTOS,STM32,Lora,485)