Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

InstNetwork.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. // =STS=> InstNetwork.cpp[2732].aa08 open SMID:8
  2. //////////////////////////////////////////////////////////////////////////////
  3. //
  4. // (c) Copyright 2010 - 2011 Blackrock Microsystems
  5. //
  6. // $Workfile: InstNetwork.cpp $
  7. // $Archive: /common/InstNetwork.cpp $
  8. // $Revision: 1 $
  9. // $Date: 3/15/10 12:21a $
  10. // $Author: Ehsan $
  11. //
  12. // $NoKeywords: $
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. //
  16. // PURPOSE:
  17. //
  18. // Common xPlatform instrument network
  19. //
  20. #include "StdAfx.h"
  21. #include <algorithm> // Use C++ default min and max implementation.
  22. #include "InstNetwork.h"
  23. #ifndef WIN32
  24. #include <semaphore.h>
  25. #endif
  26. const uint32_t InstNetwork::MAX_NUM_OF_PACKETS_TO_PROCESS_PER_PASS = 5000; // This is not exported correctly unless redefined here.
  27. // Author & Date: Ehsan Azar 15 March 2010
  28. // Purpose: Constructor for instrument networking thread
  29. InstNetwork::InstNetwork(STARTUP_OPTIONS startupOption) :
  30. QThread(),
  31. m_enLOC(LOC_LOW),
  32. m_nStartupOptionsFlags(startupOption),
  33. m_timerTicks(0),
  34. m_timerId(0),
  35. m_bDone(false),
  36. m_nRecentPacketCount(0),
  37. m_dataCounter(0),
  38. m_nLastNumberOfPacketsReceived(0),
  39. m_runlevel(cbRUNLEVEL_SHUTDOWN),
  40. m_bStandAlone(true),
  41. m_instInfo(0),
  42. m_nInstance(0),
  43. m_nIdx(0),
  44. m_nInPort(NSP_IN_PORT),
  45. m_nOutPort(NSP_OUT_PORT),
  46. m_bBroadcast(false),
  47. m_bDontRoute(true),
  48. m_bNonBlocking(true),
  49. m_nRecBufSize(NSP_REC_BUF_SIZE),
  50. m_strInIP(NSP_IN_ADDRESS),
  51. m_strOutIP(NSP_OUT_ADDRESS)
  52. {
  53. qRegisterMetaType<NetEventType>("NetEventType"); // For QT connect to recognize this type
  54. qRegisterMetaType<NetCommandType>("NetCommandType"); // For QT connect to recognize this type
  55. // This should be the last
  56. moveToThread(this); // The object could not be moved if it had a parent
  57. }
  58. // Author & Date: Ehsan Azar 15 March 2010
  59. // Purpose: Open the instrument network
  60. // Inputs:
  61. // listener - the instrument listener of packets and events
  62. void InstNetwork::Open(Listener * listener)
  63. {
  64. if (listener)
  65. m_listener += listener;
  66. }
  67. // Author & Date: Ehsan Azar 23 Sept 2010
  68. // Purpose: Shut down the instrument network
  69. void InstNetwork::ShutDown()
  70. {
  71. if (m_bStandAlone)
  72. m_icInstrument.Shutdown();
  73. else
  74. cbSetSystemRunLevel(cbRUNLEVEL_SHUTDOWN, 0, 0, m_nInstance);
  75. }
  76. // Author & Date: Ehsan Azar 23 Sept 2010
  77. // Purpose: Standby the instrument network
  78. void InstNetwork::StandBy()
  79. {
  80. if (m_bStandAlone)
  81. m_icInstrument.Standby();
  82. else
  83. cbSetSystemRunLevel(cbRUNLEVEL_HARDRESET, 0, 0, m_nInstance);
  84. }
  85. // Author & Date: Ehsan Azar 15 March 2010
  86. // Purpose: Close the instrument network
  87. void InstNetwork::Close()
  88. {
  89. // Signal thread to finish
  90. m_bDone = true;
  91. // Wait for thread to finish
  92. if (QThread::currentThread() != thread())
  93. wait();
  94. }
  95. // Author & Date: Ehsan Azar 14 Feb 2012
  96. // Purpose: Specific network commands to handle as Qt slots
  97. // Inputs:
  98. // cmd - network command to perform
  99. // code - additional argument for the command
  100. void InstNetwork::OnNetCommand(NetCommandType cmd, unsigned int /*code*/)
  101. {
  102. switch (cmd)
  103. {
  104. case NET_COMMAND_NONE:
  105. // Do nothing
  106. break;
  107. case NET_COMMAND_OPEN:
  108. start(QThread::TimeCriticalPriority);
  109. break;
  110. case NET_COMMAND_CLOSE:
  111. Close();
  112. break;
  113. case NET_COMMAND_STANDBY:
  114. StandBy();
  115. break;
  116. case NET_COMMAND_SHUTDOWN:
  117. ShutDown();
  118. break;
  119. }
  120. }
  121. // Author & Date: Ehsan Azar 24 June 2010
  122. // Purpose: Some packets coming from the stand-alone instrument network need
  123. // to be processed for any listener application.
  124. // then ask the network listener for more process.
  125. // Inputs:
  126. // pPkt - pointer to the packet
  127. void InstNetwork::ProcessIncomingPacket(const cbPKT_GENERIC * const pPkt)
  128. {
  129. // -------- Process some incoming packet here -----------
  130. // check for configuration class packets
  131. if (pPkt->chid & 0x8000)
  132. {
  133. // Check for configuration packets
  134. if (pPkt->chid == 0x8000)
  135. {
  136. if ((pPkt->type & 0xF0) == cbPKTTYPE_CHANREP)
  137. {
  138. if (m_bStandAlone)
  139. {
  140. const cbPKT_CHANINFO * pNew = reinterpret_cast<const cbPKT_CHANINFO *>(pPkt);
  141. uint32_t chan = pNew->chan;
  142. if (chan > 0 && chan <= cbMAXCHANS)
  143. {
  144. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->chaninfo[chan - 1]), pPkt, sizeof(cbPKT_CHANINFO));
  145. if (pPkt->type == cbPKTTYPE_CHANREP)
  146. {
  147. // Invalidate the cache
  148. if (chan <= cbNUM_ANALOG_CHANS)
  149. cb_spk_buffer_ptr[m_nIdx]->cache[chan - 1].valid = 0;
  150. }
  151. }
  152. }
  153. }
  154. else if ((pPkt->type & 0xF0) == cbPKTTYPE_SYSREP)
  155. {
  156. const cbPKT_SYSINFO * pNew = reinterpret_cast<const cbPKT_SYSINFO *>(pPkt);
  157. if (m_bStandAlone)
  158. {
  159. cbPKT_SYSINFO & rOld = cb_cfg_buffer_ptr[m_nIdx]->sysinfo;
  160. // replace our copy with this one
  161. rOld = *pNew;
  162. }
  163. // Rely on the fact that sysrep must be the last config packet sent via NSP6.04 and upwards
  164. if (pPkt->type == cbPKTTYPE_SYSREP)
  165. {
  166. // Any change to the instrument will be reported here, including initial connection as stand-alone
  167. uint32_t instInfo;
  168. cbGetInstInfo(&instInfo, m_nInstance);
  169. // If instrument connection state has changed
  170. if (instInfo != m_instInfo)
  171. {
  172. m_instInfo = instInfo;
  173. InstNetworkEvent(NET_EVENT_INSTINFO, instInfo);
  174. }
  175. }
  176. else if (pPkt->type == cbPKTTYPE_SYSREPRUNLEV)
  177. {
  178. if (pNew->runlevel == cbRUNLEVEL_HARDRESET)
  179. {
  180. // If any app did a hard reset which is not the initial reset
  181. // Application should decide what to do on reset
  182. if (!m_bStandAlone || (m_bStandAlone && pPkt->time > 500))
  183. InstNetworkEvent(NET_EVENT_RESET);
  184. }
  185. else if (pNew->runlevel == cbRUNLEVEL_RUNNING)
  186. {
  187. if (pNew->runflags & cbRUNFLAGS_LOCK)
  188. {
  189. InstNetworkEvent(NET_EVENT_LOCKEDRESET);
  190. }
  191. }
  192. }
  193. }
  194. else if (pPkt->type == cbPKTTYPE_GROUPREP)
  195. {
  196. if (m_bStandAlone)
  197. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->groupinfo[0][((cbPKT_GROUPINFO*)pPkt)->group-1]), pPkt, sizeof(cbPKT_GROUPINFO));
  198. }
  199. else if (pPkt->type == cbPKTTYPE_FILTREP)
  200. {
  201. if (m_bStandAlone)
  202. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->filtinfo[0][((cbPKT_FILTINFO*)pPkt)->filt-1]), pPkt, sizeof(cbPKT_FILTINFO));
  203. }
  204. else if (pPkt->type == cbPKTTYPE_PROCREP)
  205. {
  206. if (m_bStandAlone)
  207. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->procinfo[0]), pPkt, sizeof(cbPKT_PROCINFO));
  208. }
  209. else if (pPkt->type == cbPKTTYPE_BANKREP)
  210. {
  211. if (m_bStandAlone)
  212. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->bankinfo[0][((cbPKT_BANKINFO*)pPkt)->bank-1]), pPkt, sizeof(cbPKT_BANKINFO));
  213. }
  214. else if (pPkt->type == cbPKTTYPE_ADAPTFILTREP)
  215. {
  216. if (m_bStandAlone)
  217. cb_cfg_buffer_ptr[m_nIdx]->adaptinfo = *reinterpret_cast<const cbPKT_ADAPTFILTINFO *>(pPkt);
  218. }
  219. else if (pPkt->type == cbPKTTYPE_REFELECFILTREP)
  220. {
  221. if (m_bStandAlone)
  222. cb_cfg_buffer_ptr[m_nIdx]->refelecinfo = *reinterpret_cast<const cbPKT_REFELECFILTINFO *>(pPkt);
  223. }
  224. else if (pPkt->type == cbPKTTYPE_SS_MODELREP)
  225. {
  226. if (m_bStandAlone)
  227. {
  228. cbPKT_SS_MODELSET rNew = *reinterpret_cast<const cbPKT_SS_MODELSET*>(pPkt);
  229. UpdateSortModel(rNew);
  230. }
  231. }
  232. else if (pPkt->type == cbPKTTYPE_SS_STATUSREP)
  233. {
  234. if (m_bStandAlone)
  235. {
  236. cbPKT_SS_STATUS rNew = *reinterpret_cast<const cbPKT_SS_STATUS*>(pPkt);
  237. cbPKT_SS_STATUS & rOld = cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.pktStatus;
  238. rOld = rNew;
  239. }
  240. }
  241. else if (pPkt->type == cbPKTTYPE_SS_DETECTREP)
  242. {
  243. if (m_bStandAlone)
  244. {
  245. // replace our copy with this one
  246. cbPKT_SS_DETECT rNew = *reinterpret_cast<const cbPKT_SS_DETECT*>(pPkt);
  247. cbPKT_SS_DETECT & rOld = cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.pktDetect;
  248. rOld = rNew;
  249. }
  250. }
  251. else if (pPkt->type == cbPKTTYPE_SS_ARTIF_REJECTREP)
  252. {
  253. if (m_bStandAlone)
  254. {
  255. // replace our copy with this one
  256. cbPKT_SS_ARTIF_REJECT rNew = *reinterpret_cast<const cbPKT_SS_ARTIF_REJECT*>(pPkt);
  257. cbPKT_SS_ARTIF_REJECT & rOld = cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.pktArtifReject;
  258. rOld = rNew;
  259. }
  260. }
  261. else if (pPkt->type == cbPKTTYPE_SS_NOISE_BOUNDARYREP)
  262. {
  263. if (m_bStandAlone)
  264. {
  265. // replace our copy with this one
  266. cbPKT_SS_NOISE_BOUNDARY rNew = *reinterpret_cast<const cbPKT_SS_NOISE_BOUNDARY*>(pPkt);
  267. cbPKT_SS_NOISE_BOUNDARY & rOld = cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.pktNoiseBoundary[rNew.chan - 1];
  268. rOld = rNew;
  269. }
  270. }
  271. else if (pPkt->type == cbPKTTYPE_SS_STATISTICSREP)
  272. {
  273. if (m_bStandAlone)
  274. {
  275. // replace our copy with this one
  276. cbPKT_SS_STATISTICS rNew = *reinterpret_cast<const cbPKT_SS_STATISTICS*>(pPkt);
  277. cbPKT_SS_STATISTICS & rOld = cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.pktStatistics;
  278. rOld = rNew;
  279. }
  280. }
  281. else if (pPkt->type == cbPKTTYPE_FS_BASISREP)
  282. {
  283. if (m_bStandAlone)
  284. {
  285. cbPKT_FS_BASIS rPkt = *reinterpret_cast<const cbPKT_FS_BASIS*>(pPkt);
  286. UpdateBasisModel(rPkt);
  287. }
  288. }
  289. else if (pPkt->type == cbPKTTYPE_LNCREP)
  290. {
  291. if (m_bStandAlone)
  292. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->isLnc), pPkt, sizeof(cbPKT_LNC));
  293. // For 6.03 and before, use this packet instead of sysrep for instinfo event
  294. }
  295. else if (pPkt->type == cbPKTTYPE_REPFILECFG)
  296. {
  297. if (m_bStandAlone)
  298. {
  299. const cbPKT_FILECFG * pPktFileCfg = reinterpret_cast<const cbPKT_FILECFG*>(pPkt);
  300. if (pPktFileCfg->options == cbFILECFG_OPT_REC || pPktFileCfg->options == cbFILECFG_OPT_STOP)
  301. {
  302. cb_cfg_buffer_ptr[m_nIdx]->fileinfo = * reinterpret_cast<const cbPKT_FILECFG *>(pPkt);
  303. }
  304. }
  305. }
  306. else if (pPkt->type == cbPKTTYPE_REPNTRODEINFO)
  307. {
  308. if (m_bStandAlone)
  309. memcpy(&(cb_cfg_buffer_ptr[m_nIdx]->isLnc), pPkt, sizeof(cbPKT_LNC));
  310. }
  311. else if (pPkt->type == cbPKTTYPE_NMREP)
  312. {
  313. if (m_bStandAlone)
  314. {
  315. const cbPKT_NM * pPktNm = reinterpret_cast<const cbPKT_NM *>(pPkt);
  316. // video source to go to the file header
  317. if (pPktNm->mode == cbNM_MODE_SETVIDEOSOURCE)
  318. {
  319. if (pPktNm->flags > 0 && pPktNm->flags <= cbMAXVIDEOSOURCE)
  320. {
  321. memcpy(cb_cfg_buffer_ptr[m_nIdx]->isVideoSource[pPktNm->flags - 1].name, pPktNm->name, cbLEN_STR_LABEL);
  322. cb_cfg_buffer_ptr[m_nIdx]->isVideoSource[pPktNm->flags - 1].fps = ((float)pPktNm->value) / 1000;
  323. // fps>0 means valid video source
  324. }
  325. }
  326. // trackable object to go to the file header
  327. else if (pPktNm->mode == cbNM_MODE_SETTRACKABLE)
  328. {
  329. if (pPktNm->flags > 0 && pPktNm->flags <= cbMAXTRACKOBJ)
  330. {
  331. memcpy(cb_cfg_buffer_ptr[m_nIdx]->isTrackObj[pPktNm->flags - 1].name, pPktNm->name, cbLEN_STR_LABEL);
  332. cb_cfg_buffer_ptr[m_nIdx]->isTrackObj[pPktNm->flags - 1].type = (uint16_t)(pPktNm->value & 0xff);
  333. cb_cfg_buffer_ptr[m_nIdx]->isTrackObj[pPktNm->flags - 1].pointCount = (uint16_t)((pPktNm->value >> 16) & 0xff);
  334. // type>0 means valid trackable
  335. }
  336. }
  337. // nullify all tracking upon NM exit
  338. else if (pPktNm->mode == cbNM_MODE_STATUS && pPktNm->value == cbNM_STATUS_EXIT)
  339. {
  340. memset(cb_cfg_buffer_ptr[m_nIdx]->isTrackObj, 0, sizeof(cb_cfg_buffer_ptr[m_nIdx]->isTrackObj));
  341. memset(cb_cfg_buffer_ptr[m_nIdx]->isVideoSource, 0, sizeof(cb_cfg_buffer_ptr[m_nIdx]->isVideoSource));
  342. }
  343. }
  344. }
  345. else if (pPkt->type == cbPKTTYPE_WAVEFORMREP)
  346. {
  347. if (m_bStandAlone)
  348. {
  349. const cbPKT_AOUT_WAVEFORM * pPktAoutWave = reinterpret_cast<const cbPKT_AOUT_WAVEFORM *>(pPkt);
  350. uint16_t nChan = pPktAoutWave->chan;
  351. if (nChan > cbFIRST_ANAOUT_CHAN)
  352. {
  353. nChan -= (cbFIRST_ANAOUT_CHAN + 1);
  354. if (nChan < AOUT_NUM_GAIN_CHANS)
  355. {
  356. uint8_t trigNum = pPktAoutWave->trigNum;
  357. if (trigNum < cbMAX_AOUT_TRIGGER)
  358. cb_cfg_buffer_ptr[m_nIdx]->isWaveform[nChan][trigNum] = *pPktAoutWave;
  359. }
  360. }
  361. }
  362. }
  363. else if (pPkt->type == cbPKTTYPE_NPLAYREP)
  364. {
  365. if (m_bStandAlone)
  366. {
  367. const cbPKT_NPLAY * pNew = reinterpret_cast<const cbPKT_NPLAY *>(pPkt);
  368. // Only store the main config packet in stand-alone mode
  369. if (pNew->flags == cbNPLAY_FLAG_MAIN)
  370. {
  371. cbPKT_NPLAY & rOld = cb_cfg_buffer_ptr[m_nIdx]->isNPlay;
  372. // replace our copy with this one
  373. rOld = *pNew;
  374. }
  375. }
  376. }
  377. } // end if (pPkt->chid==0x8000
  378. } // end if (pPkt->chid & 0x8000
  379. else if ( (pPkt->chid > 0) && (pPkt->chid < cbPKT_SPKCACHELINECNT) )
  380. {
  381. if (m_bStandAlone)
  382. {
  383. // post the packet to the cache buffer
  384. memcpy( &(cb_spk_buffer_ptr[m_nIdx]->cache[pPkt->chid - 1].spkpkt[cb_spk_buffer_ptr[m_nIdx]->cache[pPkt->chid - 1].head]),
  385. pPkt, (pPkt->dlen + cbPKT_HEADER_32SIZE) * 4);
  386. // increment the valid pointer
  387. cb_spk_buffer_ptr[m_nIdx]->cache[pPkt->chid - 1].valid++;
  388. // increment the head pointer of the packet and check for wraparound
  389. uint32_t head = cb_spk_buffer_ptr[m_nIdx]->cache[(pPkt->chid)-1].head + 1;
  390. if (head >= cbPKT_SPKCACHEPKTCNT)
  391. head = 0;
  392. cb_spk_buffer_ptr[m_nIdx]->cache[pPkt->chid - 1].head = head;
  393. }
  394. }
  395. // -- Process the incoming packet inside the listeners --
  396. for (int i = 0; i < m_listener.count(); ++i)
  397. m_listener[i]->ProcessIncomingPacket(pPkt);
  398. }
  399. // Author & Date: Kirk Korver 25 Apr 2005
  400. // Purpose: update our sorting model
  401. // Inputs:
  402. // rUnitModel - the unit model packet of interest
  403. inline void InstNetwork::UpdateSortModel(const cbPKT_SS_MODELSET & rUnitModel)
  404. {
  405. uint32_t nChan = rUnitModel.chan;
  406. uint32_t nUnit = rUnitModel.unit_number;
  407. // Unit 255 == noise, put it into the last slot
  408. if (nUnit == 255)
  409. nUnit = ARRAY_SIZE(cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.asSortModel[0]) - 1;
  410. if (cb_library_initialized[m_nIdx] && cb_cfg_buffer_ptr[m_nIdx])
  411. cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.asSortModel[nChan][nUnit] = rUnitModel;
  412. }
  413. // Author & Date: Hyrum L. Sessions 21 Apr 2009
  414. // Purpose: update our PCA basis model
  415. // Inputs:
  416. // rBasisModel - the basis model packet of interest
  417. inline void InstNetwork::UpdateBasisModel(const cbPKT_FS_BASIS & rBasisModel)
  418. {
  419. if (0 == rBasisModel.chan)
  420. return; // special packet request to get all basis, don't save it
  421. uint32_t nChan = rBasisModel.chan - 1;
  422. if (cb_library_initialized[m_nIdx] && cb_cfg_buffer_ptr[m_nIdx])
  423. cb_cfg_buffer_ptr[m_nIdx]->isSortingOptions.asBasis[nChan] = rBasisModel;
  424. }
  425. /////////////////////////////////////////////////////////////////////////////
  426. // Author & Date: Kirk Korver 07 Jan 2003
  427. // Purpose: do any processing necessary to test for link failure (i.e. wire disconnected)
  428. // Inputs:
  429. // nTicks - the ever growing number of times that the mmtimer has been called
  430. // rParent - the parent window
  431. // nCurrentPacketCount - the number of packets that we have ever received
  432. inline void InstNetwork::CheckForLinkFailure(uint32_t nTicks, uint32_t nCurrentPacketCount)
  433. {
  434. if ((nTicks % 250) == 0) // Check every 2.5 seconds
  435. {
  436. if (m_nLastNumberOfPacketsReceived != nCurrentPacketCount)
  437. {
  438. m_nLastNumberOfPacketsReceived = nCurrentPacketCount;
  439. }
  440. else
  441. {
  442. InstNetworkEvent(NET_EVENT_LINKFAILURE);
  443. }
  444. }
  445. }
  446. // Author & Date: Ehsan Azar 15 March 2010
  447. // Purpose: Networking timer timeout function
  448. // Inputs:
  449. // event - QT timer event for networking
  450. void InstNetwork::timerEvent(QTimerEvent * /*event*/)
  451. {
  452. m_timerTicks++; // number of intervals
  453. int burstcount = 0;
  454. int recv_returned = 0;
  455. int time_factor = 10; // we let the timer execute more often. as a result, we need to adjust timing to
  456. // get configuration at startup right
  457. if (m_bDone)
  458. {
  459. if (m_timerId)
  460. {
  461. killTimer(m_timerId);
  462. m_timerId = 0;
  463. }
  464. quit();
  465. return;
  466. }
  467. /////////////////////////////////////////
  468. // below 5 seconds, call startup routines
  469. if (m_timerTicks < 500 * time_factor)
  470. {
  471. // at time 0 request sysinfo
  472. if (m_timerTicks == 1)
  473. {
  474. InstNetworkEvent(NET_EVENT_INSTCONNECTING);
  475. cbSetSystemRunLevel(cbRUNLEVEL_RUNNING, 0, 0, m_nInstance);
  476. }
  477. // at 0.5 seconds, reset the hardware
  478. else if (m_timerTicks == 50 * time_factor)
  479. {
  480. // get runlevel
  481. cbGetSystemRunLevel(&m_runlevel, NULL, NULL, m_nInstance);
  482. // if not running reset
  483. if (cbRUNLEVEL_RUNNING != m_runlevel)
  484. {
  485. InstNetworkEvent(NET_EVENT_INSTHARDRESET);
  486. cbSetSystemRunLevel(cbRUNLEVEL_HARDRESET, 0, 0, m_nInstance);
  487. }
  488. }
  489. // at 1.0 seconds, retreive the hardware config
  490. else if (m_timerTicks == 100 * time_factor)
  491. {
  492. InstNetworkEvent(NET_EVENT_INSTCONFIG);
  493. cbPKT_GENERIC pktgeneric;
  494. pktgeneric.time = 1;
  495. pktgeneric.chid = 0x8000;
  496. pktgeneric.type = cbPKTTYPE_REQCONFIGALL;
  497. pktgeneric.dlen = 0;
  498. cbSendPacket(&pktgeneric, m_nInstance);
  499. }
  500. // at 2.0 seconds, start running
  501. else if (m_timerTicks == 200 * time_factor)
  502. {
  503. InstNetworkEvent(NET_EVENT_INSTRUN); // going to soft reset and run
  504. // if already running do not reset, otherwise reset
  505. if (cbRUNLEVEL_RUNNING != m_runlevel)
  506. {
  507. cbSetSystemRunLevel(cbRUNLEVEL_RESET, 0, 0, m_nInstance);
  508. }
  509. }
  510. } // end if (m_timerTicks < 500 * time_factor
  511. if (m_icInstrument.Tick())
  512. {
  513. InstNetworkEvent(NET_EVENT_PCTONSPLOST);
  514. m_bDone = true;
  515. }
  516. // Check for link failure because we always have heartbeat packets
  517. if (!(m_instInfo & cbINSTINFO_NPLAY))
  518. CheckForLinkFailure(m_timerTicks, cb_rec_buffer_ptr[m_nIdx]->received);
  519. // Process 1024 remaining packets
  520. while (burstcount < 1024)
  521. {
  522. bool bLoopbackPacket = false;
  523. burstcount++;
  524. recv_returned = m_icInstrument.Recv(&(cb_rec_buffer_ptr[m_nIdx]->buffer[cb_rec_buffer_ptr[m_nIdx]->headindex]));
  525. if (recv_returned <= 0)
  526. {
  527. // If the real instrument doesn't work, then try the fake one
  528. recv_returned = m_icInstrument.Recv(&(cb_rec_buffer_ptr[m_nIdx]->buffer[cb_rec_buffer_ptr[m_nIdx]->headindex]));
  529. if (recv_returned <= 0)
  530. break; // No data returned
  531. bLoopbackPacket = true;
  532. }
  533. // get pointer to the first packet in received data block
  534. cbPKT_GENERIC *pktptr = (cbPKT_GENERIC*) &(cb_rec_buffer_ptr[m_nIdx]->buffer[cb_rec_buffer_ptr[m_nIdx]->headindex]);
  535. uint32_t bytes_to_process = recv_returned;
  536. do {
  537. if (bLoopbackPacket)
  538. {
  539. // Put fake packets in-order
  540. pktptr->time = cb_rec_buffer_ptr[m_nIdx]->lasttime;
  541. } else {
  542. ++m_nRecentPacketCount; // only count the "real" packets, not loopback ones
  543. m_icInstrument.TestForReply(pktptr); // loopbacks won't need a "reply"...they are never sent
  544. }
  545. // make sure that the next packet in the data block that we are processing fits.
  546. uint32_t quadlettotal = (pktptr->dlen) + 2;
  547. uint32_t packetsize = quadlettotal << 2;
  548. if (packetsize > bytes_to_process)
  549. {
  550. // TODO: complain about bad packet
  551. break;
  552. }
  553. // update time index
  554. cb_rec_buffer_ptr[m_nIdx]->lasttime = pktptr->time;
  555. // Do incoming packet process
  556. ProcessIncomingPacket(pktptr);
  557. // increment packet pointer and subract out the packetsize from the processing counter
  558. pktptr = (cbPKT_GENERIC*) (((BYTE*) pktptr) + packetsize);
  559. bytes_to_process -= packetsize;
  560. // Increment head index and check for buffer wraparound.
  561. // If the currently processed packet extends at all within the last 1k of the circular
  562. // recording buffer, wrap the head pointer around to zero. This is the same mechanism
  563. // that the client applications that read the buffer use to update their tail pointers.
  564. cb_rec_buffer_ptr[m_nIdx]->headindex += quadlettotal;
  565. if ((cb_rec_buffer_ptr[m_nIdx]->headindex) > (cbRECBUFFLEN - (cbCER_UDP_SIZE_MAX / 4)))
  566. {
  567. // rewind the circular buffer head pointer and increment the headwrap count
  568. cb_rec_buffer_ptr[m_nIdx]->headwrap++;
  569. cb_rec_buffer_ptr[m_nIdx]->headindex = 0;
  570. // Since multiple Cerebus packets can be contained within a single UDP packet,
  571. // a few Cerebus packets may be extended beyond the bound of the currently
  572. // processed packet. These need to be copied (wrapped) around to the beginning
  573. // of the circular buffer so that they are not dropped.
  574. if (bytes_to_process > 0)
  575. {
  576. // copy the remaining packet bytes
  577. memcpy(&(cb_rec_buffer_ptr[m_nIdx]->buffer[0]), pktptr,
  578. bytes_to_process);
  579. // wrap the internal packet pointer
  580. pktptr = (cbPKT_GENERIC*) &(cb_rec_buffer_ptr[m_nIdx]->buffer[0]);
  581. }
  582. }
  583. // increment the packets received and data exchanged counters
  584. cb_rec_buffer_ptr[m_nIdx]->received++;
  585. m_dataCounter += quadlettotal;
  586. } while (bytes_to_process); // end do
  587. } // end while (burstcount
  588. // check for receive errors
  589. if (recv_returned < 0)
  590. {
  591. // Complain
  592. }
  593. //////////////////////////////////////////////////////////////////////////////////////////////////////
  594. // Check for and process outgoing packets
  595. //
  596. // This routine roughly executes every 10ms. In order to prevent the NSP from being overloaded by
  597. // floods of configuration packets, throttle the configuration packets bursts per 10ms.
  598. {
  599. // UINT nPacketsLeftInBurst = 16;
  600. //
  601. // The line above was in use for a while. It appears that sometimes a packet from the PC->NSP
  602. // will be dropped. By reducing the possible number of packets that can be sent at a time, we
  603. // appear to not have this problem any more. The real solution is to ensure that packets are sent
  604. UINT nPacketsLeftInBurst = 4;
  605. cbPKT_GENERIC
  606. *xmtpacket =
  607. (cbPKT_GENERIC*) &(cb_xmt_global_buffer_ptr[m_nIdx]->buffer[cb_xmt_global_buffer_ptr[m_nIdx]->tailindex]);
  608. while ((xmtpacket->time) && (nPacketsLeftInBurst--))
  609. {
  610. // find the length of the packet
  611. uint32_t quadlettotal = (xmtpacket->dlen) + 2;
  612. if (m_icInstrument.OkToSend() == false)
  613. continue;
  614. // transmit the packet
  615. m_icInstrument.Send(xmtpacket);
  616. // complete the packet processing by clearing the packet from the xmt buffer
  617. memset(xmtpacket, 0, quadlettotal << 2);
  618. cb_xmt_global_buffer_ptr[m_nIdx]->transmitted++;
  619. cb_xmt_global_buffer_ptr[m_nIdx]->tailindex += quadlettotal;
  620. m_dataCounter += quadlettotal;
  621. if (cb_xmt_global_buffer_ptr[m_nIdx]->tailindex
  622. > cb_xmt_global_buffer_ptr[m_nIdx]->last_valid_index)
  623. {
  624. cb_xmt_global_buffer_ptr[m_nIdx]->tailindex = 0;
  625. }
  626. // update the local reference pointer
  627. xmtpacket = (cbPKT_GENERIC*) &(cb_xmt_global_buffer_ptr[m_nIdx]->buffer[cb_xmt_global_buffer_ptr[m_nIdx]->tailindex]);
  628. }
  629. }
  630. // Signal the other apps that new data is available
  631. #ifdef WIN32
  632. PulseEvent(cb_sig_event_hnd[m_nIdx]);
  633. #else
  634. sem_post((sem_t *)cb_sig_event_hnd[m_nIdx]);
  635. #endif
  636. }
  637. // Author & Date: Ehsan Azar 15 March 2010
  638. // Purpose: The thread function
  639. void InstNetwork::run()
  640. {
  641. // No instrument yet
  642. m_instInfo = 0;
  643. // Start initializing instrument network
  644. InstNetworkEvent(NET_EVENT_INIT);
  645. if (m_listener.count() == 0)
  646. {
  647. // If listener not set
  648. InstNetworkEvent(NET_EVENT_LISTENERERR);
  649. return;
  650. }
  651. m_nIdx = cb_library_index[m_nInstance];
  652. // Open the cbhwlib library and create the shared objects
  653. cbRESULT cbRet = cbOpen(FALSE, m_nInstance);
  654. if (cbRet == cbRESULT_OK)
  655. {
  656. m_nIdx = cb_library_index[m_nInstance];
  657. m_bStandAlone = false;
  658. InstNetworkEvent(NET_EVENT_NETCLIENT); // Client to the Central application
  659. } else if (cbRet == cbRESULT_NOCENTRALAPP) { // If Central is not running run as stand alone
  660. m_bStandAlone = true; // Run stand alone without Central
  661. // Run as stand-alone application
  662. cbRet = cbOpen(TRUE, m_nInstance);
  663. if (cbRet)
  664. {
  665. InstNetworkEvent(NET_EVENT_CBERR, cbRet); // report cbRESULT
  666. return;
  667. }
  668. m_nIdx = cb_library_index[m_nInstance];
  669. InstNetworkEvent(NET_EVENT_NETSTANDALONE); // Stand-alone application
  670. } else {
  671. // Report error and quit
  672. InstNetworkEvent(NET_EVENT_CBERR, cbRet);
  673. return;
  674. }
  675. STARTUP_OPTIONS startupOption = m_nStartupOptionsFlags;
  676. // If non-stand-alone just being local can be detected at this stage
  677. // because the network is not yet running.
  678. cbGetInstInfo(&m_instInfo, m_nInstance);
  679. if (m_instInfo & cbINSTINFO_LOCAL)
  680. {
  681. // if local instrument detected
  682. startupOption = OPT_LOCAL; // Override startup option
  683. }
  684. // If stand-alone network
  685. if (m_bStandAlone)
  686. {
  687. // Give nPlay and Cereplex more time
  688. bool bHighLatency = (m_instInfo & (cbINSTINFO_NPLAY | cbINSTINFO_CEREPLEX));
  689. m_icInstrument.Reset(bHighLatency ? (int)INST_TICK_COUNT : (int)Instrument::TICK_COUNT);
  690. // Set network connection details
  691. const QByteArray inIP = m_strInIP.toLatin1();
  692. const QByteArray outIP = m_strOutIP.toLatin1();
  693. m_icInstrument.SetNetwork(m_nInPort, m_nOutPort, inIP, outIP);
  694. // Open UDP
  695. cbRESULT cbres = m_icInstrument.Open(startupOption, m_bBroadcast, m_bDontRoute, m_bNonBlocking, m_nRecBufSize);
  696. if (cbres)
  697. {
  698. // if we can't open NSP, say so
  699. InstNetworkEvent(NET_EVENT_NETOPENERR, cbres); // report cbRESULT
  700. cbClose(m_bStandAlone, m_nInstance); // Close library
  701. return;
  702. }
  703. }
  704. // Reset counters and initial state
  705. m_timerTicks = 0;
  706. m_nRecentPacketCount = 0;
  707. m_dataCounter = 0;
  708. m_nLastNumberOfPacketsReceived = 0;
  709. m_runlevel = cbRUNLEVEL_SHUTDOWN;
  710. m_bDone = false;
  711. // If stand-alone setup network packet handling timer
  712. if (m_bStandAlone)
  713. {
  714. // Start network packet processing timer later in the message loop
  715. #ifdef WIN32
  716. timeBeginPeriod(1);
  717. #endif
  718. m_timerId = startTimer(1);
  719. // Start the message loop
  720. exec();
  721. } else { // else wait for central application data
  722. // Instrument info for non-stand-alone
  723. InstNetworkEvent(NET_EVENT_INSTINFO, m_instInfo);
  724. bool bMonitorThreadMessageWaiting = false; // If message is waiting in non stand-alone mode
  725. UINT missed_messages = 0;
  726. // Start the network loop
  727. while (!m_bDone)
  728. {
  729. cbRESULT waitresult = cbWaitforData(m_nInstance); //hls );
  730. if (waitresult == cbRESULT_NOCENTRALAPP)
  731. {
  732. // No instrument anymore
  733. m_instInfo = 0;
  734. InstNetworkEvent(NET_EVENT_NETOPENERR, cbRESULT_NOCENTRALAPP);
  735. m_bDone = true;
  736. }
  737. else if ((waitresult == cbRESULT_OK) || (bMonitorThreadMessageWaiting == false))
  738. {
  739. missed_messages = 0;
  740. bMonitorThreadMessageWaiting = true;
  741. OnWaitEvent(); // Handle incoming packets
  742. }
  743. else if ((missed_messages++) > 25)
  744. bMonitorThreadMessageWaiting = false;
  745. }
  746. }
  747. // No instrument anymore
  748. m_instInfo = 0;
  749. InstNetworkEvent(NET_EVENT_CLOSE);
  750. msleep(500); // Give apps some to flush their work
  751. if (m_bStandAlone)
  752. {
  753. // Close the Data Socket and Winsock Subsystem
  754. m_icInstrument.Close();
  755. }
  756. // Close the library
  757. cbClose(m_bStandAlone, m_nInstance);
  758. }
  759. // Author & Date: Ehsan Azar 1 June 2010
  760. // Purpose: Network incoming packet handling in non-stand-alone mode
  761. void InstNetwork::OnWaitEvent()
  762. {
  763. // Look to see how much there is to process
  764. uint32_t pktstogo;
  765. cbCheckforData(m_enLOC, &pktstogo, m_nInstance);
  766. if (m_enLOC == LOC_CRITICAL)
  767. {
  768. cbMakePacketReadingBeginNow(m_nInstance);
  769. InstNetworkEvent(NET_EVENT_CRITICAL);
  770. return;
  771. }
  772. // Limit how many we can look at
  773. pktstogo = std::min(pktstogo, MAX_NUM_OF_PACKETS_TO_PROCESS_PER_PASS);
  774. // process any available packets
  775. for(UINT p = 0; p < pktstogo; ++p)
  776. {
  777. cbPKT_GENERIC *pktptr = cbGetNextPacketPtr(m_nInstance);
  778. if (pktptr == NULL)
  779. {
  780. cbMakePacketReadingBeginNow(m_nInstance);
  781. InstNetworkEvent(NET_EVENT_CRITICAL);
  782. break;
  783. } else {
  784. ProcessIncomingPacket(pktptr);
  785. }
  786. }
  787. }