/*
============================================================================
Name : iec.c
Author : ChenShaoming
Version :1.09
Copyright :13054509118
Description : 烟台 招远
============================================================================
*/
//主备通道切换实现,相对简化。主通道为奇数,备通道为+1
//网络状态:socket_state 0--connecting 1-connected,-1不可用
//104通信状态 state_104 0--发送STARTDT,1--收到STARTDT-ACK,链路已建立
//is_stoped 1---通道停止
//运行时,先运行主通道,延时后再运行备通道。备通道建立连接后,检测主通道运行状态,如主通道运行异常,则切换到备通道。
//主通道建立连接后,也需判断备通道状态,如备通道没有成为主,则主运行。
//通道故障时,发切换命令
//双机主备切换,思路:运行时,隔一定时间,广播自己的存在。若邻居死掉,则备份定上。
//文件句柄个数和信号量,系统都有限制。定时器的实现,即可以用文件,也可用信号量。信号量是用户限制,文件是进程限制。
//#define _DEBUG
#include "lzma/lzma.h"//解压缩文件
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <time.h>
#include <sys/timerfd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <error.h>
#include <errno.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/resource.h>
#include <stdarg.h>
#include <sys/msg.h>
#include <sys/time.h>
#include <signal.h>
#include <dirent.h>
#include <math.h>
#define MAX_SEQUNCE 0X7FFF //最大序列号
#define RTUMAX 512//rtu最大个数
#define YXMAX 4096 //每个厂站遥信最大个数
#define YCMAX 2048 //每个厂站遥测最大个数
#define MONITOR_NUM 16
int FILE_MAXSIZE = 20; //文件大小-20M
char MONITOR_IP[32] = "127.0.0.1";
int MONITOR_PORT = 5000; //5000转发数据 6000 全数据 7000 变化的数据 8000 监控
int epoll_t023_timer_fd = -1;
int epoll_t1_timer_fd = -1;
int EPOLL_THREAD_NUM = 2; //线程池
int epoll_period_timer_fd = -1;
int epoll_frame_timer_fd = -1;
int epoll_rtu_fd[128] = { -1 };
int epoll_transfer_fd = -1;
int msgid = 0;
int msgid_transfer = 0;
int g_over = 0; //是否结束
int is_master = 0; //程序是否是主运行。
#ifdef _DEBUG
#define debug_info(fmt,args...) \
do { \
int err_no; \
err_no = errno; \
struct timespec curr; \
clock_gettime(CLOCK_REALTIME, &curr); \
time_t nSeconds; \
struct tm TM; \
nSeconds = curr.tv_sec; \
localtime_r(&nSeconds, &TM); \
pthread_mutex_lock(&Comm_Mutex); \
fprintf(stdout,"[%s](Line %d): ",__FUNCTION__,__LINE__); \
fprintf(stdout,"{errno:%d}[%02d %02d:%02d:%02d.%03d]:", err_no, TM.tm_mday, \
TM.tm_hour, TM.tm_min, TM.tm_sec, (int) (curr.tv_nsec / 1000)); \
fprintf(stdout,fmt,##args); \
fseek(fp_log, SEEK_SET, SEEK_END); \
int file_len = ftell(fp_log); \
if (file_len > FILE_MAXSIZE * 1024 * 1024) { \
fclose(fp_log); \
char file_newname[128]; \
sprintf(file_newname, "test.%d%d%d%d%d%d.txt", TM.tm_year,TM.tm_mon,TM.tm_mday,TM.tm_hour, TM.tm_min, TM.tm_sec); \
rename("test.txt", file_newname); \
fp_log = fopen("test.txt", "a"); } \
fprintf(fp_log,"[%s](Line %d): ",__FUNCTION__,__LINE__); \
fprintf(fp_log,"{errno:%d}[%02d %02d:%02d:%02d.%03d]:", err_no, TM.tm_mday, \
TM.tm_hour, TM.tm_min, TM.tm_sec, (int) (curr.tv_nsec / 1000)); \
fprintf(fp_log,fmt,##args); \
fflush(fp_log); \
pthread_mutex_unlock(&Comm_Mutex); \
} while (0)
#else
#define debug_info(fmt,args...)
#endif
#ifdef _DEBUG
FILE *fp_log;
int first_run = 1;
int check_single_instance();
#endif
pthread_mutex_t Transfer_Mutex = PTHREAD_MUTEX_INITIALIZER; //
pthread_mutex_t Alldata_Mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t Sudden_Mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t Monitor_Mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t Comm_Mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t thread_Mutex[128] = { PTHREAD_MUTEX_INITIALIZER };
struct msg {
int rtu_i; //厂站
int type; //0-yx,1-yc
int no;
int value;
int qs;
};
struct msgbuf {
long mtype;
struct msg mtext;
};
//数据转发队列定义
struct msg_channel {
int rtu_i;
int len;
char buf[4096];
};
struct msg_transfer {
long mtype;
struct msg_channel mtext;
};
struct rtu_para {
int k;
int w;
int call_time; //总召时间
int adjust_time; //校时时间
int t0;
int t1;
int t2;
int t3;
int yc_addr;
int yx_addr;
int yk_addr;
int send_no;
int recieve_no;
int reason_len;
int comm_len;
int addr_len;
int call_time_limit; //总召超时时间
int yk_time_limit; //遥控超时时间
int adjust_time_limit; //校时超时时间
int comm_addr; //公共地址
} rtu_para;
struct _rtu_sum {
int sum_read; //读字节数
int offline_time; //总共掉线时间
int offline_begin; //起始掉线时间
int sum_write; //写字节数
int start_time; //起始运行时间
} _rtu_sum;
struct send_node {
int send_no; //发送序号
struct timespec send_time; //发送时间
struct send_node *next;
} send_node;
struct send_node_Queue //建立队列首尾指针
{
struct send_node *front;
struct send_node *rear;
} send_node_Queue;
struct rtu_one {
int id; //序号,唯一.主通道为偶数,备通道为奇数
int station_id; //厂站代码,主备通道相同。
int is_first_run; //是否是首次运行,首次运行时发总召和校时。
int socket_fd; //
int is_slave;
int socket_state; //网络状态 0--connecting 1-connected,-1不可用
int link_port; //5000,6000,7000,8000
int pointer;
int is_rtu;
int t023_timerfd; //定时器,t0,t2,t3,收到第一个没确认的I帧后启动t2,到点后发送S帧确认,停止t2,同时启动t3;收到任意一帧i,s,u,T3清零。若收到s帧或测试应答帧,重新启动t3
int t1_timerfd; //定时器t1,发送I帧和U帧(不包括测试应答帧)启动,收到confirm后,停止。每一帧都要监视。
int t023timer_flag; //0--t0 2---t2 3----t3,定时器类型
int last_read_type; //最后一帧接受的类型
int last_send_type; //最后一帧发送的类型。
int cur_stage; //当前帧状态,0---,0x6406(总召发起),以后扩展
//0x6406 总召发起
//0x6407总召确认
//0x640a总召结束。
//0x2e0601; 预置 ,激活
//0x2e0600; 执行,激活
//0x2e0801; 预置,撤销
//0x2e0800; 执行,撤销
//0x2e07;预置确认
//0x2e07;执行确认
//0x2e09:预置撤销
//0x2e09:执行撤销
//0x2e0a:执行结束
int next_step; //发送本帧后,下一步即将进行的操作 0--没有 1--发送总召,2---发送校时
int state_104; //104通信状态,0--发送STARTDT,1--收到STARTDT-ACK,链路已建立
int not_answered; //没有响应的I帧个数。
int error_frame; //错误的帧数
int send_no; //实际发送序号
int recieve_no; //实际接收序号
int period_timerfd; //定时器,用于完成定时总召,对时
int next_calltime; //
int next_adjusttime; //
int frame_timerfd; //用于关联帧之间的定时,如yK限定时间,对时限定时间,总召回复时间等
int frame_timerflag; //关联定时标志:yk --1,call_reply --2 adjust_reply -3;
int read_len; //接受数据的长度
int write_len; //发送数据的长度
struct send_node_Queue send_queue; //发送队列
struct rtu_para rtu_para; //rtu参数
struct _rtu_sum rtu_sum;
unsigned char read_buf[256 * 12];
unsigned char write_buf[256 * 12];
FILE *fp;
//停止通道
int li_stoped; //通道是否停止
int li_sendstoped; //是否发送通道停止命令
//以下参数用于时间测试
struct timespec begin_time;
struct timespec end_time;
int li_test_t1;
int li_test_t2;
};
struct rtu_one sck_listen[4];
struct rtu_one sck_sudden[MONITOR_NUM]; //突发数据传输
struct rtu_one sck_