网络通讯中路由将数据包选择不同链路发送,接收端有可能收到重复数据包,TCP有相应的识机制可将重复包过滤丢弃,参考TCP机制,在协议中定义seg字段,发送端通过485及lora发送数据,有可能485断开或lora断开,或者2条通讯线路都连通情况下,接收端那个速度快就会通过那条线路接收到数据包,接收端通过seq识别是否已经处理过的数据包,已处理丢弃,发送端每发一个数据包seq加1,避免重复

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; i<master_working.slave_num; i++){//比较分控地址if( addr==master_working.slave_working[i]->addr ){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;elsecmd_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);elsexStatus = 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; i<master_working.slave_num; i++){if( proto_ptr->header.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_time<SLAVE_POLL_TIME && master_working.wait_reply){REPLY_TYPE_T reply_type;vTaskDelayUntil( &ticks, 1 );master_working.poll_time++;//485回复先到达,只处理485PROTOCOL_T       *recv_pro;reply_type = slave_poll_reply_comp(&reply_msg);daemon_refresh();if( reply_type==REPLY_485 ){recv_pro = reply_msg.recv_485_pro;slave_poll_log( "recv 485\r\n");}else if( reply_type==REPLY_LORA ){recv_pro = reply_msg.recv_lora_pro;slave_poll_log( "recv lora\r\n");}else{recv_pro = NULL;}if( recv_pro != NULL ){if( slave_poll_recv((uint8_t*)recv_pro)==RTN_OK ){///<比较到达数据帧的主控地址及帧序号if( recv_pro->header.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();}
}

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

lora 与 485 双线备份式通讯相关推荐

  1. 西门子1200PLC模板通讯程序,包含多种通讯Modbus-RTU(485),S7通讯

    西门子1200PLC模板通讯程序,包含多种通讯Modbus-RTU(485),S7通讯,Modbus-TCP,TCP/IP等,简单明了 编号:54112654376937554tbNick_mtjdq

  2. 三菱、汇川plc用485通讯板和变频器通讯,实现正转、反转、运行过程改变频率实现调速

    三菱.汇川plc用485通讯板和变频器通讯,实现正转.反转.运行过程改变频率实现调速. D8120设为H0C8E, Rs D200 k12 D500 k13. D207D206是正转.反转.停止命令控 ...

  3. lora终端连接云服务器_物联网通讯技术三足鼎立形成:NB-IoT、eMTC、LoRa各有千秋...

    物联网通讯技术三足鼎立形成:NB-IoT.eMTC.LoRa各有千秋 如今,即便是不懂技术的人都知道IoT具有非常可观的前景,而物联网产业的发展并非一帆风顺,其中制约行业发展的一大关键技术就是通讯技术 ...

  4. 树莓派基于QT实现利用USB转485模块进行串口通讯

    本文的QT版本为5.3.2,是树莓派可直接下载安装的QT版本,不用自己编译. 树莓派为3B+. 树莓派利用自带的硬件串口是3.3V的ttl电平,在做测试的时候会遇到很多485的设备,在使用232转48 ...

  5. adprw指令通讯案例_S7-1200与S7-300傻瓜式通讯

    最近在做一个使用西门子S7-1200控制伺服电机运动的一个小设备,这个设备需要作为一个子站挂载在 S7-300主站下.在把设备寄到厂家以后,对方表示通讯不上,后经过现场查看发现对方对S7-300不太熟 ...

  6. 485通讯的校验和_485转lora - ZLAN卓岚

    485转lora是一款485无线远距离传输设备,可以解决用户485布线困难的问题.实现485设备无线远距离数据传输. LoRa是一种远距离无线通讯方案.LoRa和GPRS.4G方案相比它无需入网月租费 ...

  7. 工程小白问题:数采网关、智慧网关、物联网关、工业网关、DTU透传网关、边缘网关、协议网关、通讯管理机、中控网关、LORA网关、PROFIBUS网关、HART网关,都啥区别?如何判断是否符合工程要求?

    什么是数采网关,LoRa数采网关\NB-IOT数采网关\HART数采网关profibus DB 数采网关 数采网关就是数据采集网关,一端对接各种数据采集终端.电子仪器仪表,一般都是工业现场总线通讯传输 ...

  8. Lora和Zigbee无线通讯技术的对比

    物联网应用中的无线技术有很多种,从大的方向分为两种,一种是局域网,另外一种是广域网. 最常见的广域网,是基于电信公司网络通讯的无线技术,例如2G,3G,4G,5G等,以及现在比较流行的NB-Iot.  ...

  9. php 485串口通信,485串口通信中的常见问题

    通信距离 485总线的通讯距离理论可以达到1200米,一般是指通讯线材优质达标,波特率9600,只有一台485设备才能使得通讯距离达到1200米,而且能通讯并不代表每次通讯都正常.所以通常485总线实 ...

最新文章

  1. 心形尺寸比例图解_0元图解建筑史-05 | 中国木构建筑的特征与详部演变(2)——斗栱、厅堂殿堂...
  2. JavaScript对象及初始面向对象
  3. 有两个链表a,b,设结点包括学号,姓名。从a链表中删去与b链表中有相同学号的那些结点。
  4. voip 音频采集时间_蓝牙音频续航监测系统展会现场演示
  5. 接口测试文件上传(python+requests)
  6. Objective-C代码学习大纲
  7. column分栏布局只是文字布局吗_CSS3 column 分栏
  8. graphviz安装及使用
  9. [转载]用户(User)和用户组(Grou…
  10. 阿里平台上转的 数据模型架构规范
  11. Windows 10 20H2 微软MSDN官方正式版ISO镜像下载
  12. 华为路由器后台登录协议
  13. fiddler视频分析
  14. 梦想家-致停不下来的我们
  15. linux 批量convert,使用convert来批量处理图片
  16. Linux开发 | 电脑WiFi上网,开发板和电脑网线直连,文件拷贝
  17. Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)
  18. YOLOv5 安全帽识别:如何使用 YOLOv5 进行实时安全帽检测
  19. PPT设计Tips总结
  20. sent2vec教程

热门文章

  1. swift项目嵌入flutter的module混合开发(framework模式:适合多人协作开发,一个负责混合开发)
  2. java计算:拉马努金数
  3. 紧急通知:无论你英语多差,只要想学,看了此文必有改变
  4. win10“未激活”提示太烦人,轻松一招教你搞定它
  5. 毕业设计(二十三)- 以前在金堆里淘金,现在却只能在垃圾堆里寻“宝”了!
  6. python输入序列语句_Python语句序列如下: x='car' y=2 print(x+y) 输出结果为( )_学小易找答案...
  7. 第63天学习打卡(MySQL 测试索引 索引原则 数据管理和备份 规范数据库设计)
  8. 第9章 开发实例-文件保险箱
  9. pdf to word文件转换器,出自著名的PDF解决方案供应商NitroPDF
  10. Latex 关于bib参考文献在正文中的引用