//
// Created by huli on 2020/9/25.
//

#ifndef NNXX_TESTS_SNAP7_E_BASE_H
#define NNXX_TESTS_SNAP7_E_BASE_H

#include <s7_client.h>
#include <mutex>
#include <map>
#include <glog/logging.h>

#include "../error_code/error_code.h"
#include "../tool/thread_condition.h"
#include "../snap7_communication/snap7_buf.h"
#include "../snap7_communication/s7_plc.h"
#include "../snap7_communication/snap7_communication.pb.h"

class Snap7_communication_base
{
public:
	//snap7的通信延时, 默认50ms
#define SNAP7_COMMUNICATION_DELAY_TIME_MS 	10

//snap7, 通信错误的最大次数， 默认3
#define SNAP7_COMMUNICATION_ERROR_COUNT_MAX 	10

//snap7的通信参数路径
#define SNAP7_COMMUNICATION_PARAMETER_PATH	"snap7_communication.prototxt"
	//通信状态
	enum Snap7_communication_statu
	{
		SNAP7_COMMUNICATION_UNKNOWN		=0,	        //通信状态 未知
		SNAP7_COMMUNICATION_READY			=1,			//通信状态 正常

		SNAP7_COMMUNICATION_RECEIVE		=2, 		//接受
		SNAP7_COMMUNICATION_SEND			=3, 		//发送
		SNAP7_COMMUNICATION_DISCONNECT	=4, 		//断连

		SNAP7_COMMUNICATION_FAULT			=10,         //通信状态 错误
	};
public:
	Snap7_communication_base();
	Snap7_communication_base(const Snap7_communication_base& other)= default;
	Snap7_communication_base& operator =(const Snap7_communication_base& other)= default;
	~Snap7_communication_base();
public://API functions
	//初始化 通信 模块。如下三选一
	virtual Error_manager communication_init();
	//初始化 通信 模块。从文件读取
	virtual Error_manager communication_init_from_protobuf(std::string prototxt_path);
	//初始化 通信 模块。从protobuf读取
	virtual Error_manager communication_init_from_protobuf(Snap7_communication_proto::Snap7_communication_parameter_all& snap7_communication_parameter_all);
	//反初始化 通信 模块。
	virtual Error_manager communication_uninit();

	//唤醒s7通信线程
	virtual Error_manager communication_start();
	//停止s7通信线程
	virtual Error_manager communication_stop();

public://get or set member variable
	Snap7_communication_statu get_status();

	//修改通信延时, 单位ms
	Error_manager set_communication_delay_time_ms(int time);

	//修改状态
	Error_manager set_snap7_communication_statu(Snap7_communication_base::Snap7_communication_statu statu);

protected://member functions
	//通信连接
	Error_manager communication_connect(std::string ip_string);
	//启动通信, run thread
	Error_manager communication_run();
	//通信断连
	Error_manager communication_disconnect();
	//mp_communication_thread线程的执行函数, 负责进行s7的通信
	void communication_thread();

	//接受数据, 读取DB块,
	Error_manager read_data_buf(Snap7_buf& snap7_buf);
	//发送数据, 写入DB块,
	Error_manager write_data_buf(Snap7_buf& snap7_buf);
	//数据颠倒
	Error_manager reverse_byte(void* p_buf_in, void* p_buf_out, int size);

	//更新数据
	virtual Error_manager updata_receive_buf();
	virtual Error_manager updata_send_buf();
protected://member variable
public:
	//状态
	Snap7_communication_statu				m_communication_status;	//通信状态
	std::string						m_ip_string;			//通信ip
	int 							m_error_count;			//错误的计数， 如果超过3次就重连

	//通信模块
	std::mutex  					m_communication_lock;	//通信锁
	TSnap7Client 					m_snap7_client;			//通信的客户端
	int 							m_communication_delay_time_ms;//通信延时, 单位ms
	//注:s7协议通信很不稳定, 在每次使用 TSnap7Client 之后, 都需要加延时

	//数据
	std::mutex  					m_receive_buf_lock;		//接受的锁
	std::map<int, Snap7_buf>		m_receive_buf_map; 		//接受的map容器
	std::mutex  					m_send_buf_lock;		//发送的锁
	std::map<int, Snap7_buf>		m_send_buf_map; 		//发送的map容器

	//线程, snap7的通信核心就是对 发送和接受内存的 周期性读写, 所以使用一个线程即可.
	std::thread*					mp_communication_thread;    		//通信的线程指针
	Thread_condition				m_communication_condition;			//通信的条件变量


private:

};


#endif //NNXX_TESTS_SNAP7_E_BASE_H
