CompareItemThread.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. #include "CompareItemThread.h"
  2. #include "FromMQTT.h"
  3. #include "GlobalInfo.h"
  4. #include "ThreadManager.h"
  5. #include "CalculateDBThread.h"
  6. #include "NoiseDetectThread.h"
  7. #include "CompareDoubleThread.h"
  8. #include "ThreadPool.h"
  9. #include "commonDefine.h"
  10. #include "ThreadAlarmManager.h"
  11. #include "spdlog.h"
  12. #include <qdatetime.h>
  13. CompareItemThread::CompareItemThread(CalculateThreadInfo_t& threadInfo)
  14. : QObject(nullptr), BaseCalculateThread(threadInfo)
  15. {
  16. }
  17. CompareItemThread::~CompareItemThread()
  18. {
  19. }
  20. /* 重写父类的线程函数,这里重新实现 */
  21. void CompareItemThread::threadTask()
  22. {
  23. m_logBase = fmt::format("对比项: {}", m_threadInfo.compareItemInfo.strName.toStdString());
  24. SPDLOG_LOGGER_INFO(m_logger, "----------------------------------------------------------------");
  25. SPDLOG_LOGGER_INFO(m_logger, "{} 线程开始运行, 对比通道: ", m_logBase);
  26. for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  27. {
  28. SPDLOG_LOGGER_INFO(m_logger, " 通道名称: {}, 通道编号: {}, 声卡通道: {}:{}",
  29. road.strCompareRoadName.toStdString(), road.nCompareRoadNum, road.scRoadInfo.strSoundCardName.toStdString(), road.scRoadInfo.roadInfo.nRoadNum);
  30. }
  31. SPDLOG_LOGGER_INFO(m_logger, "----------------------------------------------------------------");
  32. /* 初始化数据 */
  33. if(!initData())
  34. {
  35. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  36. return;
  37. }
  38. /* 更新线程状态标志 */
  39. m_threadInfo.threadState = EThreadState::State_Running;
  40. m_isStop = false;
  41. m_pTimer = new QTimer();
  42. if(m_pTimer == nullptr)
  43. {
  44. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建定时器失败", m_logBase);
  45. }
  46. // SPDLOG_LOGGER_WARN(m_logger, "{} 创建定时器成功,开启定时器", m_logBase);
  47. m_pTimer->setTimerType(Qt::PreciseTimer);
  48. m_pTimer->setSingleShot(false); // 设置为非单次定时器
  49. m_pTimer->setInterval(50);
  50. m_eventLoop.connect(m_pTimer, &QTimer::timeout, this, &CompareItemThread::do_timeout);
  51. m_pTimer->start();
  52. /* 开启事件循环 */
  53. m_eventLoop.exec();
  54. /* 等待 */
  55. // std::this_thread::sleep_for(std::chrono::seconds(20));
  56. /* 线程结束,清理数据 */
  57. clearData();
  58. m_threadInfo.threadState = EThreadState::State_Stopped;
  59. m_isStop = true;
  60. SPDLOG_LOGGER_WARN(m_logger, "★ {} 线程结束运行", m_logBase);
  61. }
  62. /* 停止线程函数 */
  63. void CompareItemThread::stopThread()
  64. {
  65. if(m_pTimer != nullptr)
  66. {
  67. if(m_pTimer->isActive())
  68. {
  69. m_pTimer->stop();
  70. }
  71. disconnect(m_pTimer, &QTimer::timeout, this, &CompareItemThread::do_timeout);
  72. delete m_pTimer;
  73. m_pTimer = nullptr;
  74. }
  75. /* 停止事件循环 */
  76. m_eventLoop.quit();
  77. }
  78. void CompareItemThread::stopThreadBlock()
  79. {
  80. stopThread();
  81. while(!m_isStop) // 等待线程停止
  82. {
  83. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  84. }
  85. }
  86. /* 设置检测时段 */
  87. void CompareItemThread::setDetectPeriod(const DetectPeriodConfig_t& detectPeriod)
  88. {
  89. std::lock_guard<std::mutex> lock(m_mutexDetectPeriod);
  90. if(detectPeriod.nID != m_threadInfo.compareItemInfo.nID)
  91. {
  92. SPDLOG_LOGGER_ERROR(m_logger, "{} 设置检测时段失败,ID不匹配: {}, 当前ID: {}", m_logBase, detectPeriod.nID, m_detectPeriod.nID);
  93. return;
  94. }
  95. m_detectPeriod = detectPeriod;
  96. // m_isDetectPeriodUpdated = true; // 标记检测时段已更新
  97. }
  98. /* 线程功能函数 */
  99. void CompareItemThread::task()
  100. {
  101. m_logBase = fmt::format("对比项: {}", m_threadInfo.compareItemInfo.strName.toStdString());
  102. SPDLOG_LOGGER_INFO(m_logger, "----------------------------------------------------------------");
  103. SPDLOG_LOGGER_INFO(m_logger, "{} 线程开始运行, 对比通道: ", m_logBase);
  104. for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  105. {
  106. SPDLOG_LOGGER_INFO(m_logger, " 通道名称: {}, 通道编号: {}, 声卡通道: {}:{}",
  107. road.strCompareRoadName.toStdString(), road.nCompareRoadNum, road.scRoadInfo.strSoundCardName.toStdString(), road.scRoadInfo.roadInfo.nRoadNum);
  108. }
  109. SPDLOG_LOGGER_INFO(m_logger, "----------------------------------------------------------------");
  110. /* 初始化数据 */
  111. if(!initData())
  112. {
  113. SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase);
  114. return;
  115. }
  116. // SPDLOG_LOGGER_WARN(m_logger, "{} 初始化数据完成,开始对比检测, isRunning: {}", m_logBase, m_isRunning.load());
  117. while (m_isRunning)
  118. {
  119. /* 睡眠100ms */
  120. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  121. /* -------------------------------------------------------------------------------------
  122. * 更新对比项信息
  123. * ------------------------------------------------------------------------------------- */
  124. if(updateThreadInfoInternal())
  125. {
  126. SPDLOG_LOGGER_INFO(m_logger, "{} 暂停对比检测,更新对比项信息");
  127. m_threadInfo.compareItemInfo = m_threadInfoNew.compareItemInfo;
  128. initData();
  129. SPDLOG_LOGGER_INFO(m_logger, "{} 更新对比项信息完成,继续检测对比");
  130. }
  131. /* -------------------------------------------------------------------------------------
  132. * 更新数据
  133. * ------------------------------------------------------------------------------------- */
  134. if(!updateResultData())
  135. {
  136. continue;
  137. // return;
  138. }
  139. /* -------------------------------------------------------------------------------------
  140. * 处理数据,将报警信息给写报警数据的线程
  141. * ------------------------------------------------------------------------------------- */
  142. // processAlarmData();
  143. /* -------------------------------------------------------------------------------------
  144. * 将音量包数据发送到MQTT中
  145. * ------------------------------------------------------------------------------------- */
  146. sendResultData();
  147. /* 清除标志位 */
  148. clearUpdateFlags();
  149. SPDLOG_LOGGER_WARN(m_logger, "{} 发送对比项数据到MQTT中", m_logBase);
  150. }
  151. /* 清理数据 */
  152. clearData();
  153. SPDLOG_LOGGER_WARN(m_logger, "★ {} 线程结束运行", m_logBase);
  154. }
  155. /* 定时器任务 */
  156. void CompareItemThread::timerTask()
  157. {
  158. /* -------------------------------------------------------------------------------------
  159. * 更新对比项信息
  160. * ------------------------------------------------------------------------------------- */
  161. if(updateThreadInfoInternal())
  162. {
  163. SPDLOG_LOGGER_INFO(m_logger, "{} 暂停对比检测,更新对比项信息");
  164. m_threadInfo.compareItemInfo = m_threadInfoNew.compareItemInfo;
  165. initData();
  166. SPDLOG_LOGGER_INFO(m_logger, "{} 更新对比项信息完成,继续检测对比");
  167. }
  168. /* 更新检测时间段 */
  169. checkDetectPeriod();
  170. /* -------------------------------------------------------------------------------------
  171. * 更新数据
  172. * ------------------------------------------------------------------------------------- */
  173. if(!updateResultData())
  174. {
  175. return;
  176. }
  177. /* -------------------------------------------------------------------------------------
  178. * 处理数据,将报警信息给写报警数据的线程,直接由各个计算线程直接写入
  179. * ------------------------------------------------------------------------------------- */
  180. // processAlarmData();
  181. /* -------------------------------------------------------------------------------------
  182. * 将音量包数据发送到MQTT中
  183. * ------------------------------------------------------------------------------------- */
  184. sendResultData();
  185. /* 清除标志位 */
  186. clearUpdateFlags();
  187. // SPDLOG_LOGGER_WARN(m_logger, "{} 发送对比项数据到MQTT中", m_logBase);
  188. }
  189. /* 初始化数据 */
  190. bool CompareItemThread::initData()
  191. {
  192. /* 创建录音通道线程 */
  193. for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  194. {
  195. ThreadMan.createRecordThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID);
  196. }
  197. /* 创建计算音量报警信息的线程指针 */
  198. destroyCalculateDBThreads(); // 清理之前的线程
  199. createCalculateDBThreads();
  200. /* 创建两个对比线程,主通道是第一个通道,其他都需要和主通道进行对比 */
  201. destroyCompareThreads();
  202. createCompareThreads();
  203. /* 获取计算噪音的线程 */
  204. destroyNoiseDetectThreads();
  205. createNoiseDetectThreads();
  206. /* 初始化存储结果的数据结构 */
  207. m_compareResult = CompareResult_t();
  208. m_compareResult.compareItemID = m_threadInfo.compareItemInfo.nID;
  209. m_compareResult.compareItemName = m_threadInfo.compareItemInfo.strName.toStdString();
  210. m_compareResult.dateTime = QDateTime::currentDateTime();
  211. m_compareResult.isClientAlarm = false; // 默认不报警
  212. m_compareResult.mapRoadVolumes.clear(); // 清空之前的数据
  213. for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  214. {
  215. OneRoadVolume_t oneRoadVolume;
  216. oneRoadVolume.roadInfo = road; // 设置通道信息
  217. oneRoadVolume.dateTime = QDateTime::currentDateTime(); // 初始化时间
  218. m_compareResult.mapRoadVolumes.insert({road.nCompareRoadNum, oneRoadVolume});
  219. }
  220. m_mapCDBUpdated.clear();
  221. for(auto it : m_threadInfo.compareItemInfo.mapRoad)
  222. {
  223. m_mapCDBUpdated.insert({it.nCompareRoadNum, false}); // 初始化更新标志位为false
  224. }
  225. m_lastDetectPeriodUpdateTime = QDateTime::currentDateTime();
  226. return true;
  227. }
  228. /* 清理数据 */
  229. void CompareItemThread::clearData()
  230. {
  231. /* 停止所有的比对线程 */
  232. destroyCompareThreads();
  233. /* 销毁音量报警线程 */
  234. destroyCalculateDBThreads();
  235. /* 移除噪音检测线程 */
  236. // removeNoiseDetectThreads();
  237. destroyNoiseDetectThreads();
  238. /* 移除使用到的录音通道 */
  239. for(auto& it : m_threadInfo.compareItemInfo.mapRoad)
  240. {
  241. SoundCardRoadInfo_t roadInfo = it.scRoadInfo;
  242. if(!ThreadMan.removeRecordThread(roadInfo, m_threadInfo.compareItemInfo.nID))
  243. {
  244. SPDLOG_LOGGER_ERROR(m_logger, "{} 移除录音通道 {}:{} 失败", m_logBase, roadInfo.strSoundCardName.toStdString(), roadInfo.roadInfo.nRoadNum);
  245. }
  246. }
  247. if(m_pFromMQTT != nullptr)
  248. {
  249. delete m_pFromMQTT; // 删除MQTT对象
  250. m_pFromMQTT = nullptr; // 设置为nullptr
  251. }
  252. }
  253. /* 定时器槽函数 */
  254. void CompareItemThread::do_timeout()
  255. {
  256. // SPDLOG_LOGGER_WARN(m_logger, "{} 定时器触发,开始执行定时任务", m_logBase);
  257. if(m_pFromMQTT == nullptr)
  258. {
  259. initMQTT();
  260. }
  261. timerTask();
  262. }
  263. /* 初始化MQTT */
  264. void CompareItemThread::initMQTT()
  265. {
  266. if(m_pFromMQTT == nullptr)
  267. {
  268. m_pFromMQTT = new FromMQTT();
  269. if(m_pFromMQTT == nullptr)
  270. {
  271. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建MQTT对象失败", m_logBase);
  272. return; // 创建MQTT对象失败
  273. }
  274. }
  275. /* 登陆MQTT */
  276. m_pFromMQTT->setIPAndPort(GInfo.mqttIP(), GInfo.mqttPort());
  277. m_pFromMQTT->setAutoReconnect();
  278. m_pFromMQTT->connectToServer();
  279. m_pubTopic = QString("%1/%2").arg(GInfo.mqttPubTopicDB()).arg(QString::number(m_threadInfo.compareItemInfo.nID));
  280. SPDLOG_LOGGER_INFO(m_logger, "☆ {} 连接MQTT服务器: {}:{}, 音量包订阅主题: {}", m_logBase, GInfo.mqttIP().toStdString(), GInfo.mqttPort(), m_pubTopic.toStdString());
  281. }
  282. /* 创建两个对比线程,主通道是第一个通道,其他都需要和主通道进行对比 */
  283. bool CompareItemThread::createCompareThreads()
  284. {
  285. auto it = m_threadInfo.compareItemInfo.mapRoad.begin();
  286. auto mainRoad = it.value(); // 主通道信息
  287. it++; // 移动到下一个通道
  288. // uint64_t size = m_threadInfo.compareItemInfo.mapRoad.size();
  289. for(; it != m_threadInfo.compareItemInfo.mapRoad.end(); it++)
  290. {
  291. CalculateThreadInfo_t compareThreadInfo;
  292. compareThreadInfo.compareItemInfo = m_threadInfo.compareItemInfo;
  293. compareThreadInfo.compareItemInfo.mapRoad.clear(); // 清空通道信息
  294. compareThreadInfo.compareItemInfo.mapRoad.insert(mainRoad.nCompareRoadNum, mainRoad); // 添加主通道
  295. compareThreadInfo.compareItemInfo.mapRoad.insert(it.key(), it.value()); // 添加当前通道
  296. compareThreadInfo.threadState = EThreadState::State_Inited;
  297. CompareDoubleThread* pThread = new CompareDoubleThread(compareThreadInfo);
  298. if(pThread == nullptr)
  299. {
  300. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建对比线程 {} - {} 失败", m_logBase, mainRoad.strCompareRoadName.toStdString(), it.value().strCompareRoadName.toStdString());
  301. return false;
  302. }
  303. m_mapCompareDoubleThreads.insert({it.key(), pThread}); // 保存线程指针
  304. /* 开始运行 */
  305. CPPTP.add_task(&CompareDoubleThread::threadTask, pThread);
  306. }
  307. return true;
  308. }
  309. /* 销毁两两对比线程 */
  310. void CompareItemThread::destroyCompareThreads()
  311. {
  312. if(m_mapCompareDoubleThreads.size() == 0)
  313. {
  314. return; // 没有对比线程
  315. }
  316. SPDLOG_LOGGER_INFO(m_logger, "{} 销毁对比线程", m_logBase);
  317. for(auto& pair : m_mapCompareDoubleThreads)
  318. {
  319. if(pair.second != nullptr)
  320. {
  321. pair.second->stopThreadBlock(); // 停止线程
  322. delete pair.second; // 删除线程
  323. pair.second = nullptr; // 设置为nullptr
  324. }
  325. }
  326. m_mapCompareDoubleThreads.clear();
  327. m_mapCDBUpdated.clear(); // 清空更新标志位
  328. SPDLOG_LOGGER_INFO(m_logger, "{} 对比线程销毁完成", m_logBase);
  329. }
  330. /* 创建计算音量报警的线程 */
  331. bool CompareItemThread::createCalculateDBThreads()
  332. {
  333. for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  334. {
  335. CalculateThreadInfo_t threadInfo;
  336. threadInfo.compareItemInfo.mapRoad.clear(); // 清空通道信息
  337. threadInfo.compareItemInfo.mapRoad.insert(road.nCompareRoadNum, road); // 添加当前通道
  338. threadInfo.threadState = EThreadState::State_Inited; // 初始化线程状态
  339. threadInfo.threadType = EThreadType::Type_CalculateDB;
  340. CalculateDBThread* pThread = new CalculateDBThread(threadInfo);
  341. if(pThread == nullptr)
  342. {
  343. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建音量计算线程失败", m_logBase);
  344. // return false; // 获取线程失败
  345. }
  346. CPPTP.add_task(&CalculateDBThread::threadTask, pThread);
  347. m_mapCalculateDBThreads.insert({road.nCompareRoadNum, pThread}); // 保存线程指针
  348. }
  349. return true;
  350. }
  351. /* 销毁音量计算的线程 */
  352. void CompareItemThread::destroyCalculateDBThreads()
  353. {
  354. if(m_mapCalculateDBThreads.size() == 0)
  355. {
  356. return; // 没有音量计算线程
  357. }
  358. SPDLOG_LOGGER_INFO(m_logger, "{} 销毁音量计算线程", m_logBase);
  359. for(auto& pair : m_mapCalculateDBThreads)
  360. {
  361. if(pair.second != nullptr)
  362. {
  363. pair.second->stopThreadBlock(); // 停止线程
  364. delete pair.second; // 删除线程
  365. pair.second = nullptr; // 设置为nullptr
  366. }
  367. }
  368. m_mapCalculateDBThreads.clear();
  369. m_mapCDBUpdated.clear(); // 清空更新标志位
  370. SPDLOG_LOGGER_INFO(m_logger, "{} 音量计算线程销毁完成", m_logBase);
  371. }
  372. /* 创建噪音检测线程 */
  373. void CompareItemThread::createNoiseDetectThreads()
  374. {
  375. for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  376. {
  377. CalculateThreadInfo_t threadInfo;
  378. threadInfo.compareItemInfo.mapRoad.clear(); // 清空通道信息
  379. threadInfo.compareItemInfo.mapRoad.insert(road.nCompareRoadNum, road); // 添加当前通道
  380. threadInfo.threadState = EThreadState::State_Inited; // 初始化线程状态
  381. threadInfo.threadType = EThreadType::Type_CalculateDB;
  382. NoiseDetectThread* pThread = new NoiseDetectThread(threadInfo);
  383. if(pThread == nullptr)
  384. {
  385. SPDLOG_LOGGER_ERROR(m_logger, "{} 创建噪音检测线程失败", m_logBase);
  386. return; // 获取线程失败
  387. }
  388. m_mapNoiseDetectThreads.insert({road.nCompareRoadNum, pThread});
  389. }
  390. }
  391. /* 销毁噪音检测线程 */
  392. void CompareItemThread::destroyNoiseDetectThreads()
  393. {
  394. if(m_mapNoiseDetectThreads.size() == 0)
  395. {
  396. return; // 没有噪音检测线程
  397. }
  398. SPDLOG_LOGGER_INFO(m_logger, "{} 销毁噪音检测线程", m_logBase);
  399. for(auto& pair : m_mapNoiseDetectThreads)
  400. {
  401. if(pair.second != nullptr)
  402. {
  403. pair.second->stopThreadBlock(); // 停止线程
  404. delete pair.second; // 删除线程
  405. pair.second = nullptr; // 设置为nullptr
  406. }
  407. }
  408. m_mapNoiseDetectThreads.clear();
  409. SPDLOG_LOGGER_INFO(m_logger, "{} 噪音检测线程销毁完成", m_logBase);
  410. }
  411. /* 获取噪音检测的线程 */
  412. // bool CompareItemThread::getNoiseDetectThreads()
  413. // {
  414. // for(const auto& road : m_threadInfo.compareItemInfo.mapRoad)
  415. // {
  416. // NoiseDetectThread* pThread = ThreadMan.getNoiseDetectThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID);
  417. // if(pThread == nullptr)
  418. // {
  419. // SPDLOG_LOGGER_ERROR(m_logger, "{} 获取噪音检测线程失败", m_logBase);
  420. // return false; // 获取线程失败
  421. // }
  422. // /* 向噪音检测线程写入对比项通道信息 */
  423. // pThread->startCompareItemNoiseAlarm(m_threadInfo.compareItemInfo.nID, m_threadInfo.compareItemInfo.strName, road);
  424. // m_mapNoiseDetectThreads.insert({road.nCompareRoadNum, pThread});
  425. // }
  426. // return true;
  427. // }
  428. /* 移除噪音检测的线程 */
  429. // void CompareItemThread::removeNoiseDetectThreads()
  430. // {
  431. // if(m_mapNoiseDetectThreads.size() == 0)
  432. // {
  433. // return; // 没有噪音检测线程
  434. // }
  435. // SPDLOG_LOGGER_INFO(m_logger, "{} 移除噪音检测线程", m_logBase);
  436. // for(auto& pair : m_mapNoiseDetectThreads)
  437. // {
  438. // if(pair.second != nullptr)
  439. // {
  440. // ThreadMan.removeNoiseDetectThread(pair.second->getRoadInfo(), m_threadInfo.compareItemInfo.nID);
  441. // }
  442. // }
  443. // m_mapNoiseDetectThreads.clear();
  444. // SPDLOG_LOGGER_INFO(m_logger, "{} 噪音检测线程移除完成", m_logBase);
  445. // }
  446. /**
  447. * @brief 更新数据
  448. * 更新数据逻辑:
  449. * 1、先从音量计算线程获取最新的音量包信息,如果没有全部更新,则等待下次获取,不进行后面的操作
  450. * 2、获取噪音检测线程的噪音信息和获取一致性信息的线程的结果无需关系是否是最新的
  451. *
  452. */
  453. bool CompareItemThread::updateResultData()
  454. {
  455. /* -------------------------------------------------------------------------------------
  456. * 先从音量计算数据中获取音量包信息和报警信息(静音、过载、反相)
  457. * ------------------------------------------------------------------------------------- */
  458. for(auto& pair : m_mapCDBUpdated)
  459. {
  460. if(pair.second == true)
  461. {
  462. /* 已经更新过了 */
  463. continue;
  464. }
  465. CalculateDBThread* pThread = m_mapCalculateDBThreads[pair.first];
  466. if(pThread == nullptr)
  467. {
  468. SPDLOG_LOGGER_ERROR(m_logger, "{} 音量计算线程失效", m_logBase);
  469. continue;
  470. }
  471. /* 获取最新的音量数据,包括静音、过载、反向等报警信息 */
  472. if(!pThread->getlastVolumeInfo(m_compareResult.mapRoadVolumes[pair.first]))
  473. {
  474. continue; // 没有获取到最新数据,继续等待
  475. }
  476. // const OneRoadVolume_t& volume = m_compareResult.mapRoadVolumes[pair.first];
  477. // for(int i = 0; i < VOLUME_INFO_NUM; ++i)
  478. // {
  479. // fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
  480. // }
  481. pair.second = true; // 设置更新标志位为true
  482. }
  483. /* 判断是否全部更新,如果没有则返回,等待下次再次获取 */
  484. for(auto& pair : m_mapCDBUpdated)
  485. {
  486. if(false == pair.second)
  487. {
  488. // SPDLOG_LOGGER_DEBUG(m_logger, "{} 音量计算线程数据未全部更新,等待下次获取", m_logBase);
  489. return false;
  490. }
  491. }
  492. /* -------------------------------------------------------------------------------------
  493. * 获取噪音计算的结果(从噪音对比线程中获取)
  494. * ------------------------------------------------------------------------------------- */
  495. for(auto& pair : m_mapNoiseDetectThreads)
  496. {
  497. NoiseDetectThread* pThread = pair.second;
  498. if(pThread == nullptr)
  499. {
  500. SPDLOG_LOGGER_ERROR(m_logger, "{} 噪音检测线程失效", m_logBase);
  501. continue; // 跳过这个线程
  502. }
  503. /* 获取最新的噪音数据,噪音报警那个标志位貌似没用到 */
  504. m_compareResult.mapRoadVolumes[pair.first].isNoise = pThread->isNoise();
  505. }
  506. /* -------------------------------------------------------------------------------------
  507. * 从对比项中获取核对过后的一致性结果
  508. * ------------------------------------------------------------------------------------- */
  509. for(auto& pair : m_mapCompareDoubleThreads)
  510. {
  511. CompareDoubleThread* pThread = pair.second;
  512. if(pThread == nullptr)
  513. {
  514. SPDLOG_LOGGER_ERROR(m_logger, "{} 一致性对比线程失效", m_logBase);
  515. continue;
  516. }
  517. /* 获取最新的一致性结果 */
  518. OneRoadVolume_t roadVolume;
  519. if(pThread->getlastResult(roadVolume))
  520. {
  521. m_compareResult.mapRoadVolumes[pair.first].isConsistency = roadVolume.isConsistency;
  522. m_compareResult.mapRoadVolumes[pair.first].isNotConsistencyWarning = roadVolume.isNotConsistencyWarning;
  523. }
  524. }
  525. // for(const auto& roadVolume : m_compareResult.mapRoadVolumes)
  526. // {
  527. // const OneRoadVolume_t& volume = roadVolume.second;
  528. // for(int i = 0; i < VOLUME_INFO_NUM; ++i)
  529. // {
  530. // fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
  531. // }
  532. // }
  533. return true;
  534. }
  535. /* 发送数据 */
  536. void CompareItemThread::sendResultData()
  537. {
  538. // for(const auto& roadVolume : m_compareResult.mapRoadVolumes)
  539. // {
  540. // const OneRoadVolume_t& volume = roadVolume.second;
  541. // for(int i = 0; i < VOLUME_INFO_NUM; ++i)
  542. // {
  543. // fmt::print("LDB:{}, RDB:{}\n", volume.vecleftDB[i], volume.vecrightDB[i]);
  544. // }
  545. // }
  546. if(m_pFromMQTT == nullptr)
  547. {
  548. SPDLOG_LOGGER_WARN(m_logger, "{} MQTT连接未初始化,无法发送数据", m_logBase);
  549. return;
  550. }
  551. if(m_pFromMQTT->connectState() != QMQTT::ConnectionState::STATE_CONNECTED)
  552. {
  553. SPDLOG_LOGGER_WARN(m_logger, "{} MQTT连接未成功,无法发送数据", m_logBase);
  554. return;
  555. }
  556. /* 生成json数据 */
  557. QByteArray jsonData;
  558. if(!generateMQTTJsonData(m_compareResult, jsonData))
  559. {
  560. SPDLOG_LOGGER_WARN(m_logger, "{} 生成音量包 JSON数据失败", m_logBase);
  561. return;
  562. }
  563. /* 发送到mqtt中 */
  564. int errorCode = 0;
  565. if(!m_pFromMQTT->sendMessage(m_pubTopic, jsonData, 0, errorCode))
  566. {
  567. SPDLOG_LOGGER_ERROR(m_logger, "{} 发送音量包数据到 {} 失败,错误代码: {}", m_logBase, m_pubTopic.toStdString(), errorCode);
  568. }else {
  569. SPDLOG_LOGGER_DEBUG(m_logger, "{} 发送音量包数据到 {} 成功", m_logBase, m_pubTopic.toStdString());
  570. }
  571. }
  572. /* 清除标志更新位 */
  573. void CompareItemThread::clearUpdateFlags()
  574. {
  575. for(auto& pair : m_mapCDBUpdated)
  576. {
  577. pair.second = false; // 清除更新标志位
  578. }
  579. }
  580. /* 生成发送至MQTT的JSON数据 */
  581. bool CompareItemThread::generateMQTTJsonData(const CompareResult_t& compareResult, QByteArray& jsonData)
  582. {
  583. try
  584. {
  585. /* 生成基础信息 */
  586. nJson json0;
  587. json0["compareItem_id"] = compareResult.compareItemID;
  588. json0["compareItem_name"] = compareResult.compareItemName.c_str();
  589. json0["date_time"] = compareResult.dateTime.toString("yyyy-MM-dd hh:mm:ss").toStdString();
  590. json0["is_client_alarm"] = compareResult.isClientAlarm;
  591. for(const auto& roadVolume : compareResult.mapRoadVolumes)
  592. {
  593. nJson json1;
  594. json1["soundCard_id"] = roadVolume.second.roadInfo.scRoadInfo.strSoundCardID.toStdString(); /* 声卡id和声卡通道id */
  595. json1["soundCard_road_id"] = roadVolume.second.roadInfo.scRoadInfo.roadInfo.nRoadNum;
  596. /* 对比项通道编号和名称 */
  597. json1["item_road_num"] = roadVolume.second.roadInfo.nCompareRoadNum;
  598. json1["item_road_name"] = roadVolume.second.roadInfo.strCompareRoadName.toStdString();
  599. json1["similarity"] = roadVolume.second.similarity;
  600. json1["is_silence"] = roadVolume.second.isSilence;
  601. json1["is_overload"] = roadVolume.second.isOverload;
  602. json1["is_reversed"] = roadVolume.second.isReversed;
  603. json1["is_noise"] = roadVolume.second.isNoise;
  604. json1["is_noise_warning"] = roadVolume.second.isNoiseWarning;
  605. json1["is_consistency"] = roadVolume.second.isConsistency;
  606. json1["is_not_consistency_warning"] = roadVolume.second.isNotConsistencyWarning;
  607. json1["left_real_time_db"] = roadVolume.second.leftRealTimeDB;
  608. json1["right_real_time_db"] = roadVolume.second.rightRealTimeDB;
  609. /* 添加音量包信息 */
  610. for(const auto& db : roadVolume.second.vecleftDB)
  611. {
  612. json1["left_db_array"].push_back(db);
  613. // fmt::print("left_db_array: {}\n", db);
  614. }
  615. for(const auto& db : roadVolume.second.vecrightDB)
  616. {
  617. json1["right_db_array"].push_back(db);
  618. // fmt::print("right_db_array: {}\n", db);
  619. }
  620. /* 添加到基础信息中 */
  621. json0["road_volumes"].push_back(json1);
  622. }
  623. /* 转换为字符串 */
  624. jsonData.clear();
  625. jsonData = QByteArray::fromStdString(json0.dump());
  626. }nJsonCatch
  627. return true;
  628. }
  629. /* 检查是否在检测时间段内,更新其他检测功能的检测时间,对比项是否启用由外部控制 */
  630. bool CompareItemThread::checkDetectPeriod()
  631. {
  632. QDateTime currentTime = QDateTime::currentDateTime();
  633. /* 2秒更新一次一致性检测时间 */
  634. if(m_lastDetectPeriodUpdateTime.secsTo(currentTime) < 2)
  635. {
  636. return true;
  637. }
  638. m_lastDetectPeriodUpdateTime = currentTime;
  639. std::lock_guard<std::mutex> lock(m_mutexDetectPeriod);
  640. int currentWeekday = currentTime.date().dayOfWeek(); // 获取当前星期几,1-7表示周日到周六
  641. QTime allDayTime;
  642. allDayTime.setHMS(0, 0, 0);
  643. /* 判断时段 */
  644. bool isInDetectPeriod = false;
  645. for(const auto& period : m_detectPeriod.listDetect)
  646. {
  647. /* 先判断是否有符合的周几 */
  648. if(static_cast<int>(period.weekType) == currentWeekday)
  649. {
  650. /* 判断一种特殊情况,开始时间和结束时间都是“00:00:00”,这个是全天都检测 */
  651. if(period.timeStart == allDayTime && period.timeEnd == allDayTime)
  652. {
  653. isInDetectPeriod = true;
  654. break;
  655. }
  656. /* 判断当前时间是否在检测时段内 */
  657. if(currentTime.time() >= period.timeStart && currentTime.time() <= period.timeEnd)
  658. {
  659. isInDetectPeriod = true;
  660. break;
  661. }
  662. }
  663. }
  664. /* 再判断是否在非检测时间段内 */
  665. for(const auto& period : m_detectPeriod.listNoDetect)
  666. {
  667. /* 先判断日期 */
  668. if(period.date == currentTime.date())
  669. {
  670. /* 判断当前时间是否在非检测时段内 */
  671. if(currentTime.time() >= period.timeStart && currentTime.time() <= period.timeEnd)
  672. {
  673. isInDetectPeriod = false; // 在非检测时段内,不进行检测
  674. break;
  675. }
  676. }
  677. }
  678. /* 应用于对比项检测,对比项不设置日期不会进行检测 */
  679. for(auto& pThread : m_mapCompareDoubleThreads)
  680. {
  681. pThread.second->setInDetectPeriod(isInDetectPeriod);
  682. }
  683. /* 判断是否应用于静音、过载、反相检测 */
  684. for(auto& pThread : m_mapCalculateDBThreads)
  685. {
  686. if(m_detectPeriod.isApplySlient)
  687. {
  688. pThread.second->setSilenceInDetectPeriod(isInDetectPeriod);
  689. }else {
  690. /* 没有应用于静音检测,就一直检测 */
  691. pThread.second->setSilenceInDetectPeriod(true);
  692. }
  693. if(m_detectPeriod.isApplyOverload)
  694. {
  695. pThread.second->setOverloadInDetectPeriod(isInDetectPeriod);
  696. } else {
  697. /* 没有应用于过载检测,就一直检测 */
  698. pThread.second->setOverloadInDetectPeriod(true);
  699. }
  700. if(m_detectPeriod.isApplyPhase)
  701. {
  702. pThread.second->setPhaseInDetectPeriod(isInDetectPeriod);
  703. }else
  704. {
  705. /* 没有应用于反相检测,就一直检测 */
  706. pThread.second->setPhaseInDetectPeriod(true);
  707. }
  708. }
  709. /* 应用于噪音检测 */
  710. for(auto& pThread : m_mapNoiseDetectThreads)
  711. {
  712. if(m_detectPeriod.isApplyNoise)
  713. {
  714. pThread.second->setInDetectPeriod(isInDetectPeriod);
  715. }else
  716. {
  717. /* 没有应用于噪音检测,就一直检测 */
  718. pThread.second->setInDetectPeriod(true);
  719. }
  720. }
  721. return true;
  722. }