ToolDialog.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. #include "ToolDialog.h"
  2. #include <QImage>
  3. #include <QFileInfo>
  4. #include <QFileDialog>
  5. #include <QElapsedTimer>
  6. #include <QGridLayout>
  7. ToolDialogImpl::ToolDialogImpl(QWidget *parent)
  8. : DllToolDialog(parent)
  9. {
  10. ui.setupUi(this);
  11. this->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint /*| Qt::WindowStaysOnTopHint*/);
  12. connect(this, SIGNAL(sigUpdateUI()), this, SLOT(on_UpdateUI()));
  13. m_nTableRowCount = 0;
  14. // 列数
  15. ui.tableWidget->setColumnCount(5);
  16. // 设置表头文字
  17. QStringList headers;
  18. headers
  19. << ("Index")
  20. << ("Name")
  21. << ("DataAddr")
  22. << ("Value")
  23. << ("Comment");
  24. ui.tableWidget->setHorizontalHeaderLabels(headers);
  25. //设置表头字体
  26. QFont font = ui.tableWidget->horizontalHeader()->font();
  27. font.setBold(true);
  28. ui.tableWidget->horizontalHeader()->setFont(font);
  29. // 设置文字左对齐
  30. ui.tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);
  31. // 设置为不可编辑
  32. ui.tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
  33. // 设置为整行选中模式
  34. ui.tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
  35. ui.tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
  36. // 设置最左侧的序号不用显示
  37. ui.tableWidget->verticalHeader()->setVisible(false);
  38. //设置行高
  39. ui.tableWidget->verticalHeader()->setDefaultSectionSize(10);
  40. //点击表时不对表头行光亮(获取焦点)
  41. ui.tableWidget->horizontalHeader()->setHighlightSections(false);
  42. m_strTP = "127.0.0.1";
  43. ui.edit_IP->setText(m_strTP);
  44. m_nTimerID = 0;
  45. m_nTimerID = this->startTimer(1000);
  46. m_nIsCOnnect = -1;
  47. m_pModbus = nullptr;
  48. m_nThreadState = 1;
  49. // 启动线程
  50. m_ReadThreadPool.start(
  51. new _ReadThread(this)
  52. );
  53. // 启动线程
  54. m_WriteThreadPool.start(
  55. new _WriteThread(this)
  56. );
  57. }
  58. ToolDialogImpl::~ToolDialogImpl()
  59. {
  60. if (m_pModbus)
  61. {
  62. modbus_close(m_pModbus);
  63. modbus_free(m_pModbus);
  64. }
  65. m_nThreadState = 0;
  66. }
  67. /// <summary>
  68. /// 调整大小的消息中改变表格栏的宽度
  69. /// </summary>
  70. /// <param name="event"></param>
  71. void ToolDialogImpl::resizeEvent(QResizeEvent* event)
  72. {
  73. Q_UNUSED(event);
  74. // qDebug() << "WindowAppVariableTable::resizeEvent";
  75. int nTotalSize = ui.tableWidget->size().width();
  76. ui.tableWidget->setColumnWidth(0, nTotalSize * 0.05);
  77. ui.tableWidget->setColumnWidth(1, nTotalSize * 0.2);
  78. ui.tableWidget->setColumnWidth(2, nTotalSize * 0.2);
  79. ui.tableWidget->setColumnWidth(3, nTotalSize * 0.2);
  80. ui.tableWidget->setColumnWidth(4, nTotalSize * 0.34);
  81. //ui.tableWidget->resize(ui.tableWidget->size());
  82. }
  83. VPEnum::RETURN_VALUE ToolDialogImpl::Execute()
  84. {
  85. emit sigUpdateUI();
  86. return VPEnum::RETURN_VALUE::Success;
  87. }
  88. void ToolDialogImpl::Running(bool bRun)
  89. {
  90. }
  91. /// <summary>
  92. ///
  93. /// </summary>
  94. /// <param name="nIndex"></param>
  95. /// <returns></returns>
  96. bool ToolDialogImpl::updateValue(int nIndex)
  97. {
  98. return writeValueToPLC(nIndex);
  99. }
  100. void ToolDialogImpl::timerEvent(QTimerEvent* event)
  101. {
  102. if (event->timerId() == m_nTimerID)
  103. {
  104. }
  105. }
  106. bool ToolDialogImpl::Serialized(QDataStream& ar, bool bIsOut)
  107. {
  108. int paranum;//参数数量
  109. if (bIsOut)//保存参数流程
  110. {
  111. paranum = 3;
  112. ar << paranum;//先保存参数数量
  113. ar << (int)1 << m_strTP;
  114. ar << (int)2 << m_strPort;
  115. ar << (int)3 << m_nIsCOnnect;
  116. }
  117. else//加载参数流程,参数加载顺序一定要跟保存顺序一致
  118. {
  119. int nSize1 = 0;
  120. int para;
  121. ar >> paranum;//读取参数数量
  122. for (int i = 0; i < paranum; i++)
  123. {
  124. ar >> para;
  125. switch (para)
  126. {
  127. case 1: ar >> m_strTP; break;
  128. case 2: ar >> m_strPort; break;
  129. case 3: ar >> m_nIsCOnnect; break;
  130. default:
  131. {
  132. qWarning() << "Serialized(In) Error";
  133. return false;
  134. }
  135. break;
  136. }
  137. }
  138. setValueToUI();
  139. //hwndUnit->getHWndCtrl()->useROIController(&roiController);
  140. }
  141. return true;
  142. }
  143. void ToolDialogImpl::on_UpdateUI()
  144. {
  145. if (m_pDB != nullptr)
  146. {
  147. // 更新表格
  148. if (m_nTableRowCount != m_pDB->Variables.size())
  149. {
  150. m_nTableRowCount = m_pDB->Variables.size();
  151. for (int row = 0; row < m_nTableRowCount; row++)
  152. {
  153. ui.tableWidget->removeRow(0);
  154. }
  155. m_TableWidgetItems.clear();
  156. int i = 0;
  157. for (VARIABLE* var : m_pDB->Variables)
  158. {
  159. ui.tableWidget->insertRow(ui.tableWidget->rowCount());//增加一行
  160. ui.tableWidget->setItem(i, 0, new QTableWidgetItem(QString::number(i)));
  161. ui.tableWidget->setItem(i, 1, new QTableWidgetItem(var->strName));
  162. ui.tableWidget->setItem(i, 2, new QTableWidgetItem(var->strCommAddress));
  163. QTableWidgetItem* pItem = new QTableWidgetItem(var->strComment);
  164. m_TableWidgetItems.push_back(pItem);
  165. ui.tableWidget->setItem(i, 3, pItem);
  166. ui.tableWidget->setItem(i, 4, new QTableWidgetItem(var->strComment));
  167. i++;
  168. }
  169. }
  170. // 更新值
  171. const QVector<QTableWidgetItem*>& pTaskItems = m_TableWidgetItems;
  172. int i = 0;
  173. for (VARIABLE* var : m_pDB->Variables)
  174. {
  175. pTaskItems[i]->setText(var->getValueString());
  176. i++;
  177. }
  178. }
  179. }
  180. /// <summary>
  181. /// 确定
  182. /// </summary>
  183. void ToolDialogImpl::on_btnOK_clicked()
  184. {
  185. this->hide();
  186. }
  187. /// <summary>
  188. /// 取消按钮
  189. /// </summary>
  190. void ToolDialogImpl::on_btnCancel_clicked()
  191. {
  192. // 将本工具的恢复到打开工具之前的状态
  193. RecoverData();
  194. }
  195. /// <summary>
  196. /// 测试按钮
  197. /// </summary>
  198. void ToolDialogImpl::on_btnExecute_clicked()
  199. {
  200. QElapsedTimer toolTimer;
  201. toolTimer.start();
  202. // 发送事件
  203. ToolEvent* pToolEvent = new ToolEvent(m_strPouName, m_strInstanceName, TOOL_EVENT_TYPE::TOOL_TRIGGER);
  204. QCoreApplication::sendEvent(m_pEventTarget, pToolEvent);
  205. delete pToolEvent;
  206. // 统计返回值
  207. VPEnum::RETURN_VALUE ret = VPEnum::RETURN_VALUE::Success;
  208. double nExecTime = toolTimer.elapsed();
  209. QString str;
  210. str = QString("耗时: %1 ms").arg(nExecTime, 0, 'G', 5);
  211. ui.label_time->setText(str);
  212. str = QString("状态: %1 ").arg(QMetaEnum::fromType<VPEnum::RETURN_VALUE>().key((short)ret));
  213. ui.label_state->setText(str);
  214. }
  215. void ToolDialogImpl::on_btn_Connect_clicked()
  216. {
  217. m_strTP = ui.edit_IP->text();
  218. //if (m_pModbus != nullptr)
  219. {
  220. int nRet = ConnectToPLC();
  221. // Connect OK
  222. if (nRet == 0)
  223. {
  224. m_nIsCOnnect = 1;
  225. }
  226. }
  227. }
  228. bool ToolDialogImpl::on_rbnModbusRTU_clicked()
  229. {
  230. return true;
  231. }
  232. bool ToolDialogImpl::on_rbnModbusTCP_clicked()
  233. {
  234. return true;
  235. }
  236. /// <summary>
  237. /// 2022-3-1 向exe中的变量表界面同步数值
  238. /// </summary>
  239. /// <param name="pInfs"></param>
  240. void ToolDialogImpl::syncValuesToTableUI(QList<VARIABLE*> pInfs)
  241. {
  242. SyncValueEvent* valueEvent = new SyncValueEvent();
  243. // 携带需要同步的多个接口
  244. valueEvent->setSyncValues(pInfs);
  245. // post数值同步消息
  246. QCoreApplication::postEvent((QObject*)this->m_pGvlTarget, valueEvent);
  247. }
  248. int ToolDialogImpl::ConnectToPLC()
  249. {
  250. m_pModbus = modbus_new_tcp(m_strTP.toStdString().c_str(), 502);
  251. modbus_set_slave(m_pModbus, 1);
  252. struct timeval time;
  253. time.tv_sec = 0;
  254. time.tv_usec = 1000000;
  255. modbus_set_response_timeout(m_pModbus, (int)&time.tv_sec, (int)&time.tv_usec);
  256. return modbus_connect(m_pModbus);
  257. }
  258. void ToolDialogImpl::setValueToUI()
  259. {
  260. ui.edit_IP->setText(m_strTP);
  261. // 如果反序列化上来,发现之前是连接的状态,即开始新的链接。注:如果此时链接不成功,该值会被覆盖为未连接状态
  262. if (m_nIsCOnnect != -1)
  263. {
  264. ConnectToPLC();
  265. }
  266. }
  267. /// <summary>
  268. ///
  269. /// </summary>
  270. /// <returns></returns>
  271. bool ToolDialogImpl::readValueByPLC()
  272. {
  273. if (m_pDB == nullptr || m_pModbus == nullptr || m_nIsCOnnect == -1)
  274. {
  275. return false;
  276. }
  277. // 如果窗口的tab 行数与变量行数不一致,就需要添加数据行
  278. emit sigUpdateUI();
  279. QList<VARIABLE*> infs;
  280. int i = 0;
  281. for (VARIABLE* var : m_pDB->Variables)
  282. {
  283. int nCommAddress = var->strCommAddress.toInt();
  284. if (var->value.type == VALUE_TYPE::Type_Bool)
  285. {
  286. int nValue = (*(int*)(var->value.Ptr));
  287. if (nCommAddress > 40000 && nCommAddress < 50000)
  288. {
  289. // 根据DB 中的地址,去PLC 中读取对用的值
  290. uint16_t read_reg[255] = { 0 };
  291. modbus_read_registers(m_pModbus, nCommAddress - 40001, 1, read_reg);
  292. int nReadVar = read_reg[0];
  293. // 如果发现读上来的值与实际DB 中值不一致,就需要修改DB的值,并更新 DB的UI
  294. if (nReadVar != nValue)
  295. {
  296. (*(int*)(var->value.Ptr)) = nReadVar;
  297. infs.push_back(var);// 储存要刷新的变量列表
  298. }
  299. }
  300. }
  301. else if (var->value.type == VALUE_TYPE::Type_Int)
  302. {
  303. int nValue = (*(int*)(var->value.Ptr));
  304. if (nCommAddress > 40000 && nCommAddress < 50000)
  305. {
  306. // 根据DB 中的地址,去PLC 中读取对用的值
  307. uint16_t read_reg[255] = { 0 };
  308. modbus_read_registers(m_pModbus, nCommAddress - 40001, 1, read_reg);
  309. int nReadVar = read_reg[0];
  310. // 如果发现读上来的值与实际DB 中值不一致,就需要修改DB的值,并更新 DB的UI
  311. if (nReadVar != nValue)
  312. {
  313. (*(int*)(var->value.Ptr)) = nReadVar;
  314. infs.push_back(var);// 储存要刷新的变量列表
  315. }
  316. }
  317. }
  318. else if (var->value.type == VALUE_TYPE::Type_Float)
  319. {
  320. float fValue = (*(float*)(var->value.Ptr));
  321. if (nCommAddress > 40000 && nCommAddress < 50000)
  322. {
  323. // 根据DB 中的地址,去PLC 中读取对用的值
  324. uint16_t read_reg[255] = { 0 };
  325. modbus_read_registers(m_pModbus, nCommAddress - 40001, 2, read_reg);
  326. float fReadVar = modbus_get_float_badc(read_reg);
  327. //int fReadVar = modbus_get_float_dcba(read_reg); //高低位置换
  328. // 如果发现读上来的值与实际DB 中值不一致,就需要修改DB的值,并更新 DB的UI
  329. if ((fabs(fReadVar - fValue)) > 0.0001)
  330. {
  331. (*(float*)(var->value.Ptr)) = fReadVar;
  332. infs.push_back(var);// 储存要刷新的变量列表
  333. }
  334. }
  335. }
  336. else if (var->value.type == VALUE_TYPE::Type_Double)
  337. {
  338. float fValue = (*(float*)(var->value.Ptr));
  339. if (nCommAddress > 40000 && nCommAddress < 50000)
  340. {
  341. // 根据DB 中的地址,去PLC 中读取对用的值
  342. uint16_t read_reg[255] = { 0 };
  343. modbus_read_registers(m_pModbus, nCommAddress - 40001, 2, read_reg);
  344. float fReadVar = modbus_get_float_badc(read_reg);
  345. //int fReadVar = modbus_get_float_dcba(read_reg); //高低位置换
  346. // 如果发现读上来的值与实际DB 中值不一致,就需要修改DB的值,并更新 DB的UI
  347. if (fabs(fReadVar - fValue) < 0.000001)
  348. {
  349. (*(float*)(var->value.Ptr)) = fReadVar;
  350. infs.push_back(var);// 储存要刷新的变量列表
  351. }
  352. }
  353. }
  354. i++;
  355. }
  356. if (infs.size() > 0)
  357. {
  358. // 发送变更通知
  359. this->syncValuesToTableUI(infs);
  360. }
  361. return true;
  362. }
  363. /// <summary>
  364. ///
  365. /// </summary>
  366. /// <param name="nIndex"></param>
  367. /// <returns></returns>
  368. bool ToolDialogImpl::writeValueToPLC(int nIndex)
  369. {
  370. if (m_pDB != nullptr)
  371. {
  372. VARIABLE* var = m_pDB->Variables[nIndex];
  373. if (var != nullptr)
  374. {
  375. qDebug() << "Variable:" << var->strName << "[" << var->getValueString() << "]";
  376. int nCommAddress = var->strCommAddress.toInt();
  377. // bool
  378. if (var->value.type == VALUE_TYPE::Type_Bool)
  379. {
  380. if (nCommAddress > 40000 && nCommAddress < 50000)
  381. {
  382. // 写int 数据的启示地址为 0
  383. modbus_write_register(m_pModbus, nCommAddress - 40001, var->getValueString().toInt());
  384. }
  385. }
  386. // int
  387. else if (var->value.type == VALUE_TYPE::Type_Int)
  388. {
  389. if (nCommAddress > 40000 && nCommAddress < 50000)
  390. {
  391. // 写int 数据的启示地址为 0
  392. modbus_write_register(m_pModbus, nCommAddress - 40001, var->getValueString().toInt());
  393. }
  394. }
  395. // float
  396. else if (var->value.type == VALUE_TYPE::Type_Float)
  397. {
  398. if (nCommAddress > 40000 && nCommAddress < 50000)
  399. {
  400. // 写float 数据的启示地址为 0
  401. float fVilue = var->getValueString().toFloat();
  402. uint16_t* pRegisters = (uint16_t*)malloc(4 * sizeof(uint16_t));
  403. memset(pRegisters, 0, 4 * sizeof(uint16_t));
  404. modbus_set_float_badc(fVilue, pRegisters);// 正常高低位
  405. //modbus_set_float_dcba(fVilue, pRegisters);// 高低位置换
  406. modbus_write_registers(m_pModbus, nCommAddress - 40001, 2, pRegisters);
  407. }
  408. }
  409. // dobule
  410. else if (var->value.type == VALUE_TYPE::Type_Double)
  411. {
  412. if (nCommAddress > 40000 && nCommAddress < 50000)
  413. {
  414. // 写int 数据的启示地址为 0
  415. modbus_write_register(m_pModbus, nCommAddress - 40001, var->getValueString().toInt());
  416. }
  417. }
  418. // string
  419. else if (var->value.type == VALUE_TYPE::Type_String)
  420. {
  421. if (nCommAddress > 40000 && nCommAddress < 50000)
  422. {
  423. // 写int 数据的启示地址为 0
  424. modbus_write_register(m_pModbus, nCommAddress - 40001, var->getValueString().toInt());
  425. }
  426. }
  427. }
  428. }
  429. return true;
  430. }
  431. //============================================================
  432. //
  433. // Save 线程
  434. //
  435. //============================================================
  436. /// <summary>
  437. /// 线程函数
  438. /// </summary>
  439. void _ReadThread::run()
  440. {
  441. // 调用函数执行任务
  442. while (m_pDialog->m_nThreadState)
  443. {
  444. m_pDialog->readValueByPLC();
  445. QThread::msleep(50);
  446. }
  447. return;
  448. }
  449. /// <summary>
  450. /// 线程函数
  451. /// </summary>
  452. void _WriteThread::run()
  453. {
  454. // 调用函数执行任务
  455. while (m_pDialog->m_nThreadState)
  456. {
  457. //m_pDialog->writeValueToPLC();
  458. QThread::msleep(500);
  459. }
  460. return;
  461. }