无线有有无线的便利快捷,有线有有线的可靠,两种方式同时使用或只使用其中一种,都很大便利的系统的施工
在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();
}
}
通讯处理线程,等待消息队列,从内存池中读取发送的数据帧,等待对方回复,处理重发,计算通讯质量,对方回复消息 处理