#include "cigarette.h"
#include <qmessagebox.h>
#include <qdir.h>
#include <iostream>
#include <thread>
#include <PLCDevice.h>
#include <QtCore\qcryptographichash.h>
#include <QtCore\qprocess.h>
#include "exportData.h"

int g_op_time;	//操作员权限时长（默认300秒）
int g_admin_time;	//管理员操作权限时长（默认300秒）

int rotationAngle[NumberOfSupportedCameras];  //图片旋转角度
bool isNeedRotate[NumberOfSupportedCameras];

DisplayLabelConf g_display_label_conf[NumberOfSupportedCameras];

SysConf g_sys_conf;						//系统配置参数
ModbusConf g_modbus_conf;				//modbus地址参数
PLCDevice * m_PLCDevice;
bool g_plc_dialog_open;	//是否打开plc配置对话框

QDateTime g_ts_start;

extern SingleCamInfoStruct SingleCamInfo[NumberOfSupportedCameras];

AlgJd alg_jd[NumberOfSupportedCameras];	//检测胶点的AI算法
#ifdef __DEBUG
AlgJd alg_test;//test AI算法
#endif
QThread* pThread[NumberOfSupportedCameras];

//巴鲁夫相机相关
CaptureThread* pCaptureThread[NumberOfSupportedCameras];
FunctionInterface* pFI[NumberOfSupportedCameras];
mvIMPACT::acquire::GenICam::AcquisitionControl* pAC[NumberOfSupportedCameras];

//巴斯勒相机相关
CaptureThreadBasler* pBaslerCaptureThread[NumberOfSupportedCameras];
Pylon::CBaslerUniversalInstantCamera* BaslerCamHandle[NumberOfSupportedCameras];

//海康相机相关
void *HIKCamHandle[NumberOfSupportedCameras];
CaptureThreadHIK* pHIKCaptureThread[NumberOfSupportedCameras];

SyncQueue<std::pair<std::string, cv::Mat> > *g_save_queue;	//图片保存队列
SyncQueue<std::pair<int, cv::Mat> > *g_image_queue[NumberOfSupportedCameras];	//int表示一个目标拍了几张
ASyncQueue<bool> *g_shooted_queue[NumberOfSupportedCameras];	//
ASyncQueue<bool> *g_result_wait_queue[NumberOfSupportedCameras];	//
ASyncQueue<bool> *g_double_queue[NumberOfSupportedCameras];	//
ASyncQueue<bool> *g_result_queue[NumberOfSupportedCameras];	//
bool g_debug_mode;	//相机调试模式，工作模式必须暂停状态才能打开
SyncQueue<cv::Mat> *g_debug_queue[NumberOfSupportedCameras];	//相机调试模式图像队列

SyncQueue<_UDPSendInfo> *UDP_Info_queue;
SyncQueue<_ExportDataInfo> *export_Data_Info_queue;
ExportDataThread exportDataThread;

bool g_admin_mode;	//是否管理员模式

QString g_admin_pswd;	//管理员密码

bool g_op_mode;	//是否操作员模式

QString g_op_pswd;	//操作员密码

bool g_working;			//true 开始工作状态； false  停止工作状态

int last_shift; //记录上一次班

QStringList g_alarm_msg;
std::vector<AlarmInfo> g_vec_alarm;
int g_last_alarm_code;

int g_lst_quantiy;			//上一秒的产量
int quantity_stop_count;	//产量不变的秒数
int g_seconds;
int CurOpLabel;
bool onrestart = false;

VOID BeforeWork(int shoot[])
{
#ifdef AI_WARM_UP
	for (int j = 0;j<10;j++)
	{
		for (int i = 0; i < NumberOfSupportedCameras; i++)
		{
			if (SingleCamInfo[i].Detect && SingleCamInfo[i].IsOpen) {
				alg_jd[i].test_detect_batcht(shoot[i]);
			}
		}
	}
#endif
}

Cigarette::Cigarette(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	InitPtrMat();
	bool update_rotate = false;
	if (!read_rotate_message()) {
		update_rotate = true;
	}

	QThread* hThread = new QThread();
	CLog* clogWorkThread = new CLog();
	clogWorkThread->moveToThread(hThread);
	connect(this, &Cigarette::destroyed, hThread, &QThread::quit);
	connect(hThread, &QThread::finished, clogWorkThread, &CLog::deleteLater);
	connect(this, &Cigarette::sengMsgToClog, clogWorkThread, &CLog::recMegFromCigarette);
	hThread->start();

	emit sengMsgToClog("Application Start.");
	
	g_save_queue = new SyncQueue<std::pair<std::string, cv::Mat> >(Queue_Size);
	g_save_queue->name = "save queue";
	UDP_Info_queue = new SyncQueue<_UDPSendInfo>(Queue_Size);
	UDP_Info_queue->name = "UDP Info queue";
	export_Data_Info_queue = new SyncQueue<_ExportDataInfo>(Queue_Size);
	export_Data_Info_queue->name = "Export Data Info queue";
	last_shift = 256;
	
	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		g_image_queue[i] = new SyncQueue<std::pair<int, cv::Mat> >(Queue_Size);
		g_image_queue[i]->name = format("image_%d", i);
		g_result_queue[i] = new ASyncQueue<bool>(Queue_Size);
		g_result_queue[i]->name = format("result_%d", i);
		g_result_wait_queue[i] = new ASyncQueue<bool>(Queue_Size);
		g_result_wait_queue[i]->name = format("result_wait%d", i);
		g_double_queue[i] = new ASyncQueue<bool>(Queue_Size);
		g_double_queue[i]->name = format("double_wait%d", i);
		g_shooted_queue[i] = new ASyncQueue<bool>(Queue_Size);
		g_shooted_queue[i]->name = format("shooted_%d", i);
		g_debug_queue[i] = new SyncQueue<cv::Mat>(Queue_Size);
		g_debug_queue[i]->name = format("debug_%d", i);
		if (update_rotate) {
			rotationAngle[i] = cv::ROTATE_90_COUNTERCLOCKWISE + 1;
			isNeedRotate[i] = false;
		}
	}
	if (update_rotate) {
		if (save_rotate_message()) {
			printf("\nFail to write message to file.");;
		}
	}
	g_debug_mode = false;

	g_admin_mode = false;
	g_admin_time = ADMIN_TIME;

	g_admin_pswd = read_pswd();

	g_op_mode = false;
	g_op_time = OP_TIME;
	g_op_pswd = read_op_pswd();

	g_working = false;

	g_alarm_msg << QStringLiteral("无报警")	/// 0
		<< QStringLiteral("1#相机丢结果")	/// 1
		<< QStringLiteral("2#相机丢结果")	/// 2
		<< QStringLiteral("1#相机有剔除")	/// 3
		<< QStringLiteral("2#相机有剔除")	/// 4
		<< QStringLiteral("1#相机通讯故障")	/// 5
		<< QStringLiteral("2#相机通讯故障")	/// 6
		<< QStringLiteral("3#相机通讯故障")	/// 7
		<< QStringLiteral("4#相机通讯故障")	/// 8
		<< QStringLiteral("5#相机通讯故障")	/// 9
		<< QStringLiteral("6#相机通讯故障")	/// 10
		<< QStringLiteral("7#相机通讯故障")	/// 11
		<< QStringLiteral("8#相机通讯故障");	/// 12

	g_last_alarm_code = 0;

	g_ts_start = QDateTime::currentDateTime();

	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		g_display_label_conf[i].g_max[0] = false;
		g_display_label_conf[i].g_max[1] = false;
		OpenWithUserID[i]=0xff;
		production_number[i]=0;
		lcdNumber_total_mat[i]->display(production_number[i]);
		ok[i] = 0; 
		ng[i] = 0;
		g_display_label_conf[i].g_last_mat[0] = cv::Mat::zeros(20, 20, CV_8UC3);
		g_display_label_conf[i].g_last_mat[1] = cv::Mat::zeros(20, 20, CV_8UC3);
#ifdef DRAW_RECT
		DrawRect_init(i);
#endif
	}
	ui.lcdNumber_total_no->display(0);
	ui.lcdNumber_total_no_last->display(0);

	g_plc_dialog_open = false;

	g_lst_quantiy = 0;
	quantity_stop_count = 0;
	g_seconds = 0;

	read_sys_config(g_sys_conf);	//初始化系统配置

#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
	g_modbus_conf.kick1 = 0;			//1#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
	g_modbus_conf.kick2 = 0;			//2#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
	g_modbus_conf.kick3 = 0;			//3#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
	g_modbus_conf.kick4 = 0;			//4#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
	g_modbus_conf.kick5 = 0;			//5#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
	g_modbus_conf.kick6 = 0;			//6#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
	g_modbus_conf.kick7 = 0;			//7#通道剔除个数地址
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
	g_modbus_conf.kick8 = 0;			//8#通道剔除个数地址
#endif
	g_modbus_conf.quantity = 0;
	g_modbus_conf.shift = 0;
	g_modbus_conf.work = 0;
	g_modbus_conf.no_kick = 0;
	g_modbus_conf.debug = 0;
	g_modbus_conf.reset = 0;
	g_modbus_conf.alarm = 0;
	read_modbus_config(g_modbus_conf);	//初始化modbus地址

	//保存图片线程
	saveThread.init();
	saveThread.start_work();
#ifdef __UDPSend
	sThread.init(UDP_Info_queue,g_sys_conf.MonitorIP ,g_sys_conf.MonitorPort);
	sThread.start_work();

	rThread = new threadReceive();
	rThread->init(g_sys_conf.MonitorIP ,g_sys_conf.MonitorPort);
	connect(rThread, &threadReceive::sendMsgToCigratte, this, &Cigarette::recMsgFromUdp);
	rThread->start_work();

	sThread.sendData("ReStartOk", g_sys_conf.FeedbackPort);
	sThread.sendData("DebugDis", g_sys_conf.FeedbackPort);
	sThread.sendData("LockOk", g_sys_conf.FeedbackPort);
#endif

#ifdef __ExportData
	exportDataThread.init();
	exportDataThread.start_work();
#endif

	m_PLCDevice = new PLCDevice;
	PLCDevice::init_plc(m_PLCDevice);

	if(m_PLCDevice->g_plc_ok)
	{
		printf("Connected to dev!\n");
		ui.label_plc->setText(QStringLiteral("PLC正常"));
		ui.label_plc->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
		m_PLCDevice->g_plc_status|=(0x01);
		uint8_t Data8;
		m_PLCDevice->read_bits_from_plc( g_modbus_conf.no_kick, 1 ,&Data8);
		ui.checkBox_unkick->setChecked(Data8);
#ifdef __UDPSend
		if(Data8)sThread.sendData("UnKickOk", g_sys_conf.FeedbackPort);
		else sThread.sendData("UnKickFail", g_sys_conf.FeedbackPort);
#endif
		//初始化PLC的寄存器值
		read_plc_items();
		init_plc_value();
	}
	else
	{
		printf("\nSorry,fail to connect ttyS0,please check your device's state.\n");
		ui.label_plc->setText(QStringLiteral("PLC断开"));
		ui.label_plc->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		m_PLCDevice->g_plc_status&=~(0x01);
	}
	std::cout << " Enumerate Cameras..."<< std::endl;

	EnumerateCameras((SingleCamInfoStruct*)&SingleCamInfo,true,g_sys_conf);

	/*if (!license_pass)	授权检查失败
	{
		QMessageBox::information(NULL, QStringLiteral("授权检查失败"), QStringLiteral("授权检查失败，请联系系统供应商！"), QMessageBox::Ok);
		exit(0);
	}*/

	// 剔除值清0
	int ret = m_PLCDevice->write_bit_2_plc(g_modbus_conf.shift, 1);//给PLC发送换班消息

	//创建相机工作线程
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		if(SingleCamInfo[i].Detect){
			cam_status_mat[i]->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
			QString model_path, model_name;
			if (g_sys_conf.model_path.isEmpty()) {
				model_path = "D:/model";
				g_sys_conf.model_path = "D:/model";
			}
			else
				model_path = g_sys_conf.model_path;
			
			if (g_sys_conf.model_name.isEmpty()) {
				model_name = "jd.weights";
				g_sys_conf.model_name = "jd.weights";
			}
			else
				model_name = g_sys_conf.model_name;

			if (!alg_jd[i].init(model_path, model_name))
			{
				QMessageBox::information(NULL, QStringLiteral("系统自检失败"), QStringLiteral("AI模型1初始化失败，请检查程序完整性"), QMessageBox::Ok);
				exit(-1);
			}
			CreatWorkThread(SingleCamInfo[i].CamClass, i, this);
		}
		else {
			QDateTime ts_start = QDateTime::currentDateTime();
			QTime time = QTime::currentTime();
			QDateTime local(ts_start);
			QString localTime = local.toString("yyyy-MM-dd hh:mm:ss");

			if (g_modbus_conf.alarm > 0)
			{
				uint16_t dest16[2] = { 5+i,0 };
				int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
				//if (ret > 0) SingleCamInfo[0].OffLine = false;

				if (ret > 0)
				{
					AlarmInfo alarm_info;
					alarm_info.alarm_code = dest16[0];
					if ((alarm_info.alarm_code > 0) && (alarm_info.alarm_code <= 12))
					{
						alarm_info.alarm_msg = (g_alarm_msg[alarm_info.alarm_code]).toStdString();
						alarm_info.alarm_start = localTime.toStdString();
						ui.label_alarm->setText(g_alarm_msg[alarm_info.alarm_code]);
						ui.label_alarm->setStyleSheet(tr("background-color: rgb(255, 0, 0);"));
						if (g_last_alarm_code != alarm_info.alarm_code)
						{
							g_vec_alarm.push_back(alarm_info);
							g_last_alarm_code = alarm_info.alarm_code;
						}
					}
					else if (alarm_info.alarm_code == 0) {
						ui.label_alarm->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
						ui.label_alarm->setText(QStringLiteral("无报警"));
					}
#ifdef __UDPSend
					QString str;
					str = QString("alarm") + '_' + QString::number(alarm_info.alarm_code);
					sThread.sendData(str, g_sys_conf.FeedbackPort);
#endif
				}
			}
		}

	}
	
#ifdef __DEBUG
	alg_test.init(g_sys_conf.model_path, g_sys_conf.model_name);//test AI算法
#endif

	//自动打开所有相机
	if (g_sys_conf.auto_open == 1)
	{
		for (int i = 0; i < NumberOfSupportedCameras; i++)
		{
			if(SingleCamInfo[i].Detect){
				if(ControlCamOpenOrClose(i,OPEN))
				{
					cam_work_mat[i]->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
					QString str = QString("border-image: url(:/Cigarette/Resources/cam%1_yes.png);").arg(i+1);
					QByteArray ba = str.toLatin1();
					cam_toolButton_mat[i]->setStyleSheet(tr(ba.data()));
				}
			}
		}
	}
	
	DisableDebugMode();

	m_pTimer = new QTimer(this);
	connect(m_pTimer, SIGNAL(timeout()), this, SLOT(handleTimeout()));
	m_pTimer->start(1000);

	m_delay = new QTimer(this);//换班防连击
	connect(m_delay, SIGNAL(timeout()), this, SLOT(enable_shift()));

	m_sendMsg_delay = new QTimer(this);
	connect(m_sendMsg_delay, SIGNAL(timeout()), this, SLOT(sendLatestData()));

	m_op_delay = new QTimer(this);
	connect(m_op_delay, SIGNAL(timeout()), this, SLOT(op_timeout()));

	m_admin_delay = new QTimer(this);
	connect(m_admin_delay, SIGNAL(timeout()), this, SLOT(admin_timeout()));

	clean_pTimer = new QTimer(this);
	connect(clean_pTimer,SIGNAL(timeout()), this, SLOT(CleanThreadStartAuto()));
	clean_pTimer->start(3600000);

	connect(ui.label_alarm, SIGNAL(QlabelDoubleClick()), this, SLOT(OnCancelAlarm()));//报警标签双击消警

	image_lable_DBsignalMapper0 = new QSignalMapper(this);
	image_lable_DBsignalMapper1 = new QSignalMapper(this);
	image_lable_TPsignalMapper0 = new QSignalMapper(this);
	image_lable_TPsignalMapper1 = new QSignalMapper(this);
	label_ng_signalMapper = new QSignalMapper(this);
	pTimer_Cam_signalMapper = new QSignalMapper(this);
	toolButton_cam_signalMapper = new QSignalMapper(this);
	RotateReleased_signalMapper = new QSignalMapper(this);
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		m_pTimer_Cam_mat[i] = new QTimer(this);
		connect(m_pTimer_Cam_mat[i], SIGNAL(timeout()), pTimer_Cam_signalMapper, SLOT(map()));
		pTimer_Cam_signalMapper->setMapping(m_pTimer_Cam_mat[i], i);

		connect(display_lable_mat[i][0], SIGNAL(QlabelDoubleClick()), image_lable_DBsignalMapper0, SLOT(map()));
		image_lable_DBsignalMapper0->setMapping(display_lable_mat[i][0], i << 4 | 0);

		connect(display_lable_mat[i][1], SIGNAL(QlabelDoubleClick()), image_lable_DBsignalMapper1, SLOT(map()));
		image_lable_DBsignalMapper1->setMapping(display_lable_mat[i][1], i << 4 | 1);

		connect(display_lable_mat[i][0], SIGNAL(QlabelTripleClick()), image_lable_TPsignalMapper0, SLOT(map()));
		image_lable_TPsignalMapper0->setMapping(display_lable_mat[i][0], i << 4 | 0);

		connect(display_lable_mat[i][1], SIGNAL(QlabelTripleClick()), image_lable_TPsignalMapper1, SLOT(map()));
		image_lable_TPsignalMapper1->setMapping(display_lable_mat[i][1], i << 4 | 1);

		connect(label_ng_mat[i], SIGNAL(QlabelDoubleClick()), label_ng_signalMapper, SLOT(map()));
		label_ng_signalMapper->setMapping(label_ng_mat[i], i);

		connect(cam_toolButton_mat[i], SIGNAL(released()), toolButton_cam_signalMapper, SLOT(map()));
		toolButton_cam_signalMapper->setMapping(cam_toolButton_mat[i], i);

		connect(rotate_mat[i], SIGNAL(released()), RotateReleased_signalMapper, SLOT(map()));
		RotateReleased_signalMapper->setMapping(rotate_mat[i], i);
		
	}
	connect(toolButton_cam_signalMapper, SIGNAL(mapped(int)), this, SLOT(OnToolButtonCamReleasedHub(int)));
	connect(pTimer_Cam_signalMapper, SIGNAL(mapped(int)), this, SLOT(OpenCamTimeoutHub(int)));
	connect(image_lable_DBsignalMapper0, SIGNAL(mapped(int)), this, SLOT(OnDBClickHub(int)));
	connect(image_lable_DBsignalMapper1, SIGNAL(mapped(int)), this, SLOT(OnDBClickHub(int)));
#ifdef DRAW_RECT
	connect(image_lable_TPsignalMapper0, SIGNAL(mapped(int)), this, SLOT(OnTPClickHub(int)));
	connect(image_lable_TPsignalMapper1, SIGNAL(mapped(int)), this, SLOT(OnTPClickHub(int)));
#endif
	connect(label_ng_signalMapper, SIGNAL(mapped(int)), this, SLOT(OnDBClickNGHub(int)));
	connect(RotateReleased_signalMapper, SIGNAL(mapped(int)), this, SLOT(OnRotateReleasedHub(int)));

	//禁用调试按钮
	ui.checkBox_debug->setEnabled(false);
	//隐藏OK/NG按钮
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		label_reslut_mat[i]->setVisible(false);
	}
	ui.label_role->setText(QStringLiteral("未登录"));
	
	//自动开始工作
	if (g_sys_conf.auto_work == 1)
	{
		for (int i = 0; i < NumberOfSupportedCameras; i++)
		{
			if(SingleCamInfo[i].Detect && SingleCamInfo[i].IsOpen){
				if(SingleCamInfo[i].CamClass == BalluffClassID){
					if(pCaptureThread[i])
						while(!pCaptureThread[i]->Ready)Sleep(10);
				}else if(SingleCamInfo[i].CamClass == BaslerClassID){
					if(pBaslerCaptureThread[i])
						while(!pBaslerCaptureThread[i]->Ready)Sleep(10);
				}else if(SingleCamInfo[i].CamClass == HIKClassID){
					if(pHIKCaptureThread[i])
						while(!pHIKCaptureThread[i]->Ready)Sleep(10);
				}
			}
		}

		if (m_PLCDevice->g_plc_ok) {
			BeforeWork(g_sys_conf.shoot);
			int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.work, 1);
			ui.label_title->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
#ifdef __UDPSend
			sThread.sendData("Work", g_sys_conf.FeedbackPort);
#endif
			g_working = true;
			ui.checkBox_debug->setChecked(false);	//锁定调试不可用
			ui.checkBox_debug->setEnabled(false);	//锁定调试不可用
			for (int i = 0; i < NumberOfSupportedCameras; i++)
			{
				//显示OK/NG按钮
				label_reslut_mat[i]->setVisible(true);
			}
		}
	}
	//connect(ui.btn_pause, SIGNAL(clicked()), this, SLOT(sendLatestData()));
}

Cigarette::~Cigarette()
{
	emit sengMsgToClog("Application exited.");
	Exit();
	exit(-1);
}

void Cigarette::start_work()
{
	//清除采集临时队列缓存
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		if(SingleCamInfo[i].Detect && SingleCamInfo[i].IsOpen){
			if(SingleCamInfo[i].CamClass == BalluffClassID){
				if(pCaptureThread[i])
				{
					pCaptureThread[i]->p_result_queue->clear();
					pCaptureThread[i]->p_unit_queue->clear();
					pCaptureThread[i]->p_result_wait_queue->clear();
					pCaptureThread[i]->p_shooted_queue->clear();
				}
			}
			else if (SingleCamInfo[i].CamClass == BaslerClassID) {
				if(pBaslerCaptureThread[i])
				{
					pBaslerCaptureThread[i]->p_result_queue->clear();
					pBaslerCaptureThread[i]->p_unit_queue->clear();
					pBaslerCaptureThread[i]->p_result_wait_queue->clear();
					pBaslerCaptureThread[i]->p_shooted_queue->clear();
				}
			}
			else if (SingleCamInfo[i].CamClass == HIKClassID) {
				if(pHIKCaptureThread[i])
				{
					pHIKCaptureThread[i]->p_result_queue->clear();
					pHIKCaptureThread[i]->p_unit_queue->clear();
					pHIKCaptureThread[i]->p_result_wait_queue->clear();
					pHIKCaptureThread[i]->p_shooted_queue->clear();
				}
			}
		}
	}

	BeforeWork(g_sys_conf.shoot);
	int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.work, 1);
	/*::Sleep(5000);
	ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.work, 0);
	::Sleep(5000);
	ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.work, 1);*/
	//printf("write:\t%d\n", ret);
	ui.label_title->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
#ifdef __UDPSend
	sThread.sendData("Work", g_sys_conf.FeedbackPort);
#endif
	g_working = true;
	ui.checkBox_debug->setChecked(false);	//取消调试模式
	ui.checkBox_debug->setEnabled(false);	//锁定调试不可用
	//显示OK/NG按钮
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		//显示OK/NG按钮
		label_reslut_mat[i]->setVisible(true);
	}
}
//开始按钮
void Cigarette::on_btn_start_released()
{
	emit sengMsgToClog("Start to work.");
	if (!g_admin_mode)
	{
		if (!g_op_mode)
		{
			emit sengMsgToClog("Start to login in.");
			dialogin = new Dialogin(this);
			connect(dialogin, SIGNAL(enter_op()), this, SLOT(OnOp()));
			dialogin->setModal(true);
			dialogin->show();
			dialogin->move((this->width() - dialogin->width()) / 2, (this->height() - dialogin->height()) / 2);
			return;
		}
	}
	if (m_PLCDevice->g_plc_ok) {
		if (g_debug_mode)
		{
			QMessageBox::information(NULL, QStringLiteral("操作顺序检查"), QStringLiteral("请先点击“调试模式”复选框，取消调试模式，才可以开始工作"), QMessageBox::Ok);
			return;
		}
		if (!g_working)
		{
			start_work();
		}
	}
	g_op_time = OP_TIME;
	//ui.checkBox_debug->setEnabled(true);	//使能相机调试checkBox
}

void Cigarette::pause_work()
{
	int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.work, 0 );
	//printf("write:\t%d\n", ret);
	ui.label_title->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
#ifdef __UDPSend
	sThread.sendData("NoWork", g_sys_conf.FeedbackPort);
#endif
	g_working = false;
	ui.checkBox_debug->setEnabled(true);	//使能相机调试checkBox
	//隐藏OK/NG按钮
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		//显示OK/NG按钮
		label_reslut_mat[i]->setVisible(false);
	}

	m_sendMsg_delay->setSingleShot(true);
	m_sendMsg_delay->start(1000);
}

void Cigarette::Exit()
{
	this->on_btn_pause_released();
	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		if(SingleCamInfo[i].Detect){
			if(ControlCamOpenOrClose(i,CLOSE))
			{
				qDebug() << "Close device " << i;
				cam_work_mat[i]->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
			}
		}
		work_thread[i].stop();
		debug_thread[i].stop();
		delete g_image_queue[i];
		delete g_result_queue[i];
		delete g_result_wait_queue[i];
		delete g_double_queue[i];
		delete g_shooted_queue[i];
		delete g_debug_queue[i];
		qDebug() << "Close capture thread " << i;
	}
	saveThread.stop();
	delete g_save_queue;
#ifdef __UDPSend
	sThread.stop();
	rThread->stop();
	delete rThread;
#endif

#ifdef __ExportData
	exportDataThread.stop();
	// delete export_Data_Info_queue;
#endif
	qDebug() << "Close thread ";
	
	if(m_PLCDevice) {
		m_PLCDevice->disconnect_plc();
		delete m_PLCDevice;
	}
	qApp->quit();
	this->close();

	Pylon::PylonTerminate();

		
}
//停止工作按钮
void Cigarette::on_btn_pause_released()
{
	emit sengMsgToClog("Pause the application.");
	if (!g_admin_mode)
	{
		if (!g_op_mode)
		{
			emit sengMsgToClog("Start to login in.");
			dialogin = new Dialogin(this);
			connect(dialogin, SIGNAL(enter_op()), this, SLOT(OnOp()));
			dialogin->setModal(true);
			dialogin->show();
			dialogin->move((this->width() - dialogin->width()) / 2, (this->height() - dialogin->height()) / 2);
			return;
		}
	}
	if (m_PLCDevice->g_plc_ok) {
		if (g_working){
			pause_work();
		}
	}
	g_op_time = OP_TIME;
}

//锁定/解锁按钮
void Cigarette::on_btn_lock_released()
{
	if (!g_admin_mode)
	{
		emit sengMsgToClog("Unlock the application.");
		dialog_setup_passwd = new DialogSetupPasswd(this);
		connect(dialog_setup_passwd, SIGNAL(enter_admin()), this, SLOT(OnAdmin()));
		dialog_setup_passwd->setModal(true);
		dialog_setup_passwd->show();
		dialog_setup_passwd->move((this->width() - dialog_setup_passwd->width()) / 2, (this->height() - dialog_setup_passwd->height()) / 2);
	}
	else
	{
		emit sengMsgToClog("Lock the application.");
		g_admin_mode = false;
		g_op_mode = false;
		ui.label_12->setText(QStringLiteral("登录用户："));
		ui.label_role->setText(QStringLiteral("未登录"));
		ui.btn_lock->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/unlock.png);"));
		ui.checkBox_debug->setEnabled(false);
		if (m_op_delay->isActive())
		{
			m_op_delay->stop();
		}
		if (m_admin_delay->isActive())
		{
			m_admin_delay->stop();
		}
#ifdef __UDPSend
		sThread.sendData("LockOk", g_sys_conf.FeedbackPort);
#endif
	}
}
//设置按钮
void Cigarette::on_btn_setup_released()
{
	emit sengMsgToClog("Start to set the application.");
	if (g_admin_mode)
	{
		dialog_setup = new DialogSetup(this);
		connect(dialog_setup, SIGNAL(system_exit()), this, SLOT(OnExit()));
#ifdef __DEBUG
		connect(dialog_setup, SIGNAL(_testimg()), this, SLOT(TestImg()));
		connect(dialog_setup, SIGNAL(_testimgs()), this, SLOT(TestImgs()));
#endif
		dialog_setup->setModal(true);
		dialog_setup->show();
		dialog_setup->move((this->width() - dialog_setup->width()) / 2, (this->height() - dialog_setup->height()) / 2);
	}
	else {
		QMessageBox::information(NULL, QStringLiteral("权限检查"), QStringLiteral("请先点击解锁按钮，进入管理员模式"), QMessageBox::Ok);
	}
}
#ifdef __DEBUG
void Cigarette::TestImg()
{
	QString srcDirPath = QString::fromStdString(SelectFileOFN());

    //输入图像
    std::cout << "open file------ " << srcDirPath.toStdString() << std::endl;
    cv::Mat imagein = cv::imread(srcDirPath.toStdString(), cv::IMREAD_COLOR);
    if (!imagein.data)
    {
        return;
    }
    std::vector<std::pair<int, cv::Rect> > results;
    cv::Mat output;
    alg_test.detect(imagein, output,results);
	std::string WindowName = "TestImg";
	cv::namedWindow(WindowName, cv::WINDOW_NORMAL);
	cv::imshow(WindowName, output);
    cv::waitKeyEx(1);
#ifdef __ExportData
	alg_test.analyse(imagein, results);
#endif
}

void Cigarette::TestImgs()
{
	QString srcDirPath = QString::fromStdString(SelectDirIFD());

    vector<string> files;
    std::cout << "srcDirPath=" << srcDirPath.toStdString() << std::endl;
    srcDirPath += "/";
    //获取该路径下的所有文件
    getFiles(srcDirPath.toStdString() + "*.bmp", files);
    if (files.size() == 0)
    {
        QMessageBox::StandardButton result = QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("没有找到图片"));
        return;
    }

    for (int index = 0; index < files.size(); index++)
    {
        //输入图像
        std::cout << "open file------ " << files[index] << std::endl;
        cv::Mat imagein = cv::imread(srcDirPath.toStdString() + files[index], cv::IMREAD_COLOR);
        if (!imagein.data)
        {
            break;
        }

        cv::Mat output;
		std::vector<std::pair<int, cv::Rect> > results;
        alg_test.detect(imagein, output,results);
		std::string WindowName = "TestImg";
		cv::namedWindow(WindowName, cv::WINDOW_NORMAL);
		cv::imshow(WindowName, output);
        int k = cv::waitKeyEx(1);
        if (k == 27)break;//ESC键
#ifdef __ExportData
		alg_test.analyse(imagein, results);
#endif
        QCoreApplication::processEvents();
    }
}
#endif
//管理员登陆
void Cigarette::OnAdmin()
{
	emit sengMsgToClog("Administrator is login in.");
	g_admin_mode = true;
	ui.label_12->setText(QStringLiteral("登录用户："));
	ui.label_role->setText(QStringLiteral("管理员"));
	ui.btn_lock->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/lock.png);"));
	ui.checkBox_debug->setEnabled(true);
	g_admin_time = ADMIN_TIME;
	m_admin_delay->start(1000);
	if (m_op_delay->isActive())
	{
		m_op_delay->stop();
	}
#ifdef __UDPSend
		sThread.sendData("UnlockOk", g_sys_conf.FeedbackPort);
#endif
}
//操作员登陆
void Cigarette::OnOp()
{
	emit sengMsgToClog("Operator is login in.");
	g_op_mode = true;
	g_op_time = OP_TIME;
	ui.label_role->setText(QStringLiteral("操作员"));
	m_op_delay->start(1000);
}
//退出前执行
void Cigarette::OnExit()
{
	emit sengMsgToClog("Close the Application.");
	Exit();
	exit(-1);
}

void Cigarette::OnRestart()
{
	Exit();
	QProcess::startDetached(qApp->applicationFilePath(), QStringList());
}
//换班防连击
void Cigarette::enable_shift()
{
	ui.pushButton_clear->setEnabled(true);
}

void Cigarette::sendLatestData() {
	// 连接UDP发送最新的数据
	int dataport = g_sys_conf.MonitorPort;
	_UDPSendInfo UDPSendInfo;
	//UDP_Info_queue->take(UDPSendInfo);
	
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		UDPSendInfo.index = i;
		UDPSendInfo.FrameID = ok_frame;
		UDPSendInfo.ok[i] = ok[i];
#ifdef __UDPSend
		//sThread.sendData(("4_" + to_string(ok[i])).c_str(), dataport + UDPSendInfo.index);
		UDP_Info_queue->put(UDPSendInfo);
#endif
		UDPSendInfo.FrameID = ng_frame;
		UDPSendInfo.ng[i] = ng[i];
#ifdef __UDPSend
		//sThread.sendData(("5_" + to_string(ng[i])).c_str(), dataport + UDPSendInfo.index);
		UDP_Info_queue->put(UDPSendInfo);
#endif
		UDPSendInfo.FrameID = total_frame;
		UDPSendInfo.Total = production_number[i];
#ifdef __UDPSend
		//sThread.sendData(("7_" + to_string(production_number[i])).c_str(), dataport + UDPSendInfo.index);
		UDP_Info_queue->put(UDPSendInfo);
#endif
	}
}

void Cigarette::OnRotateReleasedHub(int Num)//旋转按钮
{
	QString str = "Start to rotate picture " + QString::number(90 * ((rotationAngle[Num] + 1) % 4)) + " degrees of camera " + QString::number(Num) + ".";
	emit sengMsgToClog(str);
	if(isNeedRotate[Num] == true)
	{
		rotationAngle[Num] = (rotationAngle[Num] + 1) % 4;
		save_rotate_message();
	}
}

//打开/关闭相机
void Cigarette::OnToolButtonCamReleasedHub(int Num)
{
	if (g_admin_mode)
	{
		if(SingleCamInfo[Num].Detect)
		{
			if (!SingleCamInfo[Num].IsOpen)
			{
				emit sengMsgToClog("Start open camera " + QString::number(Num) + ".");
				if(ControlCamOpenOrClose(Num,OPEN))
				{
					cam_work_mat[Num]->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));//相机工作提示
					cam_status_mat[Num]->setStyleSheet(tr("background-color: rgb(0,170,0);"));//相机联机指示
					QString str = QString("border-image: url(:/Cigarette/Resources/cam%1_yes.png);").arg(Num+1);
					QByteArray ba = str.toLatin1();
					cam_toolButton_mat[Num]->setStyleSheet(tr(ba.data()));
				}
			}
			else
			{
				emit sengMsgToClog("Start close camera " + QString::number(Num) + ".");
				if(ControlCamOpenOrClose(Num,CLOSE))
				{
					cam_work_mat[Num]->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
					QString str = QString("border-image: url(:/Cigarette/Resources/cam%1_no.png);").arg(Num+1);
					QByteArray ba = str.toLatin1();
					cam_toolButton_mat[Num]->setStyleSheet(tr(ba.data()));
				}
			}
		}
		else
		{
			emit sengMsgToClog("Close or open camera " + QString::number(Num) + " fail, there is no camera in potision 0.");
			QMessageBox::information(NULL, QStringLiteral("操作失败"), QStringLiteral("该机位没有检测到相机"), QMessageBox::Ok);
		}
	}
	else {
		emit sengMsgToClog("Close or open camera " + QString::number(Num) + " fail, because of authorization check fail.");
		QMessageBox::information(NULL, QStringLiteral("权限检查"), QStringLiteral("请先点击解锁按钮，进入管理员模式"), QMessageBox::Ok);
	}
}

void Cigarette::ReconnectCamHub(int Num)
{
	//close
	if(SingleCamInfo[Num].Detect)
	{
		if(ControlCamOpenOrClose(Num,CLOSE))
		{
			m_pTimer_Cam_mat[Num]->setSingleShot(true);
			m_pTimer_Cam_mat[Num]->start(2000);
		}
	}
}

void Cigarette::OpenCamTimeoutHub(int Num)	//重新打开相机
{
	//open
	if(ControlCamOpenOrClose(Num,OPEN))
	{
		cam_work_mat[Num]->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
		cam_toolButton_mat[Num]->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam1_yes.png);"));
	}
}

void Cigarette::OnKey(QKeyEvent* event)
{
	int Num = CurOpLabel >> 4;
	int Cnt = CurOpLabel & 0x0f;

	std::lock_guard<std::mutex> locker(g_display_label_conf[Num].lock);
	if (event->key() == Qt::Key_Escape && event->isAutoRepeat()==false)
	{
		if (g_display_label_conf[Num].RectVet[Cnt].size())
		{
			g_display_label_conf[Num].RectVet[Cnt].pop_back();
		}
	}
	else if (event->key() == Qt::Key_Return && event->isAutoRepeat()==false)
	{
		std::fstream cfg_file;
		char buf[256];
		memset(buf, 0, 256);
		sprintf(buf, SELECT_RECTS_FILE, Num,Cnt);
		cfg_file.open(buf, ios::trunc | ofstream::out);
		if (!cfg_file.is_open())
		{
			std::cout << "Error: Open config file SelectRects.txt" << std::endl;
			return;
		}
		for (int i = 0; i < g_display_label_conf[Num].RectVet[Cnt].size(); i++)
		{
			char buf[256];
			memset(buf, 0, 256);
			sprintf(buf,
				"%03f,%03f,%03f,%03f\n",
				g_display_label_conf[Num].RectVet[Cnt][i].TL.x,
				g_display_label_conf[Num].RectVet[Cnt][i].TL.y,
				g_display_label_conf[Num].RectVet[Cnt][i].BR.x,
				g_display_label_conf[Num].RectVet[Cnt][i].BR.y
			);
			cfg_file.write(buf, strlen(buf));
		}
	}
}
//鼠标回调函数  
void Cigarette::OnMouse(QMouseEvent* event)
{
	int Num = CurOpLabel>>4;
	int Cnt = CurOpLabel&0x0f;

	int CurWidgetWidth = display_lable_mat[Num][Cnt]->width();
	int CurWidgetHeight = display_lable_mat[Num][Cnt]->height();

	std::lock_guard<std::mutex> locker(g_display_label_conf[Num].lock);
    if (event->type() == QEvent::MouseButtonPress)
    {
        g_display_label_conf[Num].leftButtonDownFlag = true; //标志位
        g_display_label_conf[Num].originalPoint = cv::Point2f(
			event->x() * 1.0 / CurWidgetWidth,
			event->y() * 1.0 / CurWidgetHeight
		);  //设置左键按下点的矩形起点
        g_display_label_conf[Num].processPoint = g_display_label_conf[Num].originalPoint;
    }
    if (event->type() == QEvent::MouseMove && g_display_label_conf[Num].leftButtonDownFlag)
    {
		g_display_label_conf[Num].processPoint = cv::Point2f(
			event->x() * 1.0 / CurWidgetWidth,
			event->y() * 1.0 / CurWidgetHeight
		);
    }
    if (event->type() == QEvent::MouseButtonRelease)
    {
		g_display_label_conf[Num].leftButtonDownFlag = false;
		RectRatio m_RectRatio = RectRatio(
			cv::Point2f(g_display_label_conf[Num].originalPoint.x * 1.0,
				g_display_label_conf[Num].originalPoint.y * 1.0
			),
			cv::Point2f(event->x() * 1.0 / CurWidgetWidth,
				event->y() * 1.0 / CurWidgetHeight
			)
		);
		float tempx = abs((m_RectRatio.TL - m_RectRatio.BR).x);
		float tempy = abs((m_RectRatio.TL - m_RectRatio.BR).y);
		if(tempx >0.05)
		g_display_label_conf[Num].RectVet[Cnt].push_back(m_RectRatio);
    }
}

//双击视图1
void Cigarette::OnDBClickHub(int Num_Cnt)
{
	int Num = Num_Cnt>>4;
	int Cnt = Num_Cnt&0x0f;

	CurOpLabel = Num_Cnt;
	std::lock_guard<std::mutex> locker(g_display_label_conf[Num].lock);
	if (g_display_label_conf[Num].g_max[Cnt])
	{	/// 全屏状态下 双击取消全屏
		emit sengMsgToClog("Cancel the picture of camera " + QString::number(Num) + " to full screen.");
		g_display_label_conf[Num].g_max[Cnt] = false;
		display_lable_mat[Num][Cnt]->setGeometry(
			display_lable_info[Num][Cnt].x,
			display_lable_info[Num][Cnt].y,
			display_lable_info[Num][Cnt].width,
			display_lable_info[Num][Cnt].height
		);
		rotate_mat[Num]->setGeometry(
			rotate_info[Num].x,
			rotate_info[Num].y,
			rotate_info[Num].width,
			rotate_info[Num].height
		);
		if(g_display_label_conf[Num].Flag[Cnt] & DisplayLabel_Type_Bit)
		{
			g_display_label_conf[Num].Flag[Cnt] &= ~DisplayLabel_Conf_Bit;
			disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalmousePressEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
			disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalmouseMoveEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
			disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalmouseReleaseEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
			disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalkeyReleaseEvent(QKeyEvent*)), this, SLOT(OnKey(QKeyEvent*)));
		}
	}
	else
	{	// 双击全屏
		emit sengMsgToClog("Set the picture of camera " + QString::number(Num) + " to full screen.");
		g_display_label_conf[Num].g_max[Cnt] = true;
		display_lable_mat[Num][Cnt]->setGeometry(0, 0, 1280, 800);

		//rotate_mat[Num]->setGeometry(1230, 10, 40, 40);

		if (g_debug_mode)//是否为调试模式
		{
			rotate_mat[Num]->setGeometry(1230, 10, 40, 40);
		}
		else
		{
			rotate_mat[Num]->setGeometry(1230, 10, 0, 0);
		}

		display_lable_mat[Num][Cnt]->raise();
		rotate_mat[Num]->raise();

		if(g_display_label_conf[Num].Flag[Cnt] & DisplayLabel_Type_Bit)
		{
			g_display_label_conf[Num].Flag[Cnt] |= DisplayLabel_Conf_Bit;
			connect(display_lable_mat[Num][Cnt], SIGNAL(SignalmousePressEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
			connect(display_lable_mat[Num][Cnt], SIGNAL(SignalmouseMoveEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
			connect(display_lable_mat[Num][Cnt], SIGNAL(SignalmouseReleaseEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
			connect(display_lable_mat[Num][Cnt], SIGNAL(SignalkeyReleaseEvent(QKeyEvent*)), this, SLOT(OnKey(QKeyEvent*)));
		}
	}
	OnNotifyHub(Num,Cnt,g_display_label_conf[Num].g_last_mat[Cnt]);
}

void Cigarette::DrawRect_init(int Num_Cnt) {
	//int Num = Num_Cnt >> 4;
	//int Cnt = Num_Cnt & 0x0f;

	int Num = Num_Cnt & 0x0f;
	int Cnt = Num_Cnt >> 4;
	if (g_display_label_conf[Num].Flag[Cnt] & DisplayLabel_Type_Bit)
	{
		g_display_label_conf[Num].Flag[Cnt] &= ~DisplayLabel_Type_Bit;
		g_display_label_conf[Num].Flag[Cnt] &= ~DisplayLabel_Conf_Bit;
	}
	else {
		g_display_label_conf[Num].Flag[Cnt] |= DisplayLabel_Type_Bit;
		std::fstream cfg_file;
		char buf[256];
		memset(buf, 0, 256);
		sprintf(buf, SELECT_RECTS_FILE, Num, Cnt);
		cfg_file.open(buf);
		if (!cfg_file.is_open())
		{
			std::cout << "Error: Open config file SelectRects"<<Num<<Cnt<<".txt" << std::endl;
			return;
		}
		while (!cfg_file.eof())
		{
			char tmp[256] = "";
			cfg_file.getline(tmp, 256);
			QString line = QString::fromStdString(std::string(tmp));
			QStringList dataList = line.split(',');
			if (dataList.length() == 4)
			{
				RectRatio m_RectRatio = RectRatio(
					cv::Point2f(dataList[0].toFloat(), dataList[1].toFloat()),
					cv::Point2f(dataList[2].toFloat(), dataList[3].toFloat())
				);
				g_display_label_conf[Num].RectVet[Cnt].push_back(m_RectRatio);
			}
		}
	}
}

void Cigarette::OnTPClickHub(int Num_Cnt)
{
	int Num = Num_Cnt >> 4;
	int Cnt = Num_Cnt & 0x0f;
	
	std::lock_guard<std::mutex> locker(g_display_label_conf[Num].lock);
	if (g_display_label_conf[Num].Flag[Cnt] & DisplayLabel_Type_Bit)
	{
		g_display_label_conf[Num].Flag[Cnt] &= ~DisplayLabel_Type_Bit;
		g_display_label_conf[Num].Flag[Cnt] &= ~DisplayLabel_Conf_Bit;
		disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalmousePressEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
		disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalmouseMoveEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
		disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalmouseReleaseEvent(QMouseEvent*)), this, SLOT(OnMouse(QMouseEvent*)));
		disconnect(display_lable_mat[Num][Cnt], SIGNAL(SignalkeyReleaseEvent(QKeyEvent*)), this, SLOT(OnKey(QKeyEvent*)));
	}
	else
	{
		g_display_label_conf[Num].Flag[Cnt] |= DisplayLabel_Type_Bit;
		std::fstream cfg_file;
		char buf[256];
		memset(buf, 0, 256);
		sprintf(buf, SELECT_RECTS_FILE, Num, Cnt);
		cfg_file.open(buf);
		if (!cfg_file.is_open())
		{
			std::cout << "Error: Open config file SelectRects.txt" << std::endl;
			return;
		}
		while (!cfg_file.eof())
		{
			char tmp[256] = "";
			cfg_file.getline(tmp, 256);
			QString line = QString::fromStdString(std::string(tmp));
			QStringList dataList = line.split(',');
			if (dataList.length() == 4)
			{
				RectRatio m_RectRatio = RectRatio(
					cv::Point2f(dataList[0].toFloat(),dataList[1].toFloat()),
					cv::Point2f(dataList[2].toFloat(),dataList[3].toFloat())
				);
				g_display_label_conf[Num].RectVet[Cnt].push_back(m_RectRatio);
			}
		}
	}
}
//双击NG
void Cigarette::OnDBClickNGHub(int Num)
{
	emit sengMsgToClog("Double click NG.");
	QDateTime now_ts = QDateTime::currentDateTime();
	std::ostringstream   ostr;
	ostr << "explorer D:\\image\\" << (now_ts.toString("yyyy-MM-dd")).toStdString()<< "\\" << Num+1 << "\\ng_result";
	std::string str = ostr.str();
	system(str.c_str());
}

void Cigarette::OnNotifyHub(int Num, int Cnt,cv::Mat m)
{
	//将图像大小缩放为显示窗口大小
	cv::Size display_size = cv::Size(display_lable_mat[Num][Cnt]->width(), display_lable_mat[Num][Cnt]->height());
	cv::resize(m, m, display_size);

	QImage tempImage = Cigarette::cvMatToQImage(m);
	display_lable_mat[Num][Cnt]->setPixmap(QPixmap::fromImage(tempImage));
	g_display_label_conf[Num].g_last_mat[Cnt] = m;

	_UDPSendInfo UDPSendInfo;
	UDPSendInfo.FrameID = image_frame;
	UDPSendInfo.index = Num;
	UDPSendInfo.cnt = Cnt;
	UDPSendInfo.image = m.clone();
#ifdef __UDPSend
	UDP_Info_queue->put(UDPSendInfo);
#endif
}

void Cigarette::OnDisplayTimeCostHub(int Num, int ms)
{
	label_timecost_mat[Num]->setText(QString::number(ms) + "ms");
}

void Cigarette::OnDisplayCheckNumberHub(int Num, long no)
{
	production_number[Num]++;
	lcdNumber_total_mat[Num]->display(production_number[Num]);
	_UDPSendInfo UDPSendInfo;
	UDPSendInfo.FrameID = total_frame;
	UDPSendInfo.index = Num;
	UDPSendInfo.Total = production_number[Num];
#ifdef __UDPSend
	UDP_Info_queue->put(UDPSendInfo);
#endif
}

void Cigarette::OnDisplayJdNoHub(int Num, QString jd_no)
{
	label_jd_no_mat[Num]->setText(jd_no);
}

void Cigarette::OnOKHub(int Num)
{
	ok[Num]++;
	_UDPSendInfo UDPSendInfo;
	UDPSendInfo.FrameID = ok_frame;
	UDPSendInfo.index = Num;
	UDPSendInfo.ok[Num] = ok[Num];
#ifdef __UDPSend
	UDP_Info_queue->put(UDPSendInfo);
#endif
	lcdNumber_ok_mat[Num]->display(ok[Num]);
	label_reslut_mat[Num]->setText("OK");
	label_reslut_mat[Num]->setStyleSheet(tr("background-color: rgb(0, 255, 0);"));
}

void Cigarette::OnNGHub(int Num)
{
	ng[Num]++;
	_UDPSendInfo UDPSendInfo;
	UDPSendInfo.FrameID = ng_frame;
	UDPSendInfo.index = Num;
	UDPSendInfo.ng[Num] = ng[Num];
#ifdef __UDPSend
	UDP_Info_queue->put(UDPSendInfo);
#endif
	lcdNumber_ng_mat[Num]->display(ng[Num]);
	label_reslut_mat[Num]->setText("NG");
	label_reslut_mat[Num]->setStyleSheet(tr("background-color: rgb(255, 0, 0);"));
}

void Cigarette::updateStatisticsHub(const QString& statisticalData, int Num)
{
	label_cap_speed_mat[Num]->setText(statisticalData + QStringLiteral("个/秒"));
	_UDPSendInfo UDPSendInfo;
	UDPSendInfo.FrameID = speed_frame;
	UDPSendInfo.index = Num;
	UDPSendInfo.speed = statisticalData;
#ifdef __UDPSend
	UDP_Info_queue->put(UDPSendInfo);
#endif
}

//不剔除模式
void Cigarette::on_checkBox_unkick_clicked(bool checked)
{
	if (!g_admin_mode)
	{
		if (!g_op_mode)
		{
			emit sengMsgToClog("Start to login in.");
			dialogin = new Dialogin(this);
			connect(dialogin, SIGNAL(enter_op()), this, SLOT(OnOp()));
			dialogin->setModal(true);
			dialogin->show();
			dialogin->move((this->width() - dialogin->width()) / 2, (this->height() - dialogin->height()) / 2);
			ui.checkBox_unkick->setChecked(false);
			int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.no_kick, 0);
#ifdef __UDPSend
			sThread.sendData("UnKickOk", g_sys_conf.FeedbackPort);
#endif
			return;
		}
		ui.checkBox_unkick->setChecked(false);
	}
	if (m_PLCDevice->g_plc_ok) {	
		if (checked)
		{
			emit sengMsgToClog("Enter unkick mode.");
			int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.no_kick, 1);
#ifdef __UDPSend
			sThread.sendData("UnKickOk", g_sys_conf.FeedbackPort);
#endif
		}
		else
		{
			emit sengMsgToClog("Exit unkick mode.");
			int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.no_kick, 0);
#ifdef __UDPSend
			sThread.sendData("KickOk", g_sys_conf.FeedbackPort);
#endif
		}
		ui.checkBox_unkick->setChecked(checked);
	}
	else {
		ui.checkBox_unkick->setChecked(false);
		emit sengMsgToClog("Enter or exit unkick mode fail.");
#ifdef __UDPSend
		sThread.sendData("UnKickFail", g_sys_conf.FeedbackPort);
#endif
	}
}
//调试模式
void Cigarette::on_checkBox_debug_clicked(bool checked)
{
	if (!g_admin_mode)
	{
		QMessageBox::information(NULL, QStringLiteral("权限检查 "), QStringLiteral("请先点击解锁按钮，进入管理员模式"), QMessageBox::Ok);
		ui.checkBox_debug->setChecked(false);
		return;
	}
	if (checked)	//启用相机调试模式
	{
		if (g_working)
		{
			QMessageBox::information(NULL, QStringLiteral("操作顺序检查 "), QStringLiteral("请先点击‘停止工作’按钮，才能进入调试模式"), QMessageBox::Ok);
			ui.checkBox_debug->setChecked(false);
			//return;
		}
		else
		{
			emit sengMsgToClog("Enter debug mode.");
			EnableDebugMode();
			ui.checkBox_debug->setChecked(true);
#ifdef __UDPSend
			sThread.sendData("DebugEn", g_sys_conf.FeedbackPort);
#endif
		}
	}
	else //关闭相机调试
	{
		emit sengMsgToClog("Exit debug mode.");
		DisableDebugMode();
		//on_pushButton_clear_released();	//换班
		ui.checkBox_debug->setChecked(false);
		//ui.checkBox_debug->setEnabled(true);
#ifdef __UDPSend
		sThread.sendData("DebugDis", g_sys_conf.FeedbackPort);
#endif
	}
}

//打开PLC配置对话框
void Cigarette::on_toolButton_plc_released()
{
	emit sengMsgToClog("Open PLC setting.");
	if (m_PLCDevice->g_plc_ok)
	{
		if (g_admin_mode)
		{
			g_plc_dialog_open = true;
			dialog_plc_setup = new PlcSetup(this);
			dialog_plc_setup->setModal(true);
			dialog_plc_setup->show();
			dialog_plc_setup->move((this->width() - dialog_plc_setup->width()) / 2, (this->height() - dialog_plc_setup->height()) / 2);
		}
		else {
			QMessageBox::information(NULL, QStringLiteral("权限检查"), QStringLiteral("请先点击解锁按钮，进入管理员模式"), QMessageBox::Ok);
		}
	}
	else {
		QMessageBox::information(NULL, QStringLiteral("硬件问题"), QStringLiteral("请先确保PLC连接成功，再进入PLC设置"), QMessageBox::Ok);
	}
}

//操作员权限剩余时间
void Cigarette::op_timeout()
{
	g_op_time--;
	ui.label_12->setText(QString::number(g_op_time));
	if (0 == g_op_time)
	{
		g_op_mode = false;
		ui.label_12->setText(QStringLiteral("登录用户："));
		ui.label_role->setText(QStringLiteral("未登录"));
		m_op_delay->stop();
	}
}

//管理员权限剩余时间
void Cigarette::admin_timeout()
{
	g_admin_time--;
	ui.label_12->setText(QString::number(g_admin_time));
	if (0 == g_admin_time)
	{
		on_btn_lock_released();
	}
}

void Cigarette::handleTimeout()
{
	QDateTime ts_start = QDateTime::currentDateTime();
	QTime time = QTime::currentTime();
	QDateTime local(ts_start);
	QString localTime = local.toString("yyyy-MM-dd hh:mm:ss");
	ui.label_cur_time->setText(localTime);

	qint64 intervalTime = g_ts_start.secsTo(ts_start);
	int days = (intervalTime) / (24 * 3600);
	int hours = (intervalTime) % (24 * 3600) / 3600;
	int minutes = (intervalTime) % 3600 / 60;
	int second = (intervalTime) % 60;

	QString run_stat = QString(QStringLiteral("运行%1天%2时%3分%4秒"))
		.arg(days).arg(hours).arg(minutes).arg(second);
	ui.label_run_stat->setText(run_stat);

	//当班产量（从配置的PLC地址中读取）
	if (m_PLCDevice->g_plc_ok)
	{
		if (!g_plc_dialog_open)	//PLC配置对话框没有打开
		{
			if (g_modbus_conf.quantity > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc( g_modbus_conf.quantity, 2, dest16);
				if (ret == 2)
				{
					int cur_quantity = dest16[0] + (dest16[1] << 16);
					ui.lcdNumber_total_no->display(cur_quantity);
#ifdef __UDPSend
					sThread.sendData("total_" + QString::number(cur_quantity), g_sys_conf.FeedbackPort);
					sThread.sendData("totallast_" + QString::number(ui.lcdNumber_total_no_last->intValue()), g_sys_conf.FeedbackPort);
#endif
					ui.label_plc->setText(QStringLiteral("PLC在线"));
					ui.label_plc->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
					if(!(m_PLCDevice->g_plc_status&0x01))
					{
						init_plc_value();
						if(g_working)
						{
							if (g_debug_mode)
							{
								QMessageBox::information(NULL, QStringLiteral("操作顺序检查"), QStringLiteral("请先点击“调试模式”复选框，取消调试模式，才可以开始工作"), QMessageBox::Ok);
								return;
							}
							start_work();
						}
						else if (!g_working)
						{
							pause_work();
						}
						m_PLCDevice->g_plc_status|=(0x01);
					}
					//自动换班
					if (g_sys_conf.auto_shift&&g_working)
					{
						g_seconds++;
						if (g_seconds % 10 == 0)
						{
							if (cur_quantity == g_lst_quantiy)
							{
								quantity_stop_count++;
							}
							else {
								quantity_stop_count = 0;
							}
							if (quantity_stop_count == STOP_SECONDS)	//触发一次换班
							{
								g_op_mode = true;	//激活操作员模式
								on_btn_pause_released();	//停止工作
								on_pushButton_clear_released();	//换班
								on_btn_start_released();	//开始
								g_op_mode = false;	//退出操作员模式
							}
							g_lst_quantiy = cur_quantity;
						}
					}
					else if (g_sys_conf.timing_shift && g_working)
					{
						qint64 secA = time.secsTo(g_sys_conf.shiftA);
						qint64 secB = time.secsTo(g_sys_conf.shiftB);
						qint64 secC = time.secsTo(g_sys_conf.shiftC);
						if (secA == 0)
						{
							g_op_mode = true;	//激活操作员模式
							on_btn_pause_released();	//停止工作
							record_output_statistic(cur_quantity, 0);
							on_pushButton_clear_released();	//换班
							on_btn_start_released();	//开始
							g_op_mode = false;	//退出操作员模式
						}
						else if (secB == 0)
						{
							g_op_mode = true;	//激活操作员模式
							on_btn_pause_released();	//停止工作
							record_output_statistic(cur_quantity, 1);
							on_pushButton_clear_released();	//换班
							on_btn_start_released();	//开始
							g_op_mode = false;	//退出操作员模式
						}
						else if (secC == 0)
						{
							g_op_mode = true;	//激活操作员模式
							on_btn_pause_released();	//停止工作
							record_output_statistic(cur_quantity, 2);
							on_pushButton_clear_released();	//换班
							on_btn_start_released();	//开始
							g_op_mode = false;	//退出操作员模式
						}
					}
				}
				else
				{
					ui.label_plc->setText(QStringLiteral("PLC断开"));
					ui.label_plc->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
					m_PLCDevice->g_plc_status&=~(0x01);
				}
			}
		}
	}
	//剔除次数
	if (m_PLCDevice->g_plc_ok)
	{
		if (!g_plc_dialog_open)	//PLC配置对话框没有打开
		{
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
			if (g_modbus_conf.kick1 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc( g_modbus_conf.kick1, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_1->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 0;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
			if (g_modbus_conf.kick2 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc( g_modbus_conf.kick2, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_2->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 1;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
			if (g_modbus_conf.kick3 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick3, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_3->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 2;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
			if (g_modbus_conf.kick4 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick4, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_4->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 3;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
			if (g_modbus_conf.kick5 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick5, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_5->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 4;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
			if (g_modbus_conf.kick6 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick6, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_6->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 5;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
			if (g_modbus_conf.kick7 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick7, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_7->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 6;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
			if (g_modbus_conf.kick8 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick8, 2, dest16);
				if (ret == 2)
				{
					ui.lcdNumber_kick_8->display(dest16[0] + (dest16[1] << 16));
#ifdef __UDPSend
					_UDPSendInfo UDPSendInfo;
					UDPSendInfo.FrameID = kick_frame;
					UDPSendInfo.index = 7;
					UDPSendInfo.Kick[UDPSendInfo.index] = dest16[0] + (dest16[1] << 16);
					UDP_Info_queue->put(UDPSendInfo);
#endif
				}
			}
#endif
		}
	}
	//相机掉线检测
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
	if (SingleCamInfo[0].OffLine)	//1#相机掉线
	{
		//SingleCamInfo[0] = false;
		ui.cam_status_1->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_1->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_1->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam1_no.png);"));
		ui.label_reslut_1->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = {5,0};
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[0].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
	if (SingleCamInfo[1].OffLine)	//2#相机掉线
	{
		//SingleCamInfo[1] = false;
		ui.cam_status_2->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_2->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_2->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam2_no.png);"));
		ui.label_reslut_2->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = {6,0};
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if(ret > 0) SingleCamInfo[1].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
	if (SingleCamInfo[2].OffLine)	//3#相机掉线
	{
		//SingleCamInfo[2] = false;
		ui.cam_status_3->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_3->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_3->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam3_no.png);"));
		ui.label_reslut_3->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = { 7,0 };
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[2].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
	if (SingleCamInfo[3].OffLine)	//4#相机掉线
	{
		//SingleCamInfo[3] = false;
		ui.cam_status_4->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_4->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_4->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam4_no.png);"));
		ui.label_reslut_4->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = { 8,0 };
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[3].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
	if (SingleCamInfo[4].OffLine)	//5#相机掉线
	{
		//SingleCamInfo[4] = false;
		ui.cam_status_5->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_5->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_5->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam5_no.png);"));
		ui.label_reslut_5->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = { 9,0 };
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[4].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
	if (SingleCamInfo[5].OffLine)	//6#相机掉线
	{
		//SingleCamInfo[5] = false;
		ui.cam_status_6->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_6->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_6->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam6_no.png);"));
		ui.label_reslut_6->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = { 10,0 };
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[5].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
	if (SingleCamInfo[6].OffLine)	//7#相机掉线
	{
		//SingleCamInfo[6] = false;
		ui.cam_status_7->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_7->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_7->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam7_no.png);"));
		ui.label_reslut_7->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = { 11,0 };
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[6].OffLine = false;
		}
	}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
	if (SingleCamInfo[7].OffLine)	//8#相机掉线
	{
		//SingleCamInfo[7] = false;
		ui.cam_status_8->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.cam_work_8->setStyleSheet(tr("background-color: rgb(255, 255, 0);"));
		ui.toolButton_cam_8->setStyleSheet(tr("border-image: url(:/Cigarette/Resources/cam8_no.png);"));
		ui.label_reslut_8->setVisible(true);
		if (g_modbus_conf.alarm > 0)
		{
			uint16_t dest16[2] = { 12,0 };
			int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
			if (ret > 0) SingleCamInfo[7].OffLine = false;
		}
	}
#endif

	//读取报警信息
	if (m_PLCDevice->g_plc_ok)
	{
		if (!g_plc_dialog_open)	//PLC配置对话框没有打开
		{
			if (g_modbus_conf.alarm > 0) 
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc( g_modbus_conf.alarm, 2, dest16);
				if (ret>0)
				{
					AlarmInfo alarm_info;
					alarm_info.alarm_code = dest16[0];
					if ((alarm_info.alarm_code > 0) && (alarm_info.alarm_code <= 12))
					{
						alarm_info.alarm_msg = (g_alarm_msg[alarm_info.alarm_code]).toStdString();
						alarm_info.alarm_start = localTime.toStdString();
						ui.label_alarm->setText(g_alarm_msg[alarm_info.alarm_code]);
						ui.label_alarm->setStyleSheet(tr("background-color: rgb(255, 0, 0);"));
						if (g_last_alarm_code != alarm_info.alarm_code)
						{
							g_vec_alarm.push_back(alarm_info);
							g_last_alarm_code = alarm_info.alarm_code;
						}
						else {
							if (g_vec_alarm.empty()) {
								g_vec_alarm.push_back(alarm_info);
								g_last_alarm_code = alarm_info.alarm_code;
							}
						}
					}
					else if (alarm_info.alarm_code == 0) {
						ui.label_alarm->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
						ui.label_alarm->setText(QStringLiteral("无报警"));
					}
					//if (alarm_info.alarm_code == 7) {
					//	ui.label_alarm->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
					//	ui.label_alarm->setText(QStringLiteral("重连1#相机"));
					//	//重连1#相机
					//	ReconnectCamHub(0);
					//	//清除报警标志
					//	if (g_modbus_conf.alarm > 0)
					//	{
					//		uint16_t dest16[2] = {0,0};
					//		int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
					//	}
					//}
					//if (alarm_info.alarm_code == 8) {
					//	ui.label_alarm->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
					//	ui.label_alarm->setText(QStringLiteral("重连2#相机"));
					//	//重连2#相机
					//	ReconnectCamHub(1);
					//	//清除报警标志
					//	if (g_modbus_conf.alarm > 0)
					//	{
					//		uint16_t dest16[2] = {0,0};
					//		int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
					//	}
					//}
#ifdef __UDPSend
					QString str;
					str = QString("alarm") + '_' + QString::number(alarm_info.alarm_code);
					sThread.sendData(str, g_sys_conf.FeedbackPort);
#endif
				}
			}
		}
	}
}
void Cigarette::on_pushButton_reset_released()///复位按钮
{
	int ret = m_PLCDevice->write_bit_2_plc(g_modbus_conf.reset, 1);
	//Sleep(1000);
	if (g_modbus_conf.reset > 0)
		int ret = m_PLCDevice->write_bit_2_plc(g_modbus_conf.reset, 0);
}
void Cigarette::OnCancelAlarm()	//双击消警
{
	emit sengMsgToClog("Cancel alarm mode.");
	if (!g_admin_mode)
	{
		if (!g_op_mode)
		{
			dialogin = new Dialogin(this);
			connect(dialogin, SIGNAL(enter_op()), this, SLOT(OnOp()));
			dialogin->setModal(true);
			dialogin->show();
			dialogin->move((this->width() - dialogin->width()) / 2, (this->height() - dialogin->height()) / 2);
			return;
		}
	}
	if (g_modbus_conf.alarm > 0)
	{
		uint16_t dest16[2] = {0,0};
		int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
		if (ret > 0)
		{
			ui.label_alarm->setStyleSheet(tr("background-color: rgb(0, 170, 0);"));
			ui.label_alarm->setText(QStringLiteral("无报警"));
			QDateTime ts_start = QDateTime::currentDateTime();
			QDateTime local(ts_start);
			QString localTime = local.toString("yyyy-MM-dd hh:mm:ss");
			int n = g_vec_alarm.size();
			if (n>0)
			{
				g_vec_alarm[n - 1].alarm_handle = localTime.toStdString();
			}
#ifdef __UDPSend
			QString str;
			str = QString("alarm") + '_' + QString::number(0);
			sThread.sendData(str, g_sys_conf.FeedbackPort);
#endif
		}
	}
	g_op_time = OP_TIME;
}
void Cigarette::on_toolButton_alarm_released()
{
	emit sengMsgToClog("Open alarm dialog.");
	if (!g_admin_mode)
	{
		if (!g_op_mode)
		{
			emit sengMsgToClog("Start to login in.");
			dialogin = new Dialogin(this);
			connect(dialogin, SIGNAL(enter_op()), this, SLOT(OnOp()));
			dialogin->setModal(true);
			dialogin->show();
			dialogin->move((this->width() - dialogin->width()) / 2, (this->height() - dialogin->height()) / 2);
			return;
		}
	}
	AlarmDialog *alarm_dialog = new AlarmDialog(this);
	alarm_dialog->setModal(true);
	alarm_dialog->show();
	alarm_dialog->move((this->width() - alarm_dialog->width()) / 2, (this->height() - alarm_dialog->height()) / 2);
	g_op_time = OP_TIME;
}
void Cigarette::on_pushButton_clear_released()//换班
{
	emit sengMsgToClog("Change shift.");
	if (!g_admin_mode)
	{
		if (!g_op_mode)
		{
			dialogin = new Dialogin(this);
			connect(dialogin, SIGNAL(enter_op()), this, SLOT(OnOp()));
			dialogin->setModal(true);
			dialogin->show();
			dialogin->move((this->width() - dialogin->width()) / 2, (this->height() - dialogin->height()) / 2);
			return;
		}
	}
	if(g_working)
	{
		QMessageBox::information(NULL, QStringLiteral("状态检查"), QStringLiteral("请先点击“停止工作”按钮，才可以进行换班操作 "), QMessageBox::Ok);
		return;
	}
	ui.pushButton_clear->setEnabled(false);
	m_delay->setSingleShot(true);
	m_delay->start(5000);
	Sleep(500);
	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		production_number[i]=0;
		lcdNumber_total_mat[i]->display(production_number[i]);
		ok[i] = 0;
		lcdNumber_ok_mat[i]->display(ok[i]);
		ng[i] = 0;
		lcdNumber_ng_mat[i]->display(ng[i]);

		_UDPSendInfo UDPSendInfo;
		UDPSendInfo.index = i;

		UDPSendInfo.FrameID = ok_frame;
		UDPSendInfo.ok[i] = ok[i];
#ifdef __UDPSend
		UDP_Info_queue->put(UDPSendInfo);
#endif
		UDPSendInfo.FrameID = ng_frame;
		UDPSendInfo.ng[i] = ng[i];
#ifdef __UDPSend
		UDP_Info_queue->put(UDPSendInfo);
#endif
		UDPSendInfo.FrameID = info_frame;
		UDPSendInfo.timecost = QString::number(0);
		UDPSendInfo.JD = QString("0,0,0");
#ifdef __UDPSend
		UDP_Info_queue->put(UDPSendInfo);
#endif
		UDPSendInfo.FrameID = total_frame;
		UDPSendInfo.Total = 0;
#ifdef __UDPSend
		UDP_Info_queue->put(UDPSendInfo);
#endif
	}
	ui.lcdNumber_total_no->display(0);
#ifdef __UDPSend
	sThread.sendData("total_" + QString::number(0), g_sys_conf.FeedbackPort);
#endif
	//通过PLC读取当班产量，显示在上班产量中
	if (m_PLCDevice->g_plc_ok)
	{
		if (!g_plc_dialog_open)	//PLC配置对话框没有打开
		{
			if (g_modbus_conf.quantity > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc( g_modbus_conf.quantity, 2, dest16);
				//std::cout << ret << std::endl;
				if (ret > 0)
				{
					int cur_quantity = dest16[0] + (dest16[1] << 16);
					ui.lcdNumber_total_no_last->display(cur_quantity);
#ifdef __UDPSend
					sThread.sendData("totallast_" + QString::number(cur_quantity), g_sys_conf.FeedbackPort);
#endif
				}
			}
			//发送换班消息给PLC
			if (g_modbus_conf.shift > 0)
			{
				int ret = m_PLCDevice->write_bit_2_plc( g_modbus_conf.shift, 1);
				if (g_modbus_conf.alarm >0)///给报警地址（alarm对应的PLC地址）清零
				{
					uint16_t dest16[2] = { 0,0 };
					int ret = m_PLCDevice->write_short_2_plc(g_modbus_conf.alarm, 2, dest16);
				}
			}
		}
	}
	g_op_time = OP_TIME;
}

//读取系统管理员密码
QString Cigarette::read_pswd()
{
	std::fstream cfg_file;
	cfg_file.open("D:/Release/pswd.txt");
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file pswd.txt"<< std::endl;
		return "81dc9bdb52d04dc20036dbd8313ed055";
	}
	if (!cfg_file.eof())
	{
		char tmp[256];
		memset(tmp, 0, 256);
		cfg_file.getline(tmp, 256);
		QString pswd = QString(QLatin1String(tmp));
		if (pswd.length() > 0)
		{
			return pswd;
		}
		else
		{
			return "81dc9bdb52d04dc20036dbd8313ed055";
		}
	}
	else
	{
		return "81dc9bdb52d04dc20036dbd8313ed055";
	}
	cfg_file.close();
}

//读取系统操作员密码
QString Cigarette::read_op_pswd()
{
	std::fstream cfg_file;
	cfg_file.open("D:/Release/pswd_op.txt");
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file pswd_op.txt" << std::endl;
		return "81dc9bdb52d04dc20036dbd8313ed055";
	}
	if (!cfg_file.eof())
	{
		char tmp[256];
		memset(tmp, 0, 256);
		cfg_file.getline(tmp, 256);
		QString pswd = QString(QLatin1String(tmp));
		if (pswd.length() > 0)
		{
			return pswd;
		}
		else
		{
			return "81dc9bdb52d04dc20036dbd8313ed055";
		}
	}
	else
	{
		return "81dc9bdb52d04dc20036dbd8313ed055";
	}
	cfg_file.close();
}

bool Cigarette::read_sys_config(SysConf &conf)
{
	std::fstream cfg_file;
	cfg_file.open(CONFIGURE_FILE);
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file " << CONFIGURE_FILE << std::endl;
		return false;
	}
	while (!cfg_file.eof())
	{
		char tmp[256] = "";
		cfg_file.getline(tmp, 256);
		std::string line(tmp);
		if (line.length() > 0)
		{
			/// atoi返回整数值；substr返回子串；c_str()指向字符串首地址
			size_t pos = line.find('=');
			std::string tmp_key = line.substr(0, pos);
			
			if (tmp_key == "SAVE")	
			{	/// 存图设置：0不保存；1保存NG；2全存
				conf.save = atoi(line.substr(pos + 1).c_str());	
			}
			else if (tmp_key == "MISMATCHACT")
			{	/// 错位行为：1NG；0OK
				conf.MisMatchAct = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "SAVE_DAYS")
			{	/// 照片保存天数
				conf.save_days = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "FREESIZE") 
			{
				/// 清理图片设定最小空间值
				conf.freesize = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "ComPort")
			{	/// COM口
				conf.ComPort = line.substr(pos + 1);
			}
			else if (tmp_key == "CONFTHRESHOLD")
			{	///相似度
				conf.ConfThreshold = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "AUTO_OPEN")
			{	/// 是否自动打开相机：0否；1是
				conf.auto_open = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "AUTO_WORK")
			{	/// 是否自动开始工作：0否；1是
				conf.auto_work = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "AUTO_SHIFT")
			{	/// 是否自动换班：0否；1是
				conf.auto_shift = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "TIMING_SHIFT")
			{	/// 是否定时换班：0否；1是
				conf.timing_shift = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "SHIFT_A")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 2)
				{
					conf.shiftA.setHMS(atoi(vec_info[0].c_str())%24, atoi(vec_info[1].c_str()), 0);///
				}
			}
			else if (tmp_key == "SHIFT_B")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 2)
				{
					conf.shiftB.setHMS(atoi(vec_info[0].c_str())%24, atoi(vec_info[1].c_str()), 0);///
				}
			}
			else if (tmp_key == "SHIFT_C")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 2)
				{
					conf.shiftC.setHMS(atoi(vec_info[0].c_str())%24, atoi(vec_info[1].c_str()), 0);///
				}
			}
			else if (tmp_key == "LOCATION")
			{	
				conf.location = line.substr(pos + 1).c_str();
			}
			else if (tmp_key == "MODELPATH")
			{
				conf.model_path = line.substr(pos + 1).c_str();
			}
			else if (tmp_key == "MODELNAME")
			{
				conf.model_name = line.substr(pos + 1).c_str();
			}
			else if (tmp_key == "JPGPATH")
			{
				conf.jpg_path = line.substr(pos + 1).c_str();
			}
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
			else if (tmp_key == "EXPO1")
			{
				conf.expo[0] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "GAIN1")
			{
				conf.gain[0] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "FILTER1")
			{
				conf.filter[0] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "USERID1")
			{
				conf.UserID[0] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "NO1")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[0][0] = atoi(vec_info[0].c_str());
					conf.no[0][1] = atoi(vec_info[1].c_str());
					conf.no[0][2] = atoi(vec_info[2].c_str());
				}
			}
			else if (tmp_key == "SHOOT1")
			{
				conf.shoot[0] = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
			else if (tmp_key == "EXPO2")
			{
				conf.expo[1] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "GAIN2")
			{
				conf.gain[1] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "FILTER2")
			{
				conf.filter[1] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "USERID2")
			{
				conf.UserID[1] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "NO2")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[1][0] = atoi(vec_info[0].c_str());
					conf.no[1][1] = atoi(vec_info[1].c_str());
					conf.no[1][2] = atoi(vec_info[2].c_str());
				}
			}
			else if (tmp_key == "SHOOT2")
			{
				conf.shoot[1] = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
			else if (tmp_key == "EXPO3")
			{
				conf.expo[2] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "GAIN3")
			{
				conf.gain[2] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "FILTER3")
			{
				conf.filter[2] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "USERID3")
			{
				conf.UserID[2] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "NO3")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[2][0] = atoi(vec_info[0].c_str());
					conf.no[2][1] = atoi(vec_info[1].c_str());
					conf.no[2][2] = atoi(vec_info[2].c_str());
				}
			}
			else if (tmp_key == "SHOOT3")
			{
				conf.shoot[2] = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
			else if (tmp_key == "EXPO4")
			{
				conf.expo[3] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "GAIN4")
			{
				conf.gain[3] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "FILTER4")
			{
				conf.filter[3] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "USERID4")
			{
				conf.UserID[3] = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "NO4")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|",vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[3][0] = atoi(vec_info[0].c_str());
					conf.no[3][1] = atoi(vec_info[1].c_str());
					conf.no[3][2] = atoi(vec_info[2].c_str());
				}
			}
			else if (tmp_key == "SHOOT4")
			{
				conf.shoot[3] = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
			else if (tmp_key == "EXPO5")
			{
				conf.expo[4] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "GAIN5")
			{
				conf.gain[4] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "FILTER5")
			{
				conf.filter[4] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "USERID5")
			{
				conf.UserID[4] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "NO5")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|", vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[4][0] = atoi(vec_info[0].c_str());
					conf.no[4][1] = atoi(vec_info[1].c_str());
					conf.no[4][2] = atoi(vec_info[2].c_str());
				}
				}
			else if (tmp_key == "SHOOT5")
			{
				conf.shoot[4] = atoi(line.substr(pos + 1).c_str());
				}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
			else if (tmp_key == "EXPO6")
			{
				conf.expo[5] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "GAIN6")
			{
				conf.gain[5] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "FILTER6")
			{
				conf.filter[5] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "USERID6")
			{
				conf.UserID[5] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "NO6")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|", vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[5][0] = atoi(vec_info[0].c_str());
					conf.no[5][1] = atoi(vec_info[1].c_str());
					conf.no[5][2] = atoi(vec_info[2].c_str());
				}
				}
			else if (tmp_key == "SHOOT6")
			{
				conf.shoot[5] = atoi(line.substr(pos + 1).c_str());
				}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
			else if (tmp_key == "EXPO7")
			{
				conf.expo[6] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "GAIN7")
			{
				conf.gain[6] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "FILTER7")
			{
				conf.filter[6] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "USERID7")
			{
				conf.UserID[6] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "NO7")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|", vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[6][0] = atoi(vec_info[0].c_str());
					conf.no[6][1] = atoi(vec_info[1].c_str());
					conf.no[6][2] = atoi(vec_info[2].c_str());
				}
				}
			else if (tmp_key == "SHOOT7")
			{
				conf.shoot[6] = atoi(line.substr(pos + 1).c_str());
				}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
			else if (tmp_key == "EXPO8")
			{
				conf.expo[7] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "GAIN8")
			{
				conf.gain[7] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "FILTER8")
			{
				conf.filter[7] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "USERID8")
			{
				conf.UserID[7] = atoi(line.substr(pos + 1).c_str());
				}
			else if (tmp_key == "NO8")
			{
				std::vector<std::string> vec_info;
				string_split(line.substr(pos + 1), "|", vec_info);
				if (vec_info.size() == 3)
				{
					conf.no[7][0] = atoi(vec_info[0].c_str());
					conf.no[7][1] = atoi(vec_info[1].c_str());
					conf.no[7][2] = atoi(vec_info[2].c_str());
				}
				}
			else if (tmp_key == "SHOOT8")
			{
				conf.shoot[7] = atoi(line.substr(pos + 1).c_str());
				}
#endif
			else if (tmp_key == "MonitorIP")
			{
			conf.MonitorIP = line.substr(pos + 1);
			}
			else if (tmp_key == "MonitorPort")
			{
			conf.MonitorPort = atoi(line.substr(pos + 1).c_str());
			conf.FeedbackPort = conf.MonitorPort + NumberOfSupportedCameras*2;
			conf.FilePort = conf.MonitorPort + NumberOfSupportedCameras*2+2;
			}
		}
	}

	cfg_file.close();
	ui.location->setText(g_sys_conf.location);
	return true;
}

bool Cigarette::read_modbus_config(ModbusConf &conf)
{
	std::fstream cfg_file;
	cfg_file.open(MODBUS_CONFIGURE_FILE);
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file " << MODBUS_CONFIGURE_FILE << std::endl;
		return false;
	}
	while (!cfg_file.eof())
	{
		char tmp[256] = "";
		cfg_file.getline(tmp, 256);
		std::string line(tmp);
		if (line.length() > 0)
		{
			size_t pos = line.find('=');
			std::string tmp_key = line.substr(0, pos);
			if (tmp_key == "QUANTITY")
			{
				conf.quantity = atoi(line.substr(pos + 1).c_str());
			}
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
			else if (tmp_key == "KICK1")
			{
				conf.kick1 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
			else if (tmp_key == "KICK2")
			{
				conf.kick2 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
			else if (tmp_key == "KICK3")
			{
				conf.kick3 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
			else if (tmp_key == "KICK4")
			{
				conf.kick4 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
			else if (tmp_key == "KICK5")
			{
				conf.kick5 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
			else if (tmp_key == "KICK6")
			{
				conf.kick6 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
			else if (tmp_key == "KICK7")
			{
				conf.kick7 = atoi(line.substr(pos + 1).c_str());
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
			else if (tmp_key == "KICK8")
			{
				conf.kick8 = atoi(line.substr(pos + 1).c_str());
			}
#endif
			else if (tmp_key == "QUANTITY")
			{
				conf.quantity = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "SHIFT")
			{
				conf.shift = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "WORK")
			{
				conf.work = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "NO_KICK")
			{
				conf.no_kick = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "DEBUG")
			{
				conf.debug = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "RESET")
			{
				conf.reset = atoi(line.substr(pos + 1).c_str());
			}
			else if (tmp_key == "ALARM")
			{
				conf.alarm = atoi(line.substr(pos + 1).c_str());
			}
		}
	}
	cfg_file.close();
	return true;
}

//读取相机图像旋转参数
bool Cigarette::read_rotate_message()
{
	std::fstream cfg_file;
	cfg_file.open(ROTATE_FILE);
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file rotate.txt" << std::endl;
		return false;
	}
	if (!cfg_file.eof())
	{
		char tmp[256];
		memset(tmp, 0, 256);
		cfg_file.getline(tmp, 256);
		QStringList rotate_message = QString(QLatin1String(tmp)).split(",");
		if (rotate_message.length() > NumberOfSupportedCameras*2)
		{
			for (int i = 0; i < NumberOfSupportedCameras; i++) {
				isNeedRotate[i] = rotate_message[i * 2].toInt();
				rotationAngle[i] = rotate_message[i * 2 + 1].toInt();
			}
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}
	cfg_file.close();
	return true;
}

//保存相机图像旋转参数
bool Cigarette::save_rotate_message()
{
	std::fstream cfg_file;
	cfg_file.open(ROTATE_FILE, ios::trunc | ofstream::out);
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file rotate.txt" << std::endl;
		return false;
	}
	for (int i = 0; i < NumberOfSupportedCameras; i++) {
		char tmp[8];
		memset(tmp, 0, 8);
		itoa(isNeedRotate[i], tmp, 10);
		cfg_file.write(tmp, 1);
		cfg_file.write(",", 1);
		memset(tmp, 0, 8);
		itoa(rotationAngle[i], tmp, 10);
		cfg_file.write(tmp, 1);
		cfg_file.write(",", 1);
	}
	cfg_file.close();
	return true;
}

//保存报警信息
bool Cigarette::save_alarm_message(std::vector<AlarmInfo> &AlarmInfo_vect)
{
	std::fstream cfg_file;
	cfg_file.open(ALARM_RECORD_FILE);
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open config file alarm.txt" << std::endl;
		return false;
	}

	for (int i = 0; i < AlarmInfo_vect.size(); i++) {
		char buf[256];
		memset(buf, 0, 256);
		sprintf(buf, "%s_%s_%s_%d\n", AlarmInfo_vect[i].alarm_start, AlarmInfo_vect[i].alarm_handle, AlarmInfo_vect[i].alarm_msg, AlarmInfo_vect[i].alarm_code);
		cfg_file.write(buf, strlen(buf));
	}
	cfg_file.close();
	return true;
}

QImage Cigarette::cvMatToQImage(const cv::Mat& mat)
{
	const unsigned char* data = mat.data;
	int width = mat.cols;
	int height = mat.rows;
	int bytesPerLine = static_cast<int>(mat.step);
	switch (mat.type())
	{
		// 8bit, ARGB
	case CV_8UC4:
	{
		QImage image(data, width, height, bytesPerLine,
			QImage::Format_ARGB32);
		return image;
	}
	// 8bit, BGR
	case CV_8UC3:
	{
		QImage image(data, width, height, bytesPerLine,
			QImage::Format_RGB888);
		//swap blue and red channel
		return image.rgbSwapped();
	}
	// 8bit, Grayshale
	case CV_8UC1:
	{
		QImage image(data, width, height, bytesPerLine,
			QImage::Format_Grayscale8);
		return image;
	}
	default:
	{
		return QImage();
	}
	}
}

void Cigarette::read_plc_items()
{
	std::fstream cfg_file;
	cfg_file.open(PLC_CONFIG_FILE);
	if (!cfg_file.is_open())
	{
		std::cout << "Error: Open production file " << PLC_CONFIG_FILE << std::endl;
		return;
	}
	while (!cfg_file.eof())
	{
		char tmp[1024] = "";
		cfg_file.getline(tmp, 1024);
		std::string line(tmp);
		//std::cout << line << std::endl;
		if (line.length() > 0)
		{
			std::vector<std::string> vec_info;
			string_split(line, "|",vec_info);
			if (vec_info.size() == 4)
			{
				PlcItem plc_item;
				plc_item.func_desc = vec_info[0];
				plc_item.address = atoi(vec_info[1].c_str());
				plc_item.value = atoi(vec_info[2].c_str());
				plc_item.memo = vec_info[3];
				m_plc_items.push_back(plc_item);
			}
		}
	}
	cfg_file.close();
}

void Cigarette::init_plc_value()
{
	for (int i = 0; i < m_plc_items.size(); i++)
	{
		int addr = m_plc_items[i].address;
		int data = m_plc_items[i].value;
		if (addr > 0)
		{
			uint8_t dest[4];
			uint16_t * dest16 = (uint16_t *)dest;
			memset(dest, 0, 4);
			if (addr > 0)
			{
				if (addr < 40000)	//写入线圈值 bit
				{
					if (data != 0)	data = 1;
					m_PLCDevice->write_bit_2_plc( addr, data);
				}
				else {				//写入DWORD值，4字节
					dest16[0] = (data & 0xffff);
					dest16[1] = (data >> 16);
					m_PLCDevice->write_short_2_plc(addr, 2, dest16);
				}
			}
		}
	}
}

void Cigarette::CreatWorkThread(int classid,int Num,Cigarette* classptr)
{
	work_thread[Num].init(g_image_queue[Num],g_result_queue[Num],classid,Num);
	connect(&work_thread[Num], SIGNAL(notify(int,int,cv::Mat)), classptr, SLOT(OnNotifyHub(int,int,cv::Mat)));
	connect(&work_thread[Num], SIGNAL(display_timecost(int,int)), classptr, SLOT(OnDisplayTimeCostHub(int,int)));
	connect(&work_thread[Num], SIGNAL(display_check_total(int,long)), classptr, SLOT(OnDisplayCheckNumberHub(int,long)));
	connect(&work_thread[Num], SIGNAL(display_jd_no(int,QString)), classptr, SLOT(OnDisplayJdNoHub(int,QString)));
	connect(&work_thread[Num], SIGNAL(event_ok(int)), classptr, SLOT(OnOKHub(int)));
	connect(&work_thread[Num], SIGNAL(event_ng(int)), classptr, SLOT(OnNGHub(int)));
	work_thread[Num].start_work();
	debug_thread[Num].init(g_debug_queue[Num],Num);
	connect(&debug_thread[Num], SIGNAL(notify(int,int,cv::Mat)), classptr, SLOT(OnNotifyHub(int,int,cv::Mat)));
	debug_thread[Num].start_work();
}

#define InitPtrMat_init(a,b)\
cam_status_mat[a]=ui.cam_status_##b;\
cam_work_mat[a]=ui.cam_work_##b;\
cam_toolButton_mat[a]=ui.toolButton_cam_##b;\
label_cap_speed_mat[a]=ui.label_cap_speed_##b;\
display_lable_mat[a][0]=ui.image_label_##b##1;\
display_lable_mat[a][1]=ui.image_label_##b##2;\
label_timecost_mat[a]=ui.label_timecost_##b;\
lcdNumber_total_mat[a]=ui.lcdNumber_total_##b;\
label_jd_no_mat[a]=ui.label_jd_no_##b;\
lcdNumber_ok_mat[a]=ui.lcdNumber_ok_##b;\
lcdNumber_ng_mat[a]=ui.lcdNumber_ng_##b;\
label_reslut_mat[a]=ui.label_reslut_##b;\
rotate_mat[a]=ui.rotate_##b;\
label_ng_mat[a]=ui.label_ng_##b;
void Cigarette::InitPtrMat()
{
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
	InitPtrMat_init(0,1)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
	InitPtrMat_init(1,2)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
	InitPtrMat_init(2,3)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
	InitPtrMat_init(3,4)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
	InitPtrMat_init(4,5)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
	InitPtrMat_init(5,6)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
	InitPtrMat_init(6,7)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
	InitPtrMat_init(7,8)
#endif
	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		for(int j=0;j<2;j++)
		{
			display_lable_info[i][j].x = display_lable_mat[i][j]->geometry().x();
			display_lable_info[i][j].y = display_lable_mat[i][j]->geometry().y();
			display_lable_info[i][j].width = display_lable_mat[i][j]->geometry().width();
			display_lable_info[i][j].height = display_lable_mat[i][j]->geometry().height();
		}
		rotate_info[i].x = rotate_mat[i]->geometry().x();
		rotate_info[i].y = rotate_mat[i]->geometry().y();
		rotate_info[i].width = rotate_mat[i]->geometry().width();
		rotate_info[i].height = rotate_mat[i]->geometry().height();
	}
	
}

bool Cigarette::ControlCamOpenOrClose(int Num,bool OpenOrClose)
{
	if(OpenOrClose == OPEN && !SingleCamInfo[Num].IsOpen)
	{
		if (SingleCamInfo[Num].CamClass == BalluffClassID)
		{
			qDebug() << "open for balluff";
			try
			{
				Device* pDev = BalluffCamera::devMgr[SingleCamInfo[Num].unfiltered_num];
				conditionalSetProperty(pDev->interfaceLayout, dilGenICam);
				pDev->open();
				// Configure timer1
				mvIMPACT::acquire::GenICam::CounterAndTimerControl mvCATC(pDev);
				mvCATC.timerSelector.writeS("Timer1");
				mvCATC.timerTriggerSource.writeS("UserOutput0");
				mvCATC.timerDuration.write(StrobeLineTime);
				mvCATC.timerTriggerActivation.writeS("AnyEdge");
				// Configure timer2
				mvCATC.timerSelector.writeS("Timer2");
				mvCATC.timerTriggerSource.writeS("UserOutput1");
				mvCATC.timerDuration.write(StrobeLineTime);
				mvCATC.timerTriggerActivation.writeS("AnyEdge");

				//Configure output1
				mvIMPACT::acquire::GenICam::DigitalIOControl mvDIOC(pDev);
				mvDIOC.lineSelector.writeS("Line0");
				mvDIOC.lineSource.writeS("Timer1Active");
				//Configure output2
				mvDIOC.lineSelector.writeS("Line1");
				mvDIOC.lineSource.writeS("Timer2Active");

				//设置滤波
				mvDIOC.lineSelector.writeS("Line4");
				mvDIOC.mvLineDebounceTimeRisingEdge.write(g_sys_conf.filter[Num]);
				//设置滤波
				mvDIOC.lineSelector.writeS("Line5");
				mvDIOC.mvLineDebounceTimeRisingEdge.write(g_sys_conf.filter[Num]);
				//设置binning
				mvIMPACT::acquire::GenICam::ImageFormatControl ifc = mvIMPACT::acquire::GenICam::ImageFormatControl(pDev);
				ifc.binningHorizontalMode.writeS("Sum");
				ifc.binningHorizontal.write(2);
				ifc.binningVerticalMode.writeS("Sum");
				ifc.binningVertical.write(2);

				pFI[Num] = new FunctionInterface(pDev);
				if (pDev->interfaceLayout.isValid() && (pDev->interfaceLayout.read() == dilGenICam))
				{
					pAC[Num] = new mvIMPACT::acquire::GenICam::AcquisitionControl(pDev);
					//设置外触发
					pAC[Num]->triggerMode.writeS("On");
					pAC[Num]->triggerSource.writeS("Line4");
					pAC[Num]->triggerActivation.writeS("RisingEdge");
					//设置曝光时间
					pAC[Num]->exposureTime.writeS(QString::number(g_sys_conf.expo[Num]).toStdString());
					//设置增益
					mvIMPACT::acquire::GenICam::AnalogControl *pac = new mvIMPACT::acquire::GenICam::AnalogControl(pDev);
					pac->gain.write(g_sys_conf.gain[Num]);
				}
				pCaptureThread[Num] = new CaptureThread(BalluffCamera::devMgr[SingleCamInfo[Num].unfiltered_num], false, pFI[Num],Num);

				pCaptureThread[Num]->p_image_queue = g_image_queue[Num];
				pCaptureThread[Num]->p_result_queue = g_result_queue[Num];
				pCaptureThread[Num]->p_result_wait_queue = g_result_wait_queue[Num];
				pCaptureThread[Num]->p_double_queue = g_double_queue[Num];
				pCaptureThread[Num]->p_shooted_queue = g_shooted_queue[Num];
				pCaptureThread[Num]->p_debug_queue = g_debug_queue[Num];

				pThread[Num] = new QThread;
				pCaptureThread[Num]->moveToThread(pThread[Num]);

				// Signal emitted in case of acquisition errors
				connect(pThread[Num], SIGNAL(started()), pCaptureThread[Num], SLOT(process()));
				//connect(pCaptureThread[Num], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
				connect(pCaptureThread[Num], SIGNAL(finished()), pThread[Num], SLOT(quit()));
				connect(pCaptureThread[Num], SIGNAL(finished()), pCaptureThread[Num], SLOT(deleteLater()));
				if(!g_debug_mode)
					connect(pCaptureThread[Num], SIGNAL(updateStatistics(const QString&,int)), this, SLOT(updateStatisticsHub(const QString&,int)));

				pThread[Num]->start();
				if (pThread[Num]->isRunning())
				{
					qDebug() << "balluff pThread OK";
					SingleCamInfo[Num].IsOpen =true;
					return true;
				}
			}
			catch (const ImpactAcquireException& e)
			{
				QString msg;
				QTextStream(&msg) << "Error while opening device! Error message: " << QString::fromStdString(e.getErrorCodeAsString()) << "\nError Code: " << e.getErrorCode();
				QMessageBox::warning(this, "Error", msg, QMessageBox::Ok, QMessageBox::Ok);
			}
			return false;
		}
		else if (SingleCamInfo[Num].CamClass == BaslerClassID)
		{
			qDebug() << "open for basler";
			try
			{
				Pylon::CBaslerUniversalInstantCamera *baslerCamera = new Pylon::CBaslerUniversalInstantCamera(Pylon::CTlFactory::GetInstance().CreateDevice(BaslerCamera::devices[SingleCamInfo[Num].filtered_num]));
				BaslerCamHandle[Num]=baslerCamera;

				// Camera event processing must be activated first, the default is off.
				baslerCamera->GrabCameraEvents = true;

				baslerCamera->Open();
				baslerCamera->LineSelector.SetValue(Basler_UniversalCameraParams::LineSelector_Line1);
				if (!baslerCamera->LineDebouncerTime.TrySetValue(g_sys_conf.filter[Num]/1.0))
				{
					std::cout << "can not set LineDebouncerTime" << std::endl;
					if(!baslerCamera->BslInputFilterTime.TrySetValue(g_sys_conf.filter[Num]/1.0))
						std::cout << "can not set BslInputFilterTime" << std::endl;
				}
				baslerCamera->LineSelector.SetValue(Basler_UniversalCameraParams::LineSelector_Line3);
				baslerCamera->LineMode.SetValue(Basler_UniversalCameraParams::LineMode_Input);
				if (!baslerCamera->LineDebouncerTime.TrySetValue(g_sys_conf.filter[Num]/1.0))
				{
					std::cout << "can not set LineDebouncerTime" << std::endl;
					if (!baslerCamera->BslInputFilterTime.TrySetValue(g_sys_conf.filter[Num]/1.0))
						std::cout << "can not set BslInputFilterTime" << std::endl;
				}
				if (baslerCamera->LineSelector.TrySetValue(Basler_UniversalCameraParams::LineSelector_Line4))
				{
					baslerCamera->LineMode.SetValue(Basler_UniversalCameraParams::LineMode_Output);
#ifdef USB_BASLER_NEW_FW
					GENAPI_NAMESPACE::INodeMap& nodemap = baslerCamera->GetNodeMap();
					Pylon::CFloatParameter(nodemap, "UserOutputDuration").SetValue(StrobeLineTime);
#endif
					if (baslerCamera->LineSource.TrySetValue(Basler_UniversalCameraParams::LineSource_UserOutput3))
					{
						baslerCamera->UserOutputSelector.SetValue(Basler_UniversalCameraParams::UserOutputSelector_UserOutput3);
						baslerCamera->UserOutputValue.SetValue(false);
					}
					else
					{
						std::cout << "can not set LineSource_UserOutput3" << std::endl;
					}
				}
				else
				{
					std::cout << "can not set LineSelector_Line4" << std::endl;
				}
				
				baslerCamera->LineSelector.SetValue(Basler_UniversalCameraParams::LineSelector_Line2);
#ifdef USB_BASLER_NEW_FW
				GENAPI_NAMESPACE::INodeMap& nodemap = baslerCamera->GetNodeMap();
				Pylon::CFloatParameter(nodemap, "UserOutputDuration").SetValue(StrobeLineTime);
#endif
				if (baslerCamera->LineSource.TrySetValue(Basler_UniversalCameraParams::LineSource_UserOutput1))
				{
					baslerCamera->UserOutputSelector.SetValue(Basler_UniversalCameraParams::UserOutputSelector_UserOutput1);
					baslerCamera->UserOutputValue.SetValue(false);
				}
				else
				{
					std::cout << "can not set LineSource_UserOutput1" << std::endl;
				}

				baslerCamera->ExposureAuto.SetValue(Basler_UniversalCameraParams::ExposureAuto_Off);
				baslerCamera->ExposureMode.SetValue(Basler_UniversalCameraParams::ExposureMode_Timed);
				baslerCamera->ExposureTime.SetValue(g_sys_conf.expo[Num]);

				baslerCamera->GainSelector.SetValue(Basler_UniversalCameraParams::GainSelector_All);
				baslerCamera->GainAuto.SetValue(Basler_UniversalCameraParams::GainAuto_Off);
				baslerCamera->Gain.SetValue(g_sys_conf.gain[Num]);

				baslerCamera->TriggerSelector.SetValue(Basler_UniversalCameraParams::TriggerSelector_FrameStart);
				baslerCamera->TriggerMode.SetValue(Basler_UniversalCameraParams::TriggerMode_On);
				baslerCamera->TriggerSource.SetValue(Basler_UniversalCameraParams::TriggerSource_Line3);
				baslerCamera->TriggerActivation.SetValue(Basler_UniversalCameraParams::TriggerActivation_RisingEdge);

				baslerCamera->BinningHorizontal.SetValue(2);
				baslerCamera->BinningVertical.SetValue(2);
				
				pBaslerCaptureThread[Num] = new CaptureThreadBasler(baslerCamera, false, Num,g_sys_conf.shoot[Num]);

				pBaslerCaptureThread[Num]->p_image_queue = g_image_queue[Num];
				pBaslerCaptureThread[Num]->p_result_queue = g_result_queue[Num];
				pBaslerCaptureThread[Num]->p_result_wait_queue = g_result_wait_queue[Num];
				pBaslerCaptureThread[Num]->p_double_queue = g_double_queue[Num];
				pBaslerCaptureThread[Num]->p_shooted_queue = g_shooted_queue[Num];

				pBaslerCaptureThread[Num]->p_debug_queue = g_debug_queue[Num];

				pThread[Num] = new QThread;
				pBaslerCaptureThread[Num]->moveToThread(pThread[Num]);

				// Signal emitted in case of acquisition errors
				connect(pThread[Num], SIGNAL(started()), pBaslerCaptureThread[Num], SLOT(process()));
				//connect(pBaslerCaptureThread[Num], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
				connect(pBaslerCaptureThread[Num], SIGNAL(finished()), pThread[Num], SLOT(quit()));
				connect(pBaslerCaptureThread[Num], SIGNAL(finished()), pBaslerCaptureThread[Num], SLOT(deleteLater()));
				if(!g_debug_mode)
					connect(pBaslerCaptureThread[Num], SIGNAL(updateStatistics(const QString&, int)), this, SLOT(updateStatisticsHub(const QString&, int)));

				pThread[Num]->start();
				if (pThread[Num]->isRunning())
				{
					qDebug() << "basler pThread OK";
					SingleCamInfo[Num].IsOpen = true;
					return true;
				}
			}
			catch (const Pylon::GenericException& e)
			{
				QString msg;
				QTextStream(&msg) << "Error while opening device! Error message: " << QString::fromStdString(e.GetDescription()) << "\nError" ;
				QMessageBox::warning(this, "Error", msg, QMessageBox::Ok, QMessageBox::Ok);
			}
			return false;
		}
		else if (SingleCamInfo[Num].CamClass == HIKClassID)
		{
			qDebug() << "open for hik";
			int nRet = MV_OK;
			void *camhandle;
			nRet = MV_CC_CreateHandle(&camhandle, HIKCamera::stDeviceList.pDeviceInfo[SingleCamInfo[Num].unfiltered_num]);
			HIKCamHandle[Num]=camhandle;
			nRet = MV_CC_OpenDevice(camhandle);
			if (nRet)
			{
				MV_CC_CloseDevice(camhandle);
				if (MV_CC_OpenDevice(camhandle))
				{
					qDebug() << "Failed to open camera";
					return false;
				}
			}
			if (HIKCamera::stDeviceList.pDeviceInfo[SingleCamInfo[Num].unfiltered_num]->nTLayerType == MV_GIGE_DEVICE)
			{
				int nPacketSize = MV_CC_GetOptimalPacketSize(camhandle);
				if (nPacketSize > 0)
				{
					int nRet = MV_CC_SetIntValue(camhandle, "GevSCPSPacketSize", nPacketSize);
					if (nRet != MV_OK)
					{
						//printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
					}
				}
			}
			int nnRet = MV_OK;
			nRet = MV_CC_SetEnumValue(camhandle, "LineSelector", 1);	//0:Line0 1:Line1 2:Line2 
			if (nRet) { std::cout << "can not set LineSelector" << std::endl; nnRet = nRet;}

			nRet = MV_CC_SetEnumValue(camhandle, "LineMode", 8);	//0:Input 1:Output 2:Trigger 8:Strobe
			if (nRet) { std::cout << "can not set LineMode" << std::endl; nnRet = nRet; }

			//0:ExposureStartActive 5:SoftTriggerActive  6:HardTriggerActive
			nRet = MV_CC_SetEnumValue(camhandle, "LineSource", 5);
			if (nRet) { std::cout << "can not set LineSource" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetBoolValue(camhandle, "StrobeEnable",TRUE);
			if (nRet) { std::cout << "can not set StrobeEnable" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetIntValueEx(camhandle, "StrobeLineDuration", StrobeLineTime);
			if (nRet) { std::cout << "can not set StrobeLineDuration" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "LineSelector", 0);
			if (nRet) { std::cout << "can not set LineSelector" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetIntValueEx(camhandle, "LineDebouncerTime", g_sys_conf.filter[Num]);
			if (nRet) { std::cout << "can not set LineDebouncerTime" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "LineSelector", 2);
			if (nRet) { std::cout << "can not set LineSelector" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetIntValueEx(camhandle, "LineDebouncerTime", g_sys_conf.filter[Num]);
			if (nRet) { std::cout << "can not set LineDebouncerTime" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "TriggerMode", MV_TRIGGER_MODE_ON);
			if (nRet) { std::cout << "can not set TriggerMode" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "TriggerSource", MV_TRIGGER_SOURCE_LINE2);
			if (nRet) { std::cout << "can not set TriggerSource" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "TriggerActivation", 1);//1表示下降沿
			if (nRet) { std::cout << "can not set TriggerActivation" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "BinningHorizontal", 2);//设置binning
			if (nRet) { std::cout << "can not set BinningHorizontal" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "BinningVertical", 2);//设置binning
			if (nRet) { std::cout << "can not set BinningVertical" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "ExposureAuto", FALSE);
			if (nRet) { std::cout << "can not set ExposureAuto" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "ExposureMode", 0);//timed
			if (nRet) { std::cout << "can not set ExposureMode" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetFloatValue(camhandle, "ExposureTime", g_sys_conf.expo[Num]);
			if (nRet) { std::cout << "can not set ExposureTime" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetEnumValue(camhandle, "GainAuto", FALSE);
			if (nRet) { std::cout << "can not set GainAuto" << std::endl; nnRet = nRet; }

			nRet = MV_CC_SetFloatValue(camhandle, "Gain", g_sys_conf.gain[Num]);
			if (nRet) { std::cout << "can not set Gain" << std::endl; nnRet = nRet; }

			pHIKCaptureThread[Num] = new CaptureThreadHIK(camhandle, false,Num);

			pHIKCaptureThread[Num]->p_image_queue = g_image_queue[Num];
			pHIKCaptureThread[Num]->p_result_queue = g_result_queue[Num];
			pHIKCaptureThread[Num]->p_debug_queue = g_debug_queue[Num];
			pHIKCaptureThread[Num]->p_result_wait_queue = g_result_wait_queue[Num];
			pHIKCaptureThread[Num]->p_double_queue = g_double_queue[Num];
			pHIKCaptureThread[Num]->p_shooted_queue = g_shooted_queue[Num];

			pThread[Num] = new QThread;
			pHIKCaptureThread[Num]->moveToThread(pThread[Num]);

			// Signal emitted in case of acquisition errors
			connect(pThread[Num], SIGNAL(started()), pHIKCaptureThread[Num], SLOT(process()));
			//connect(pHIKCaptureThread[Num], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
			connect(pHIKCaptureThread[Num], SIGNAL(finished()), pThread[Num], SLOT(quit()));
			connect(pHIKCaptureThread[Num], SIGNAL(finished()), pHIKCaptureThread[Num], SLOT(deleteLater()));
			if (!g_debug_mode)
				connect(pHIKCaptureThread[Num], SIGNAL(updateStatistics(const QString&,int)), this, SLOT(updateStatisticsHub(const QString&,int)));
			pThread[Num]->start();
			if (pThread[Num]->isRunning())
			{
				qDebug() << "hik pThread OK";
				SingleCamInfo[Num].IsOpen =true;
				return true;
			}
			return false;
		}
	}
	else if(OpenOrClose == CLOSE && SingleCamInfo[Num].IsOpen)
	{
		if (SingleCamInfo[Num].CamClass == BalluffClassID)
		{
			qDebug() << "close for balluff";
			disconnect(pThread[Num], SIGNAL(started()), pCaptureThread[Num], SLOT(process()));
			//disconnect(pCaptureThread[Num], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
			disconnect(pCaptureThread[Num], SIGNAL(finished()), pThread[Num], SLOT(quit()));
			disconnect(pCaptureThread[Num], SIGNAL(finished()), pCaptureThread[Num], SLOT(deleteLater()));
			disconnect(pCaptureThread[Num], SIGNAL(updateStatistics(const QString&,int)), this, SLOT(updateStatisticsHub(const QString&,int)));
			if (pCaptureThread[Num])
			{
				pCaptureThread[Num]->terminate();
				if (pThread[Num])
				{
					pThread[Num]->quit();
					pThread[Num]->wait();
				}
			}
			Device* pDev = BalluffCamera::devMgr[SingleCamInfo[Num].unfiltered_num];
			if (pDev && pDev->isOpen())
			{
				pDev->close();
			}
			DeleteElement(pCaptureThread[Num]);
			DeleteElement(pThread[Num]);
			DeleteElement(pFI[Num]);
			DeleteElement(pAC[Num]);
			SingleCamInfo[Num].IsOpen = false;
			return true;
		}
		else if (SingleCamInfo[Num].CamClass == BaslerClassID)
		{
			qDebug() << "close for basler";
			disconnect(pThread[Num], SIGNAL(started()), pBaslerCaptureThread[Num], SLOT(process()));
			//disconnect(pBaslerCaptureThread[Num], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
			disconnect(pBaslerCaptureThread[Num], SIGNAL(finished()), pThread[Num], SLOT(quit()));
			disconnect(pBaslerCaptureThread[Num], SIGNAL(finished()), pBaslerCaptureThread[Num], SLOT(deleteLater()));
			disconnect(pBaslerCaptureThread[Num], SIGNAL(updateStatistics(const QString&, int)), this, SLOT(updateStatisticsHub(const QString&, int)));
			if (pBaslerCaptureThread[Num])
			{
				pBaslerCaptureThread[Num]->terminate();
				if (pThread[Num])
				{
					pThread[Num]->quit();
					pThread[Num]->wait();
				}
			}
			Pylon::CBaslerUniversalInstantCamera* baslerCamera = BaslerCamHandle[Num];
			/*if(baslerCamera && baslerCamera->IsOpen())
			{
				baslerCamera->Close();
				baslerCamera->GrabCameraEvents = false;
			}*/
			DeleteElement(pBaslerCaptureThread[Num]);
			DeleteElement(pThread[Num]);
			SingleCamInfo[Num].IsOpen = false;
			return true;
		}
		else if (SingleCamInfo[Num].CamClass == HIKClassID)
		{
			qDebug() << "close for hik";
			void* camhandle;
			camhandle = pHIKCaptureThread[Num]->CamHandle;
			disconnect(pThread[Num], SIGNAL(started()), pHIKCaptureThread[Num], SLOT(process()));
			//disconnect(pCaptureThread[Num], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
			disconnect(pHIKCaptureThread[Num], SIGNAL(finished()), pThread[Num], SLOT(quit()));
			disconnect(pHIKCaptureThread[Num], SIGNAL(finished()), pHIKCaptureThread[Num], SLOT(deleteLater()));
			disconnect(pHIKCaptureThread[Num], SIGNAL(updateStatistics(const QString&, int)), this, SLOT(updateStatisticsHub(const QString&, int)));
			if (pHIKCaptureThread[Num])
			{
				pHIKCaptureThread[Num]->terminate();
				if (pThread[Num])
				{
					pThread[Num]->quit();
					pThread[Num]->wait();
				}
			}
			if (camhandle)
			{
				MV_CC_CloseDevice(camhandle);
				MV_CC_DestroyHandle(camhandle);
			}
			DeleteElement(pHIKCaptureThread[Num]);
			DeleteElement(pThread[Num]);
			SingleCamInfo[Num].IsOpen = false;
			return true;
		}
	}
	return false;
}

void Cigarette::EnumerateCameras(SingleCamInfoStruct *TempSingleCamInfoStruct,bool showinfo,SysConf &conf)
{
	std::vector<SingleCamInfoStruct> TempSingleCamInfo;
	//这些厂商相机枚举时候会过滤别的厂商相机，单独枚举
	int basler_cnt = 0;
	int filtered = 0;
	filtered = BaslerCamera::Enumerate();
	Pylon::CInstantCameraArray cameras(filtered);
	Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance();

	for (int i = 0; i < min(filtered, NumberOfSupportedCameras); i++)
	{
		SingleCamInfoStruct CamInfo;
		//cameras[i].Attach(tlFactory.CreateDevice(BaslerCamera::devices[i]));
		//Pylon::String_t selectedAction = ::GenICam::gcstring("Action");
		//std::string manufacture = cameras[i].GetDeviceInfo().GetVendorId();
		//if (!manufacture.compare(0, 6, "BASLER"))
		//{
		// Print the UserDefined name of the camera.
		//std::string UserID = cameras[i].GetDeviceInfo().GetUserDefinedName();
		Pylon::CBaslerUniversalInstantCamera* baslerCamera = new Pylon::CBaslerUniversalInstantCamera(tlFactory.CreateDevice(BaslerCamera::devices[i]));
		baslerCamera->Open();
		std::string UserID = baslerCamera->DeviceUserID();
		baslerCamera->Close();
		delete baslerCamera;
		if(showinfo)std::cout << "Basler user ID = " << UserID << std::endl;
		CamInfo.UserID = atoi(UserID.c_str());
		CamInfo.CamClass = BaslerClassID;
		CamInfo.filtered_num = i;
		CamInfo.Detect = false;
		CamInfo.IsOpen = false;
		CamInfo.OffLine = false;
		TempSingleCamInfo.push_back(CamInfo);
		basler_cnt++;
		//}
	}

	//这些厂商相机可以互相枚举，但是Enumerate都要执行里面会初始化一些全局信息
	int hik_cnt = 0;
	int unfiltered = 0;
	unfiltered = HIKCamera::Enumerate();
	for (int i = 0; i < min(unfiltered, NumberOfSupportedCameras); i++)
	{
		MV_CC_DEVICE_INFO* pDeviceInfo = HIKCamera::stDeviceList.pDeviceInfo[i];
		std::string manufacture;
		char chManufacturer[32];
		if (pDeviceInfo->nTLayerType == MV_GIGE_DEVICE)
		{
			MV_GIGE_DEVICE_INFO* TempPtr = &(pDeviceInfo->SpecialInfo.stGigEInfo);
			memcpy(chManufacturer, TempPtr->chManufacturerName, 32);
			manufacture = chManufacturer;
		}
		else if (pDeviceInfo->nTLayerType == MV_USB_DEVICE)
		{
			MV_USB3_DEVICE_INFO* TempPtr = &(pDeviceInfo->SpecialInfo.stUsb3VInfo);
			memcpy(chManufacturer, TempPtr->chManufacturerName, 32);
			manufacture = chManufacturer;
		}
		else
		{
			continue;
		}

		if(showinfo)std::cout << "Camera:" << i << ",vendor = " << manufacture << std::endl;
		transform(manufacture.begin(), manufacture.end(), manufacture.begin(), ::toupper);
		SingleCamInfoStruct CamInfo;
		if ((!manufacture.compare(0, 3, "HIK")) || (!manufacture.compare(0, 3, "U3V")))
		{
			void* camhandle;
			MVCC_STRINGVALUE UserID;
			MVCC_STRINGVALUE YSXID;
			MVCC_STRINGVALUE YSXID2;
			string id;
			MV_CC_CreateHandle(&camhandle, HIKCamera::stDeviceList.pDeviceInfo[i]);
			if (!MV_CC_OpenDevice(camhandle))
			{
				MV_CC_GetDeviceUserID(camhandle, &UserID);
				MV_CC_GetStringValue(camhandle, "DeviceYSXID", &YSXID);
				if(showinfo)std::cout << "Hikrobot user ID = " << UserID.chCurValue << std::endl;
				id = YSXID.chCurValue;
#ifdef identify_Hik_YSXID
				if (id!="YSX9256")
				{
					QMessageBox::information(NULL, QStringLiteral("系统自检失败"), QStringLiteral("相机匹配失败，请检查相机型号"), QMessageBox::Ok);
					exit(-1);
				}
				YSXID = YSXID2;//清除数据
#endif
				MV_CC_CloseDevice(camhandle);
			}
			MV_CC_DestroyHandle(camhandle);
			CamInfo.UserID = atoi(UserID.chCurValue);
			CamInfo.CamClass = HIKClassID;
			CamInfo.unfiltered_num = i;
			CamInfo.Detect = false;
			CamInfo.IsOpen = false;
			CamInfo.OffLine = false;
			TempSingleCamInfo.push_back(CamInfo);
			hik_cnt++;
		}
	}

	int balluff_cnt = 0;
	unfiltered = BalluffCamera::Enumerate();
	for (int i = 0; i < min(unfiltered, NumberOfSupportedCameras); i++)
	{
		Device* pDev = BalluffCamera::devMgr[i];
		std::string manufacture = pDev->manufacturer.read();
		if(showinfo)std::cout << "Camera:" << i << ",vendor = " << manufacture << std::endl;
		transform(manufacture.begin(), manufacture.end(), manufacture.begin(), ::toupper);
		SingleCamInfoStruct CamInfo;
		if ((!manufacture.compare(0, 7, "BALLUFF"))||(!manufacture.compare(0, 13, "MATRIX VISION")))
		{
			mvIMPACT::acquire::GenICam::DeviceControl dc(pDev);
			std::string UserID = dc.deviceUserID.read();
			pDev->close();
			if(showinfo)std::cout << "Balluff user ID = " << UserID << std::endl;
			CamInfo.UserID = atoi(UserID.c_str());
			CamInfo.CamClass = BalluffClassID;
			CamInfo.unfiltered_num = i;
			CamInfo.Detect = false;
			CamInfo.IsOpen = false;
			CamInfo.OffLine = false;
			TempSingleCamInfo.push_back(CamInfo);
			balluff_cnt++;
		}
	}

	if (showinfo) {
		std::cout << "Camera Count:\t" << TempSingleCamInfo.size() << std::endl;
		if (balluff_cnt)std::cout << "Balluff Count:\t" << balluff_cnt << std::endl;
		if (hik_cnt)std::cout << "Hikvision Count:\t" << hik_cnt << std::endl;
		if (basler_cnt)std::cout << "Basler Count:\t" << basler_cnt << std::endl;
	}

	//各个厂商相机按照userid打开的逻辑代码----start
	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		for (int j = 0; j < TempSingleCamInfo.size(); j++)
		{
			if ((TempSingleCamInfo[j].UserID == conf.UserID[i]) && (TempSingleCamInfo[j].Detect!= true))
			{
				TempSingleCamInfo[j].Detect = true;
				TempSingleCamInfoStruct[i].unfiltered_num = TempSingleCamInfo[j].unfiltered_num;
				TempSingleCamInfoStruct[i].filtered_num = TempSingleCamInfo[j].filtered_num;
				TempSingleCamInfoStruct[i].CamClass = TempSingleCamInfo[j].CamClass;
				TempSingleCamInfoStruct[i].UserID = TempSingleCamInfo[j].UserID;
				TempSingleCamInfoStruct[i].Detect = TempSingleCamInfo[j].Detect;
				TempSingleCamInfoStruct[i].IsOpen = TempSingleCamInfo[j].IsOpen;
				TempSingleCamInfoStruct[i].OffLine = TempSingleCamInfo[j].OffLine;
				break;
			}
		}
	}
	//各个厂商相机按照userid打开的逻辑代码----end
}

void Cigarette::EnableDebugMode()
{
	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		if (SingleCamInfo[i].IsOpen && SingleCamInfo[i].Detect)
		{
			if(SingleCamInfo[i].CamClass == BalluffClassID)
			{
				//设置帧率=10fps
				pAC[i]->acquisitionFrameRateEnable.write(bTrue);
				pAC[i]->acquisitionFrameRate.write(10.0);
				//关闭外触发
				pAC[i]->triggerMode.writeS("Off");
			}
			else if(SingleCamInfo[i].CamClass == HIKClassID)
			{
				int nRet = MV_OK;
				MV_CC_SetFrameRate(HIKCamHandle[i], 10.0);
				nRet = MV_CC_SetBoolValue(HIKCamHandle[i], "AcquisitionFrameRateEnable",true);
				if (nRet) { std::cout << "can not set Hik's AcquisitionFrameRateEnable" << std::endl;}

				nRet = MV_CC_SetEnumValue(HIKCamHandle[i], "TriggerMode", MV_TRIGGER_MODE_OFF);
				if (nRet) { std::cout << "can not set Hik's TriggerMode" << std::endl;}
			}
			else if(SingleCamInfo[i].CamClass == BaslerClassID)
			{
				bool nRet = false;
				nRet = BaslerCamHandle[i]->AcquisitionFrameRate.TrySetValue(10);
				if (!nRet) { std::cout << "can not set Basler's AcquisitionFrameRate" << std::endl; }
				nRet = BaslerCamHandle[i]->AcquisitionFrameRateEnable.TrySetValue(true);
				if (!nRet) { std::cout << "can not set Basler's AcquisitionFrameRateEnable" << std::endl; }
				nRet = BaslerCamHandle[i]->TriggerSelector.TrySetValue(Basler_UniversalCameraParams::TriggerSelector_FrameStart);
				if (!nRet) { std::cout << "can not set Basler's TriggerSelector_FrameStart" << std::endl; }
				nRet = BaslerCamHandle[i]->TriggerMode.TrySetValue(Basler_UniversalCameraParams::TriggerMode_Off);
				if (!nRet) { std::cout << "can not set Basler's TriggerMode_Off" << std::endl; }
#ifndef USB_BASLER_NEW_FW
				nRet = BaslerCamHandle[i]->TriggerSelector.TrySetValue(Basler_UniversalCameraParams::TriggerSelector_FrameBurstStart);
				if (!nRet) { std::cout << "can not set Basler's TriggerSelector_FrameBurstStart" << std::endl;}
				nRet = BaslerCamHandle[i]->TriggerMode.TrySetValue(Basler_UniversalCameraParams::TriggerMode_Off);
				if (!nRet) { std::cout << "can not set Basler's TriggerMode_Off" << std::endl;}
#endif
			}
		}
	}
	g_debug_mode = true;
}

void Cigarette::DisableDebugMode()
{
	for(int i=0;i<NumberOfSupportedCameras;i++)
	{
		if (SingleCamInfo[i].IsOpen && SingleCamInfo[i].Detect)
		{
			if(SingleCamInfo[i].CamClass == BalluffClassID)
			{
				//设置帧率
				pAC[i]->acquisitionFrameRateEnable.write(bFalse);
				pAC[i]->triggerMode.writeS("On");
				pAC[i]->triggerSource.writeS("Line4");
				pAC[i]->triggerActivation.writeS("RisingEdge");
			}
			else if(SingleCamInfo[i].CamClass == HIKClassID)
			{
				int nRet = MV_OK;
				nRet = MV_CC_SetEnumValue(HIKCamHandle[i], "TriggerMode", MV_TRIGGER_MODE_ON);
				if (nRet) { std::cout << "can not set Hik's TriggerMode" << std::endl;}

				nRet = MV_CC_SetEnumValue(HIKCamHandle[i], "TriggerSource", MV_TRIGGER_SOURCE_LINE2);
				if (nRet) { std::cout << "can not set Hik's TriggerSource" << std::endl;}

				nRet = MV_CC_SetEnumValue(HIKCamHandle[i], "TriggerActivation", 1);//1表示下降沿
				if (nRet) { std::cout << "can not set Hik's TriggerActivation" << std::endl;}

				nRet = MV_CC_SetFrameRate(HIKCamHandle[i], 1000.0);
				if (nRet) { std::cout << "can not set Hik's FrameInfo" << std::endl;}
				nRet = MV_CC_SetBoolValue(HIKCamHandle[i], "AcquisitionFrameRateEnable",false);
				if (nRet) { std::cout << "can not set Hik's AcquisitionFrameRateEnable" << std::endl;}
			}
			else if(SingleCamInfo[i].CamClass == BaslerClassID)
			{
				bool nRet = false;
#ifndef USB_BASLER_NEW_FW
				nRet = BaslerCamHandle[i]->TriggerSelector.TrySetValue(Basler_UniversalCameraParams::TriggerSelector_FrameBurstStart);
				if (!nRet) { std::cout << "can not set Basler's TriggerSelector_FrameBurstStart" << std::endl;}
				nRet = BaslerCamHandle[i]->TriggerMode.TrySetValue(Basler_UniversalCameraParams::TriggerMode_On);
				if (!nRet) { std::cout << "can not set Basler's TriggerMode_On" << std::endl; }
#endif
				nRet = BaslerCamHandle[i]->TriggerSelector.TrySetValue(Basler_UniversalCameraParams::TriggerSelector_FrameStart);
				if (!nRet) { std::cout << "can not set Basler's TriggerSelector_FrameStart" << std::endl;}
				nRet = BaslerCamHandle[i]->TriggerMode.TrySetValue(Basler_UniversalCameraParams::TriggerMode_On);
				if (!nRet) { std::cout << "can not set Basler's TriggerMode_On" << std::endl;}
				nRet = BaslerCamHandle[i]->AcquisitionFrameRateEnable.TrySetValue(false);
				if (!nRet) { std::cout << "can not set Basler's AcquisitionFrameRateEnable" << std::endl;}
			}
		}
	}
	g_debug_mode = false;
}

void Cigarette::CleanThreadStart()
{
	QThread* handleThread = new QThread();
	CleanWorkThread* cleanWorkThread = new CleanWorkThread();

	cleanWorkThread->moveToThread(handleThread);

	connect(handleThread, &QThread::started, cleanWorkThread, &CleanWorkThread::startWork);
	connect(cleanWorkThread, &CleanWorkThread::workStart, cleanWorkThread, &CleanWorkThread::setSel);
	connect(cleanWorkThread, &CleanWorkThread::workFinished, cleanWorkThread, &CleanWorkThread::deleteLater);
	connect(cleanWorkThread, &CleanWorkThread::destroyed, handleThread, &QThread::quit);
	connect(handleThread, &QThread::finished, handleThread, &QThread::deleteLater);
	handleThread->start();
}
void Cigarette::CleanThreadStartAuto()
{
	QThread* handleThread = new QThread();
	CleanWorkThread* cleanWorkThread = new CleanWorkThread();

	cleanWorkThread->moveToThread(handleThread);

	connect(handleThread, &QThread::started, cleanWorkThread, &CleanWorkThread::startWorkAuto);
	connect(cleanWorkThread, &CleanWorkThread::workStart, cleanWorkThread, &CleanWorkThread::setSelAuto);
	connect(cleanWorkThread, &CleanWorkThread::workFinished, cleanWorkThread, &CleanWorkThread::deleteLater);
	connect(cleanWorkThread, &CleanWorkThread::destroyed, handleThread, &QThread::quit);
	connect(handleThread, &QThread::finished, handleThread, &QThread::deleteLater);
	handleThread->start();
}

void Cigarette::record_output_statistic(qint64 quantity, int shift)
{
	float Kick[NumberOfSupportedCameras] = {0};
	if (m_PLCDevice->g_plc_ok)
	{
		if (!g_plc_dialog_open)	//PLC配置对话框没有打开
		{
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
			if (g_modbus_conf.kick1 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick1, 2, dest16);
				if (ret == 2)
				{
					Kick[0] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
			if (g_modbus_conf.kick2 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick2, 2, dest16);
				if (ret == 2)
				{
					Kick[1] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
			if (g_modbus_conf.kick3 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick3, 2, dest16);
				if (ret == 2)
				{
					Kick[2] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
			if (g_modbus_conf.kick4 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick4, 2, dest16);
				if (ret == 2)
				{
					Kick[3] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
			if (g_modbus_conf.kick5 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick5, 2, dest16);
				if (ret == 2)
				{
					Kick[4] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
			if (g_modbus_conf.kick6 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick6, 2, dest16);
				if (ret == 2)
				{
					Kick[5] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
			if (g_modbus_conf.kick7 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick7, 2, dest16);
				if (ret == 2)
				{
					Kick[6] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
			if (g_modbus_conf.kick8 > 0)
			{
				uint16_t dest16[2];
				int ret = m_PLCDevice->read_short_from_plc(g_modbus_conf.kick8, 2, dest16);
				if (ret == 2)
				{
					Kick[7] = dest16[0] + (dest16[1] << 16);
				}
			}
#endif
		}
	}

	for (int i = 0; i < NumberOfSupportedCameras; i++)
	{
		if (SingleCamInfo[i].IsOpen && quantity > 0) {
			std::fstream cfg_file;
			char buf[256];
			memset(buf, 0, 256);
			sprintf(buf, STATISTIC_FILE, i);
			cfg_file.open(buf, std::ios::app);
			if (cfg_file.good())
			{
				if (last_shift == 2 || last_shift == 256) {
					memset(buf, 0, 256);
					sprintf(buf, "\n\n**************************************************************************************\n");
					cfg_file.write(buf, strlen(buf));
					QDate date = QDate::currentDate();
					memset(buf, 0, 256);
					sprintf(buf, "%s:\n", date.toString("yyyy-MM-dd ").toStdString().c_str());
					cfg_file.write(buf, strlen(buf));
				}
				memset(buf, 0, 256);
				sprintf(buf, "%c     总产量:%010I64d      剔除率:%02.5f%%      合格率:%02.5f%%   \n", (shift == 0) ? 'A' : ((shift == 1) ? 'B' : 'C'), quantity, (Kick[i] / quantity) * 100, (1.0 - (Kick[i] / quantity)) * 100);
				cfg_file.write(buf, strlen(buf));
				memset(buf, 0, 256);

			}
			cfg_file.close();
		}
	}
	last_shift = shift;
}

void Cigarette::recMsgFromUdp(QString data)
{
	//std::cout << data.toStdString() << std::endl;
#ifdef __UDPSend
	if (data == "START")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				return;
			}
		}
		if (m_PLCDevice->g_plc_ok) {
			if (g_debug_mode)
			{
				sThread.sendData("StillDebug", g_sys_conf.FeedbackPort);
			}
			else
			{
				on_btn_start_released();
			}
		}
	}
	else if (data == "END")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				return;
			}
		}
		on_btn_pause_released();
	}

	else if (data == "0")
	{
		OnRotateReleasedHub(0);
	}
	else if (data == "1")
	{
		OnRotateReleasedHub(1);
	}
	else if (data == "2")
	{
		OnRotateReleasedHub(2);
	}
	else if (data == "3")
	{
		OnRotateReleasedHub(3);
	}
	else if (data == "4")
	{
		OnRotateReleasedHub(4);
	}
	else if (data == "5")
	{
		OnRotateReleasedHub(5);
	}
	else if (data == "6")
	{
		OnRotateReleasedHub(6);
	}
	else if (data == "7")
	{
		OnRotateReleasedHub(7);
	}
	else if (data == "LOCK")
	{
		if (!g_admin_mode)
		{
			sThread.sendData("AdminNoLogin", g_sys_conf.FeedbackPort);
			return;
		}
		on_btn_lock_released();
	}
	else if (data == "CHANGESHIFT")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				return;
			}
		}
		if (g_working)
		{
			sThread.sendData("CheckWorkState", g_sys_conf.FeedbackPort);
		}
		else
		{
			on_pushButton_clear_released();
		}
	}
	else if (data == "CLEARNIMAGE")
	{
		emit sengMsgToClog("Clean images.");
		CleanThreadStart();
	}
	else if (data == "DEBUGEN")
	{
		if (!g_admin_mode)
		{
			sThread.sendData("Need_Login", g_sys_conf.FeedbackPort);
			sThread.sendData("DebugEnFail", g_sys_conf.FeedbackPort);
			return;
		}
		if (g_working)
		{
			if (g_debug_mode)
			{
				sThread.sendData("DebugEnStillWork", g_sys_conf.FeedbackPort);
			}
			else
			{
				sThread.sendData("DebugDisStillWork", g_sys_conf.FeedbackPort);
			}
		}
		else
		{
			on_checkBox_debug_clicked(true);
		}
	}
	else if (data == "DEBUGDIS")
	{
		if (!g_admin_mode)
		{
			sThread.sendData("Need_Login", g_sys_conf.FeedbackPort);
			sThread.sendData("DebugDisFail", g_sys_conf.FeedbackPort);
			return;
		}
		on_checkBox_debug_clicked(false);
	}
	else if (data == "KICK")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				sThread.sendData("KickFail", g_sys_conf.FeedbackPort);
				return;
			}
		}
		on_checkBox_unkick_clicked(false);
	}
	else if (data == "UNKICK")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				sThread.sendData("UnKickFail", g_sys_conf.FeedbackPort);
				return;
			}
		}
		if (m_PLCDevice->g_plc_ok) 
		{
			on_checkBox_unkick_clicked(true);
			ui.checkBox_unkick->setChecked(true);
		}
		else
		{
			sThread.sendData("UnKickFail", g_sys_conf.FeedbackPort);
		}
	}
	else if (data == "GETCONF")
	{
		sThread.sendFile(CONFIGURE_FILE,g_sys_conf.FilePort);
		for(int i=0;i<NumberOfSupportedCameras;i++)
		{
			char buf[256];
			memset(buf, 0, 256);
			sprintf(buf, STATISTIC_FILE, i);
			QString str(buf);
			sThread.sendFile(str, g_sys_conf.FilePort);
		}

	}
	else if (data == "SETCONF")
	{
		sThread.sendData("CanSetConf", g_sys_conf.FeedbackPort);
	}
	else if (data == "RESTART")
	{
		onrestart = true;
		OnRestart();
		onrestart = false;
	}
	else if (data == "GETSETTING")
	{
		if (!g_admin_mode)///管理员权限进入系统设置
		{
				sThread.sendData("AdminNoLogin", g_sys_conf.FeedbackPort);
				return;
		}
		else
		{
			sThread.sendData("CanGetSetting", g_sys_conf.FeedbackPort);
		}
		
	}
	else if (data == "RESET")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				return;
			}
		}
		on_pushButton_reset_released();
	}
	else if (data == "CLEARALARM")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				return;
			}
		}
			OnCancelAlarm();
	}
	else if (data == "GETALARMRECORD")
	{
		if (!g_admin_mode)
		{
			if (!g_op_mode)
			{
				sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
				return;
			}
		}
		sThread.sendFile(ALARM_RECORD_FILE,g_sys_conf.FilePort);
	}
	else {
		QStringList dataList = data.split(':');
		if (dataList[0] == "OPLOGIN") {
			QString md5Str = QCryptographicHash::hash(dataList[1].toLatin1(), QCryptographicHash::Md5).toHex();
			qDebug() << "m_pswd:" << dataList[1];
			qDebug() << "m_pswd md5:" << md5Str;
			qDebug() << "g_op_pswd md5:" << g_op_pswd;///
			if (md5Str.compare(g_op_pswd, Qt::CaseInsensitive) == 0)///
			{
				g_op_mode = true;
				OnOp();
				sThread.sendData("LoginIn", g_sys_conf.FeedbackPort);
			}
			else {
				sThread.sendData("PswError", g_sys_conf.FeedbackPort);
			}
		}
		else if (dataList[0] == "ADMINLOGIN") {
			QString md5Str = QCryptographicHash::hash(dataList[1].toLatin1(), QCryptographicHash::Md5).toHex();
			qDebug() << "m_pswd:" << dataList[1];
			qDebug() << "m_pswd md5:" << md5Str;
			qDebug() << "g_admin_pswd md5:" << g_admin_pswd;
			if (md5Str.compare(g_admin_pswd, Qt::CaseInsensitive) == 0)///
			{
				g_admin_mode = true;
				OnAdmin();
				sThread.sendData("LoginIn", g_sys_conf.FeedbackPort);
			}
			else {
				sThread.sendData("PswError", g_sys_conf.FeedbackPort);
			}
		}
		else if (dataList[0] == "CONNECTIONTEST")
		{
			QString msg = QString("HandShake") + '_';
			if (g_admin_mode) 
			{
				msg += "UnlockOk";
			}
			else 
			{
				msg += "LockOk";
			}
			msg += '_';
			if (g_debug_mode) 
			{
				msg += "DebugEn";
			}
			else
			{
				msg += "DebugDis";
			}
			msg += '_';
			if (ui.checkBox_unkick->isChecked())
			{
				msg += "UnKickOk";
			}
			else
			{
				msg += "KickOk";
			}
			sThread.sendData(msg, g_sys_conf.FeedbackPort);
		}
		else if (dataList[0] == "GETSETTINGPRO")
		{
			if (!g_admin_mode)
			{
				if (!g_op_mode)
				{
					sThread.sendData("OpNoLogin", g_sys_conf.FeedbackPort);
					return;
				}
			}
			int camcnt = dataList[1].toInt();
			QString str;
			str = QString("getsetting") + '_' + \
			QString::number(g_sys_conf.auto_open) + '_' +\
			QString::number(g_sys_conf.auto_work) + '_' +\
			QString::number(g_sys_conf.save) + '_';
			for(int i = 0;i<camcnt;i++){
				str += QString::number(g_sys_conf.expo[i]) + '_' + QString::number(g_sys_conf.gain[i]) + '_' + QString::number(g_sys_conf.filter[i]) + '_';
			}
			str += QString::number(g_sys_conf.shift_byhand) + '_' + \
				QString::number(g_sys_conf.timing_shift) + '_';
			str += QString::number(g_sys_conf.shiftA.hour()) + '_' +\
					QString::number(g_sys_conf.shiftA.minute())+ '_' +\
					QString::number(g_sys_conf.shiftB.hour()) + '_' +\
					QString::number(g_sys_conf.shiftB.minute())+ '_' +\
					QString::number(g_sys_conf.shiftC.hour()) + '_' +\
					QString::number(g_sys_conf.shiftC.minute())+ '_';
			for(int i = 0;i<camcnt;i++){
				str += QString::number(g_sys_conf.no[i][0]) + '_' + QString::number(g_sys_conf.no[i][1]) + '_' + QString::number(g_sys_conf.no[i][2]) + '_';
			}
			sThread.sendData(str, g_sys_conf.FeedbackPort);
			//std::cout << "=> to UDP: " << str.toStdString() << std::endl;
		}
		else if (dataList[0] == "UPDSETTING")
		{
			// 参数比远程端多1
			int index =0;
			int camcnt = atoi(dataList[1].toStdString().c_str());
			g_sys_conf.auto_open = dataList[2].toStdString() == "True" ? 1 : 0;
			g_sys_conf.auto_work = dataList[3].toStdString() == "True" ? 1 : 0;
			g_sys_conf.save = atoi(dataList[4].toStdString().c_str());
			for (; index < camcnt; index++)
			{
				g_sys_conf.expo[index] = atoi(dataList[5+index*3].toStdString().c_str());
				g_sys_conf.gain[index] = atoi(dataList[6+index*3].toStdString().c_str());
				g_sys_conf.filter[index] = atoi(dataList[7+index*3].toStdString().c_str());
			}
			index = 5+camcnt*3;
			g_sys_conf.shift_byhand = dataList[index].toInt();
			g_sys_conf.timing_shift = dataList[index + 1].toInt();
			index = index + 2;
			g_sys_conf.shiftA.setHMS(atoi(dataList[index].toStdString().c_str()), atoi(dataList[index+1].toStdString().c_str()), 0);
			g_sys_conf.shiftB.setHMS(atoi(dataList[index+2].toStdString().c_str()), atoi(dataList[index+3].toStdString().c_str()), 0);
			g_sys_conf.shiftC.setHMS(atoi(dataList[index+4].toStdString().c_str()), atoi(dataList[index+5].toStdString().c_str()), 0);
			index = index+6;
			for (int i = 0; i < camcnt; i++)
			{
				g_sys_conf.no[i][0] = atoi(dataList[index+i*3].toStdString().c_str());
				g_sys_conf.no[i][1] = atoi(dataList[index+i*3+1].toStdString().c_str());
				g_sys_conf.no[i][2] = atoi(dataList[index+i*3+2].toStdString().c_str());
			}

			DialogSetup::write_config();
			sThread.sendData("UpSettingOk", g_sys_conf.FeedbackPort);
			// QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("保存参数成功,部分配置需要重启程序后生效"), QMessageBox::Ok);
		}
		else if (dataList[0] == "OPERPWDCHANGE")
		{
			QString md5Str = QCryptographicHash::hash(dataList[1].toLatin1(), QCryptographicHash::Md5).toHex();
			if (md5Str.compare(g_op_pswd, Qt::CaseInsensitive) == 0)
			{
				QString pswd_new = dataList[2];
				QString pswd_confirm = dataList[3];
				if (pswd_new.compare(pswd_confirm, Qt::CaseInsensitive) == 0)
				{
					g_op_pswd = QCryptographicHash::hash(pswd_new.toLatin1(), QCryptographicHash::Md5).toHex();
					DialogSetup::write_pswd_op();
					// QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("操作员密码修改成功"), QMessageBox::Ok);
				}
				else {
					// QMessageBox::information(NULL, QStringLiteral("提示消息"), QStringLiteral("新密码两次输入不一致，请重新输入"), QMessageBox::Ok);
				}
			}
			else {
				// QMessageBox::information(NULL, QStringLiteral("提示消息"), QStringLiteral("原密码错误，请重新输入"), QMessageBox::Ok);
			}
		}
		else if (dataList[0] == "ADMINPWDCHANGE")
		{
		QString md5Str = QCryptographicHash::hash(dataList[1].toLatin1(), QCryptographicHash::Md5).toHex();
		if (md5Str.compare(g_admin_pswd, Qt::CaseInsensitive) == 0)
		{
			QString pswd_new = dataList[2];
			QString pswd_confirm = dataList[3];
			if (pswd_new.compare(pswd_confirm, Qt::CaseInsensitive) == 0)
			{
				g_admin_pswd = QCryptographicHash::hash(pswd_new.toLatin1(), QCryptographicHash::Md5).toHex();
				DialogSetup::write_pswd();
				// QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("管理员密码修改成功"), QMessageBox::Ok);
			}
			else {
				// QMessageBox::information(NULL, QStringLiteral("提示消息"), QStringLiteral("新密码两次输入不一致，请重新输入"), QMessageBox::Ok);
			}
		}
		else {
			// QMessageBox::information(NULL, QStringLiteral("提示消息"), QStringLiteral("原密码错误，请重新输入"), QMessageBox::Ok);
		}
		}
	}
#endif
}