THM1176InstrumentManager  1.0
Qt Object abstraction for Metrolab THM1176
THM1176IM_Test01_Connect.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 Metrolab Technology S.A., Geneva, Switzerland (www.metrolab.com)
2 // See the included file LICENSE.txt for the licensing conditions.
3 
7 
8 #include <regex>
9 #include <thread>
10 #include <chrono>
11 #include <iostream>
12 
13 #include <QtTest>
14 #include <QSignalSpy>
15 
17 
18 #define THM1176_PROMPT_TIME 10 // s
19 #define THM1176_BOOT_N_SCAN_TIME 15000 // ms
20 #define THM1176_CONNECT_TIME 10000 // ms
21 #define THM1176_SCAN_INTERVAL 1000 // ms
22 #define THM1176_SILLY_RESOURCE_NAME "Humpty_Dumpty_had_a_great_fall"
23 
24 using namespace MTL;
25 
27 
28 //----------------------------------------------------------------------//
29 // Utility functions //
30 //----------------------------------------------------------------------//
31 static void PromptAndWait(std::string Prompt)
32 {
33  std::string l_Space = ("" == Prompt) ? "" : " ";
34  std::string l_Message = ">>> " + Prompt + l_Space + "(Will continue in " + std::to_string(THM1176_PROMPT_TIME) + " seconds) <<<";
35  QWARN(" ");
36  QWARN(l_Message.c_str());
37  QThread::currentThread()->sleep(THM1176_PROMPT_TIME);
38 }
39 
40 //----------------------------------------------------------------------//
41 // Test class definition //
42 //----------------------------------------------------------------------//
43 class THM1176IM_Test01_Connect: public QObject
44 {
45  Q_OBJECT
46 
47 public:
50 
51 private slots:
53  void initTestCase(void);
54 
56  void cleanupTestCase(void);
57 
59  void TestNotifyInstrumentList(void);
60 
62  void TestSetCurrentInstrument(void);
63 
64 };
65 
66 //----------------------------------------------------------------------//
67 // Test case constructor and destructor //
68 //----------------------------------------------------------------------//
70 {
71 
72 }
73 
75 {
76 
77 }
78 
79 //----------------------------------------------------------------------//
80 // Test case initialization and cleanup //
81 //----------------------------------------------------------------------//
82 void THM1176IM_Test01_Connect::initTestCase(void)
83 {
84  Manager.Start();
85 }
86 
87 void THM1176IM_Test01_Connect::cleanupTestCase(void)
88 {
89  Manager.Stop();
90 }
91 
100 void THM1176IM_Test01_Connect::TestNotifyInstrumentList(void)
101 {
102  QSignalSpy l_NotifyInstrumentListSpy(&Manager, SIGNAL(NotifyInstrumentList(CResourceList)));
103  QSignalSpy l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));
104  QList<QVariant> l_Arguments;
105  CResourceList l_ResourceList;
106 
107  // Have the user plug in the first THM, and wait for it to boot.
108  PromptAndWait("Please plug in the first THM");
109  l_NotifyInstrumentListSpy.wait(THM1176_BOOT_N_SCAN_TIME);
110 
111  // Make sure the signal was emitted exactly one time, and that
112  // there is exactly one resource.
113  QCOMPARE(l_NotifyInstrumentListSpy.count(), 1);
114 
115  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
116  l_ResourceList = qvariant_cast<CResourceList>(l_Arguments.at(0));
117 
118  QVERIFY(l_ResourceList.size() == 1);
119 
120  // Have the user plug in a second THM, and wait for it to boot.
121  PromptAndWait("Please plug in the second THM");
122  l_NotifyInstrumentListSpy.wait(THM1176_BOOT_N_SCAN_TIME);
123 
124  // Make sure the signal was emitted exactly one time, and that
125  // there are exactly two resources.
126  QCOMPARE(l_NotifyInstrumentListSpy.count(), 1);
127 
128  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
129  l_ResourceList = qvariant_cast<CResourceList>(l_Arguments.at(0));
130  QVERIFY(l_ResourceList.size() == 2);
131 
132  // Have the user unplug the THMs, and wait for one scan.
133  PromptAndWait("Please unplug both THMs");
134  l_NotifyInstrumentListSpy.wait(THM1176_SCAN_INTERVAL);
135 
136  // Make sure the signal was emitted once or twice, and that there are
137  // no resources left.
138  QVERIFY(l_NotifyInstrumentListSpy.count() == 1 || l_NotifyInstrumentListSpy.count() == 2);
139  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
140  if (l_NotifyInstrumentListSpy.count() == 1)
141  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
142  l_ResourceList = qvariant_cast<CResourceList>(l_Arguments.at(0));
143  QVERIFY(l_ResourceList.size() == 0);
144 
145  // Make sure we got no errors.
146  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
147 
148 } // THM1176IM_Test01_Connect::TestNotifyInstrumentList
149 
177 void THM1176IM_Test01_Connect::TestSetCurrentInstrument(void)
178 {
179  // Create Signal Spies to retrieve instrument list, instrument info, parameters and possible errors.
180  QSignalSpy l_NotifyInstrumentListSpy(&Manager, SIGNAL(NotifyInstrumentList(CResourceList)));
181  QSignalSpy l_NotifyCurrentInstrumentSpy(&Manager, SIGNAL(NotifyCurrentInstrument(tResourceName)));
182 
183  QSignalSpy l_NotifyIdentificationSpy(&Manager, SIGNAL(NotifyIdentification(sIdentifier)));
184  QSignalSpy l_NotifyRangeListSpy(&Manager, SIGNAL(NotifyRangeList(CFluxList)));
185  QSignalSpy l_NotifyUnitsListSpy(&Manager, SIGNAL(NotifyUnitsList(CTHM1176UnitsList)));
186  QSignalSpy l_NotifyDivisorListSpy(&Manager, SIGNAL(NotifyDivisorList(CDivisorList)));
187  QSignalSpy l_NotifyAveragingParmBoundsSpy(&Manager, SIGNAL(NotifyAveragingParmBounds(sAveraging<sBoundedParm>)));
188  QSignalSpy l_NotifyTriggerParmBoundsSpy(&Manager, SIGNAL(NotifyTriggerParmBounds(sInputTrigger<sBoundedParm>)));
189  QSignalSpy l_NotifyRangeParmBoundsSpy(&Manager, SIGNAL(NotifyRangeParmBounds(sRange<sBoundedParm>)));
190 
191  QSignalSpy l_NotifyAveragingParmsSpy(&Manager, SIGNAL(NotifyAveragingParms(sAveraging<uParm>)));
192  QSignalSpy l_NotifyTriggerParmsSpy(&Manager, SIGNAL(NotifyTriggerParms(sInputTrigger<uParm>)));
193  QSignalSpy l_NotifyOutputSelectSpy(&Manager, SIGNAL(NotifyOutputSelect(sArbitraryMeasurements)));
194  QSignalSpy l_NotifySleepParmSpy(&Manager, SIGNAL(NotifySleepParm(bool)));
195  QSignalSpy l_NotifyUnitsSpy(&Manager, SIGNAL(NotifyUnits(eTHM1176Units)));
196  QSignalSpy l_NotifyRangeParmsSpy(&Manager, SIGNAL(NotifyRangeParms(sRange<uParm>)));
197  QSignalSpy l_NotifyCommFormatSpy(&Manager, SIGNAL(NotifyCommFormat(eCommunicationFormat)));
198 
199  QSignalSpy l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
200  QSignalSpy l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));
201 
202  // Local variables.
203  QList<QVariant> l_Arguments;
204 
205  CResourceList l_ResourceList;
206  tResourceName l_CurrentInstrument;
207  tResourceName l_FormerInstrument;
208  sIdentifier l_Identification;
209  CFluxList l_RangeList;
210  CTHM1176UnitsList l_UnitsList;
211  CDivisorList l_DivisorList;
212  sAveraging<sBoundedParm> l_AveragingBounds;
213  sInputTrigger<sBoundedParm> l_TriggerBounds;
214  sRange<sBoundedParm> l_RangeBounds;
215  eTHM1176OperatingMode l_CurrentOperatingMode;
216  CErrorList l_LatestErrors;
217 
218  sAveraging<uParm> l_AveragingParms;
219  sInputTrigger<uParm> l_Trigger;
220  sArbitraryMeasurements l_OutputSelect;
221  bool l_SleepParm;
222  eTHM1176Units l_Units;
223  bool l_UseCalibration;
224  sRange<uParm> l_RangeParms;
225  eCommunicationFormat l_CommFormat;
226 
227  // Have the user plug in two THMs, and wait for them to boot.
228  // Make sure the NotifyInstrumentList signal was emitted once or twice,
229  // and that there are two resources in the end.
230  PromptAndWait("Please plug in two THMs");
231  for (int i = 0; i < 2; i++)
232  {
233  // Wait for a signal.
234  l_NotifyInstrumentListSpy.wait(THM1176_BOOT_N_SCAN_TIME);
235 
236  // Possibly we got 2 signals; take the last one.
237  QVERIFY(l_NotifyInstrumentListSpy.count() == 1 || l_NotifyInstrumentListSpy.count() == 2);
238  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
239  if (l_NotifyInstrumentListSpy.count() == 1)
240  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
241  l_ResourceList = qvariant_cast<CResourceList>(l_Arguments.at(0));
242 
243  // If we got 2 VISA resources on the first try, all is well.
244  // Otherwise loop back to wait for the second THM to boot.
245  if (l_ResourceList.size() == 2) break;
246  }
247  QCOMPARE(static_cast<int>(l_ResourceList.size()), 2);
248 
249  // Emit SetCurrentInstrument to select THM 1.
250  // Make sure we got all the appropriate signals, with non-null results.
251  Manager.SetCurrentInstrument(l_ResourceList[0]);
252 
253  // Wait for this instrument to become idle.
254  l_NotifyOperatingModeSpy.wait(THM1176_CONNECT_TIME);
255  QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
256  l_Arguments = l_NotifyOperatingModeSpy.takeFirst();
257  l_CurrentOperatingMode = qvariant_cast<eTHM1176OperatingMode>(l_Arguments.at(0));
258  QCOMPARE(l_CurrentOperatingMode, kTHM1176Idle);
259 
260  // Retrieve current instrument.
261  l_FormerInstrument = l_CurrentInstrument;
262  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 1);
263  l_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
264  l_CurrentInstrument = qvariant_cast<tResourceName>(l_Arguments.at(0));
265  QCOMPARE(l_CurrentInstrument, l_ResourceList[0]);
266 
267  // Retrieve instrument information and parameter bounds for this THM.
268  QCOMPARE(l_NotifyIdentificationSpy.count(), 1);
269  l_Arguments = l_NotifyIdentificationSpy.takeFirst();
270  l_Identification = qvariant_cast<sIdentifier>(l_Arguments.at(0));
271  QVERIFY(!l_Identification.Manufacturer.empty() && !l_Identification.Model.empty() && l_Identification.SerialNumber != 0);
272 
273  QCOMPARE(l_NotifyRangeListSpy.count(), 1);
274  l_Arguments = l_NotifyRangeListSpy.takeFirst();
275  l_RangeList = qvariant_cast<CFluxList>(l_Arguments.at(0));
276  QVERIFY(!l_RangeList.empty());
277 
278  QCOMPARE(l_NotifyUnitsListSpy.count(), 1);
279  l_Arguments = l_NotifyUnitsListSpy.takeFirst();
280  l_UnitsList = qvariant_cast<CTHM1176UnitsList>(l_Arguments.at(0));
281  QVERIFY(!l_UnitsList.empty());
282 
283  QCOMPARE(l_NotifyDivisorListSpy.count(), 1);
284  l_Arguments = l_NotifyDivisorListSpy.takeFirst();
285  l_DivisorList = qvariant_cast<CDivisorList>(l_Arguments.at(0));
286  QVERIFY(!l_DivisorList.empty());
287 
288  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 1);
289  l_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
290  l_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(l_Arguments.at(0));
291  QVERIFY(l_AveragingBounds.NoPoints.Val != 0 && l_AveragingBounds.NoPoints.Min != 0 &&
292  l_AveragingBounds.NoPoints.Max != 0 && l_AveragingBounds.NoPoints.Def != 0);
293 
294  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 1);
295  l_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
296  l_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(l_Arguments.at(0));
297  QVERIFY(l_TriggerBounds.Period_s.Val != 0 && l_TriggerBounds.Period_s.Min != 0 &&
298  l_TriggerBounds.Period_s.Max != 0 && l_TriggerBounds.Period_s.Def != 0 &&
299  l_TriggerBounds.Count.Val != 0 && l_TriggerBounds.Count.Min != 0 &&
300  l_TriggerBounds.Count.Max != 0 && l_TriggerBounds.Count.Def != 0);
301 
302  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 1);
303  l_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
304  l_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(l_Arguments.at(0));
305  QVERIFY(l_RangeBounds.Range.Val != 0 && l_RangeBounds.Range.Min != 0 &&
306  l_RangeBounds.Range.Max != 0 && l_RangeBounds.Range.Def != 0);
307 
308  // Retrieve the current parameters for this instrument.
309  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 1);
310  l_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
311  l_AveragingParms = qvariant_cast<sAveraging<uParm>>(l_Arguments.at(0));
312  QVERIFY(l_AveragingParms.NoPoints > 0);
313 
314  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 1);
315  l_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
316  l_Trigger = qvariant_cast<sInputTrigger<uParm>>(l_Arguments.at(0));
317  QVERIFY(l_Trigger.Period_s > 0. && l_Trigger.Count > 0);
318 
319  QCOMPARE(l_NotifyOutputSelectSpy.count(), 1);
320  l_Arguments = l_NotifyOutputSelectSpy.takeFirst();
321  l_OutputSelect = qvariant_cast<sArbitraryMeasurements>(l_Arguments.at(0));
322 
323  QCOMPARE(l_NotifySleepParmSpy.count(), 1);
324  l_Arguments = l_NotifySleepParmSpy.takeFirst();
325  l_SleepParm = qvariant_cast<bool>(l_Arguments.at(0));
326 
327  QCOMPARE(l_NotifyUnitsSpy.count(), 1);
328  l_Arguments = l_NotifyUnitsSpy.takeFirst();
329  l_Units = qvariant_cast<eTHM1176Units>(l_Arguments.at(0));
330 
331  QCOMPARE(l_NotifyRangeParmsSpy.count(), 1);
332  l_Arguments = l_NotifyRangeParmsSpy.takeFirst();
333  l_RangeParms = qvariant_cast<sRange<uParm>>(l_Arguments.at(0));
334 
335  QCOMPARE(l_NotifyCommFormatSpy.count(), 1);
336  l_Arguments = l_NotifyCommFormatSpy.takeFirst();
337  l_CommFormat = qvariant_cast<eCommunicationFormat>(l_Arguments.at(0));
338 
339  // We expect no errors.
340  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
341 
342  std::cout << "- Connected to " << l_Identification.Model << ", S/N " << l_Identification.SerialNumber << std::endl;
343 
344  // Emit SetCurrentInstrument to select THM 1 again.
345  // Make sure we get none of the signals.
346  Manager.SetCurrentInstrument(l_ResourceList[0]);
347 
348  l_NotifyCurrentInstrumentSpy.wait(THM1176_CONNECT_TIME);
349  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 0);
350 
351  // Retrieve instrument information and parameter bounds for this THM.
352  QCOMPARE(l_NotifyIdentificationSpy.count(), 0);
353  QCOMPARE(l_NotifyRangeListSpy.count(), 0);
354  QCOMPARE(l_NotifyUnitsListSpy.count(), 0);
355  QCOMPARE(l_NotifyDivisorListSpy.count(), 0);
356  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 0);
357  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 0);
358  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 0);
359 
360  // Retrieve the current parameters for this instrument.
361  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 0);
362  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 0);
363  QCOMPARE(l_NotifyOutputSelectSpy.count(), 0);
364  QCOMPARE(l_NotifySleepParmSpy.count(), 0);
365  QCOMPARE(l_NotifyUnitsSpy.count(), 0);
366  QCOMPARE(l_NotifyRangeParmsSpy.count(), 0);
367  QCOMPARE(l_NotifyCommFormatSpy.count(), 0);
368 
369  // Retrieve the operating mode and error list.
370  QCOMPARE(l_NotifyOperatingModeSpy.count(), 0);
371  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
372 
373  std::cout << "- Still connected to " << l_Identification.Model << ", S/N " << l_Identification.SerialNumber << std::endl;
374 
375  // Emit SetCurrentInstrument for nonexistent THM.
376  // Make sure we receive a NotifyErrorList; nothing else.
378 
379  l_FormerInstrument = l_CurrentInstrument;
380  l_NotifyCurrentInstrumentSpy.wait(THM1176_CONNECT_TIME);
381  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 0);
382 
383  // Retrieve instrument information and parameter bounds for this THM.
384  QCOMPARE(l_NotifyIdentificationSpy.count(), 0);
385  QCOMPARE(l_NotifyRangeListSpy.count(), 0);
386  QCOMPARE(l_NotifyUnitsListSpy.count(), 0);
387  QCOMPARE(l_NotifyDivisorListSpy.count(), 0);
388  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 0);
389  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 0);
390  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 0);
391 
392  // Retrieve the current parameters for this instrument.
393  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 0);
394  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 0);
395  QCOMPARE(l_NotifyOutputSelectSpy.count(), 0);
396  QCOMPARE(l_NotifySleepParmSpy.count(), 0);
397  QCOMPARE(l_NotifyUnitsSpy.count(), 0);
398  QCOMPARE(l_NotifyRangeParmsSpy.count(), 0);
399  QCOMPARE(l_NotifyCommFormatSpy.count(), 0);
400 
401  // Retrieve the operating mode and error list.
402  QCOMPARE(l_NotifyOperatingModeSpy.count(), 0);
403 
404  // Retrieve the error list.
405  QCOMPARE(l_NotifyErrorListSpy.count(), 1);
406  l_Arguments = l_NotifyErrorListSpy.takeFirst();
407  l_LatestErrors = qvariant_cast<CErrorList>(l_Arguments.at(0));
408  QCOMPARE(static_cast<int>(l_LatestErrors.size()), 1);
409 
410  std::cout << "- Invalid connection request returned error: " << l_LatestErrors[0].Code << ", " <<
411  l_LatestErrors[0].Description << ", " << l_LatestErrors[0].Context << std::endl;
412  std::cout << "- Still connected to " << l_Identification.Model << ", S/N " << l_Identification.SerialNumber << std::endl;
413 
414  // Emit SetCurrentInstrument to select THM 2.
415  Manager.SetCurrentInstrument(l_ResourceList[1]);
416 
417  // NotifyOperatingMode is emitted twice: once for the diconnect, once for the connect.
418  // Otherwise, we should get all the appropriate signals twice, once with null and once with non-null results.
419  l_NotifyOperatingModeSpy.wait(THM1176_CONNECT_TIME);
420  QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
421  l_Arguments = l_NotifyOperatingModeSpy.takeFirst();
422  l_CurrentOperatingMode = qvariant_cast<eTHM1176OperatingMode>(l_Arguments.at(0));
423  QCOMPARE(l_CurrentOperatingMode, kTHM1176NotConnected);
424  if (l_NotifyOperatingModeSpy.count() <= 0)
425  {
426  l_NotifyOperatingModeSpy.wait(THM1176_CONNECT_TIME);
427  QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
428  }
429  l_Arguments = l_NotifyOperatingModeSpy.takeFirst();
430  l_CurrentOperatingMode = qvariant_cast<eTHM1176OperatingMode>(l_Arguments.at(0));
431  QCOMPARE(l_CurrentOperatingMode, kTHM1176Idle);
432 
433  // Retrieve the Current Instrument.
434  l_FormerInstrument = l_CurrentInstrument;
435  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 2);
436  l_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
437  l_CurrentInstrument = qvariant_cast<tResourceName>(l_Arguments.at(0));
438  QVERIFY(l_CurrentInstrument.empty());
439  l_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
440  l_CurrentInstrument = qvariant_cast<tResourceName>(l_Arguments.at(0));
441  QVERIFY(l_CurrentInstrument == l_ResourceList[1]);
442 
443  // Retrieve instrument information and parameter bounds for this THM.
444  QCOMPARE(l_NotifyIdentificationSpy.count(), 2);
445  l_Arguments = l_NotifyIdentificationSpy.takeFirst();
446  l_Identification = qvariant_cast<sIdentifier>(l_Arguments.at(0));
447  QVERIFY(l_Identification.Manufacturer.empty() && l_Identification.Model.empty() && l_Identification.SerialNumber == 0);
448  l_Arguments = l_NotifyIdentificationSpy.takeFirst();
449  l_Identification = qvariant_cast<sIdentifier>(l_Arguments.at(0));
450  QVERIFY(!l_Identification.Manufacturer.empty() && !l_Identification.Model.empty() && l_Identification.SerialNumber != 0);
451 
452  QCOMPARE(l_NotifyRangeListSpy.count(), 2);
453  l_Arguments = l_NotifyRangeListSpy.takeFirst();
454  l_RangeList = qvariant_cast<CFluxList>(l_Arguments.at(0));
455  QVERIFY(l_RangeList.empty());
456  l_Arguments = l_NotifyRangeListSpy.takeFirst();
457  l_RangeList = qvariant_cast<CFluxList>(l_Arguments.at(0));
458  QVERIFY(!l_RangeList.empty());
459 
460  QCOMPARE(l_NotifyUnitsListSpy.count(), 2);
461  l_Arguments = l_NotifyUnitsListSpy.takeFirst();
462  l_UnitsList = qvariant_cast<CTHM1176UnitsList>(l_Arguments.at(0));
463  QVERIFY(l_UnitsList.empty());
464  l_Arguments = l_NotifyUnitsListSpy.takeFirst();
465  l_UnitsList = qvariant_cast<CTHM1176UnitsList>(l_Arguments.at(0));
466  QVERIFY(!l_UnitsList.empty());
467 
468  QCOMPARE(l_NotifyDivisorListSpy.count(), 2);
469  l_Arguments = l_NotifyDivisorListSpy.takeFirst();
470  l_DivisorList = qvariant_cast<CDivisorList>(l_Arguments.at(0));
471  QVERIFY(l_DivisorList.empty());
472  l_Arguments = l_NotifyDivisorListSpy.takeFirst();
473  l_DivisorList = qvariant_cast<CDivisorList>(l_Arguments.at(0));
474  QVERIFY(!l_DivisorList.empty());
475 
476  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 2);
477  l_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
478  l_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(l_Arguments.at(0));
479  QVERIFY(l_AveragingBounds.NoPoints.Val == 0 && l_AveragingBounds.NoPoints.Min == 0 &&
480  l_AveragingBounds.NoPoints.Max == 0 && l_AveragingBounds.NoPoints.Def == 0);
481  l_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
482  l_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(l_Arguments.at(0));
483  QVERIFY(l_AveragingBounds.NoPoints.Val != 0 && l_AveragingBounds.NoPoints.Min != 0 &&
484  l_AveragingBounds.NoPoints.Max != 0 && l_AveragingBounds.NoPoints.Def != 0);
485 
486  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 2);
487  l_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
488  l_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(l_Arguments.at(0));
489  QVERIFY(l_TriggerBounds.Period_s.Val == 0 && l_TriggerBounds.Period_s.Min == 0 &&
490  l_TriggerBounds.Period_s.Max == 0 && l_TriggerBounds.Period_s.Def == 0 &&
491  l_TriggerBounds.Count.Val == 0 && l_TriggerBounds.Count.Min == 0 &&
492  l_TriggerBounds.Count.Max == 0 && l_TriggerBounds.Count.Def == 0);
493  l_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
494  l_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(l_Arguments.at(0));
495  QVERIFY(l_TriggerBounds.Period_s.Val != 0 && l_TriggerBounds.Period_s.Min != 0 &&
496  l_TriggerBounds.Period_s.Max != 0 && l_TriggerBounds.Period_s.Def != 0 &&
497  l_TriggerBounds.Count.Val != 0 && l_TriggerBounds.Count.Min != 0 &&
498  l_TriggerBounds.Count.Max != 0 && l_TriggerBounds.Count.Def != 0);
499 
500  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 2);
501  l_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
502  l_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(l_Arguments.at(0));
503  QVERIFY(l_RangeBounds.Range.Val == 0 && l_RangeBounds.Range.Min == 0 &&
504  l_RangeBounds.Range.Max == 0 && l_RangeBounds.Range.Def == 0);
505  l_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
506  l_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(l_Arguments.at(0));
507  QVERIFY(l_RangeBounds.Range.Val != 0 && l_RangeBounds.Range.Min != 0 &&
508  l_RangeBounds.Range.Max != 0 && l_RangeBounds.Range.Def != 0);
509 
510  // Retrieve the current parameters for this instrument.
511  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 2);
512  l_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
513  l_AveragingParms = qvariant_cast<sAveraging<uParm>>(l_Arguments.at(0));
514  QVERIFY(l_AveragingParms.NoPoints == 0);
515  l_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
516  l_AveragingParms = qvariant_cast<sAveraging<uParm>>(l_Arguments.at(0));
517  QVERIFY(l_AveragingParms.NoPoints > 0);
518 
519  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 2);
520  l_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
521  l_Trigger = qvariant_cast<sInputTrigger<uParm>>(l_Arguments.at(0));
522  QVERIFY(l_Trigger.Source == kInputTrigSrcImmediate && l_Trigger.Period_s == 0. && l_Trigger.Count == 0);
523  l_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
524  l_Trigger = qvariant_cast<sInputTrigger<uParm>>(l_Arguments.at(0));
525  QVERIFY(l_Trigger.Period_s > 0. && l_Trigger.Count > 0);
526 
527  QCOMPARE(l_NotifyOutputSelectSpy.count(), 2);
528  l_Arguments = l_NotifyOutputSelectSpy.takeFirst();
529  l_OutputSelect = qvariant_cast<sArbitraryMeasurements>(l_Arguments.at(0));
530  QVERIFY(l_OutputSelect.Bx && l_OutputSelect.By && l_OutputSelect.Bz &&
531  l_OutputSelect.Temperature && l_OutputSelect.Timestamp && l_OutputSelect.NoMeasurements == 1);
532  l_Arguments = l_NotifyOutputSelectSpy.takeFirst();
533  l_OutputSelect = qvariant_cast<sArbitraryMeasurements>(l_Arguments.at(0));
534 
535  QCOMPARE(l_NotifySleepParmSpy.count(), 2);
536  l_Arguments = l_NotifySleepParmSpy.takeFirst();
537  l_SleepParm = qvariant_cast<bool>(l_Arguments.at(0));
538  QVERIFY(!l_SleepParm);
539  l_Arguments = l_NotifySleepParmSpy.takeFirst();
540  l_SleepParm = qvariant_cast<bool>(l_Arguments.at(0));
541 
542  QCOMPARE(l_NotifyUnitsSpy.count(), 2);
543  l_Arguments = l_NotifyUnitsSpy.takeFirst();
544  l_Units = qvariant_cast<eTHM1176Units>(l_Arguments.at(0));
545  QVERIFY(l_Units == MTL::kT);
546  l_Arguments = l_NotifyUnitsSpy.takeFirst();
547  l_Units = qvariant_cast<eTHM1176Units>(l_Arguments.at(0));
548 
549  QCOMPARE(l_NotifyRangeParmsSpy.count(), 2);
550  l_Arguments = l_NotifyRangeParmsSpy.takeFirst();
551  l_RangeParms = qvariant_cast<sRange<uParm>>(l_Arguments.at(0));
552  QVERIFY(!l_RangeParms.Auto && l_RangeParms.Range == 0.f);
553  l_Arguments = l_NotifyRangeParmsSpy.takeFirst();
554  l_RangeParms = qvariant_cast<sRange<uParm>>(l_Arguments.at(0));
555 
556  QCOMPARE(l_NotifyCommFormatSpy.count(), 2);
557  l_Arguments = l_NotifyCommFormatSpy.takeFirst();
558  l_CommFormat = qvariant_cast<eCommunicationFormat>(l_Arguments.at(0));
559  QVERIFY(l_CommFormat == kComFormatAscii);
560  l_Arguments = l_NotifyCommFormatSpy.takeFirst();
561  l_CommFormat = qvariant_cast<eCommunicationFormat>(l_Arguments.at(0));
562 
563  // Retrieve the error list.
564  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
565 
566  std::cout << "- Connected to " << l_Identification.Model << ", S/N " << l_Identification.SerialNumber << std::endl;
567 
568  // Have the user unplug THM 2.
569  // Make sure we get signals with empty lists, plus a NotifyErrorList.
570  std::string l_Prompt = "Please unplug " + l_Identification.Model + ", S/N " + std::to_string(l_Identification.SerialNumber);
571  PromptAndWait(l_Prompt);
572  l_NotifyInstrumentListSpy.wait(THM1176_BOOT_N_SCAN_TIME);
573  QVERIFY(l_NotifyInstrumentListSpy.count() == 1);
574  l_Arguments = l_NotifyInstrumentListSpy.takeFirst();
575  l_ResourceList = qvariant_cast<CResourceList>(l_Arguments.at(0));
576 
577  // The last signal that should arrive is NotifyCommFormat.
578  l_NotifyCommFormatSpy.wait(THM1176_CONNECT_TIME);
579  QCOMPARE(l_NotifyCommFormatSpy.count(), 1);
580  l_Arguments = l_NotifyCommFormatSpy.takeFirst();
581  l_CommFormat = qvariant_cast<eCommunicationFormat>(l_Arguments.at(0));
582  QVERIFY(l_CommFormat == kComFormatAscii);
583 
584  // Retrieve the current instrument.
585  l_FormerInstrument = l_CurrentInstrument;
586  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 1);
587  l_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
588  l_CurrentInstrument = qvariant_cast<tResourceName>(l_Arguments.at(0));
589  QVERIFY(l_CurrentInstrument.empty());
590 
591  // Retrieve instrument information and parameter bounds for this THM.
592  QCOMPARE(l_NotifyIdentificationSpy.count(), 1);
593  l_Arguments = l_NotifyIdentificationSpy.takeFirst();
594  l_Identification = qvariant_cast<sIdentifier>(l_Arguments.at(0));
595  QVERIFY(l_Identification.Manufacturer.empty() && l_Identification.Model.empty() && l_Identification.SerialNumber == 0);
596 
597  QCOMPARE(l_NotifyRangeListSpy.count(), 1);
598  l_Arguments = l_NotifyRangeListSpy.takeFirst();
599  l_RangeList = qvariant_cast<CFluxList>(l_Arguments.at(0));
600  QVERIFY(l_RangeList.empty());
601 
602  QCOMPARE(l_NotifyUnitsListSpy.count(), 1);
603  l_Arguments = l_NotifyUnitsListSpy.takeFirst();
604  l_UnitsList = qvariant_cast<CTHM1176UnitsList>(l_Arguments.at(0));
605  QVERIFY(l_UnitsList.empty());
606 
607  QCOMPARE(l_NotifyDivisorListSpy.count(), 1);
608  l_Arguments = l_NotifyDivisorListSpy.takeFirst();
609  l_DivisorList = qvariant_cast<CDivisorList>(l_Arguments.at(0));
610  QVERIFY(l_DivisorList.empty());
611 
612  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 1);
613  l_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
614  l_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(l_Arguments.at(0));
615  QVERIFY(l_AveragingBounds.NoPoints.Val == 0 && l_AveragingBounds.NoPoints.Min == 0 &&
616  l_AveragingBounds.NoPoints.Max == 0 && l_AveragingBounds.NoPoints.Def == 0);
617 
618  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 1);
619  l_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
620  l_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(l_Arguments.at(0));
621  QVERIFY(l_TriggerBounds.Period_s.Val == 0 && l_TriggerBounds.Period_s.Min == 0 &&
622  l_TriggerBounds.Period_s.Max == 0 && l_TriggerBounds.Period_s.Def == 0 &&
623  l_TriggerBounds.Count.Val == 0 && l_TriggerBounds.Count.Min == 0 &&
624  l_TriggerBounds.Count.Max == 0 && l_TriggerBounds.Count.Def == 0);
625 
626  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 1);
627  l_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
628  l_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(l_Arguments.at(0));
629  QVERIFY(l_RangeBounds.Range.Val == 0 && l_RangeBounds.Range.Min == 0 &&
630  l_RangeBounds.Range.Max == 0 && l_RangeBounds.Range.Def == 0);
631 
632  // Retrieve the current parameters for this instrument.
633  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 1);
634  l_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
635  l_AveragingParms = qvariant_cast<sAveraging<uParm>>(l_Arguments.at(0));
636  QVERIFY(l_AveragingParms.NoPoints == 0);
637 
638  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 1);
639  l_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
640  l_Trigger = qvariant_cast<sInputTrigger<uParm>>(l_Arguments.at(0));
641  QVERIFY(l_Trigger.Period_s == 0. && l_Trigger.Count == 0);
642 
643  QCOMPARE(l_NotifyOutputSelectSpy.count(), 1);
644  l_Arguments = l_NotifyOutputSelectSpy.takeFirst();
645  l_OutputSelect = qvariant_cast<sArbitraryMeasurements>(l_Arguments.at(0));
646  QVERIFY(l_OutputSelect.Bx && l_OutputSelect.By && l_OutputSelect.Bz &&
647  l_OutputSelect.Temperature && l_OutputSelect.Timestamp &&
648  l_OutputSelect.NoMeasurements == 1);
649 
650  QCOMPARE(l_NotifySleepParmSpy.count(), 1);
651  l_Arguments = l_NotifySleepParmSpy.takeFirst();
652  l_SleepParm = qvariant_cast<bool>(l_Arguments.at(0));
653  QVERIFY(!l_SleepParm);
654 
655  QCOMPARE(l_NotifyUnitsSpy.count(), 1);
656  l_Arguments = l_NotifyUnitsSpy.takeFirst();
657  l_Units = qvariant_cast<eTHM1176Units>(l_Arguments.at(0));
658  QVERIFY(l_Units == MTL::kT);
659 
660  QCOMPARE(l_NotifyRangeParmsSpy.count(), 1);
661  l_Arguments = l_NotifyRangeParmsSpy.takeFirst();
662  l_RangeParms = qvariant_cast<sRange<uParm>>(l_Arguments.at(0));
663  QVERIFY(!l_RangeParms.Auto && l_RangeParms.Range == 0.f);
664 
665  // Retrieve the operating mode and error list.
666  QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
667  l_Arguments = l_NotifyOperatingModeSpy.takeFirst();
668  l_CurrentOperatingMode = qvariant_cast<eTHM1176OperatingMode>(l_Arguments.at(0));
669  QCOMPARE(l_CurrentOperatingMode, kTHM1176NotConnected);
670 
671  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
672 
673  std::cout << "- No longer connected" << std::endl;
674 
675  // Emit SetCurrentInstrument for the now unplugged THM.
676  // Make sure we get NotifyCurrentInstrument twice, once for the requested resource, once for no resource,
677  // plus a NotifyErrorList.
678  Manager.SetCurrentInstrument(l_FormerInstrument);
679 
680  l_NotifyCurrentInstrumentSpy.wait(THM1176_CONNECT_TIME);
681  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 0);
682 
683  // Retrieve instrument information and parameter bounds for this THM.
684  QCOMPARE(l_NotifyIdentificationSpy.count(), 0);
685  QCOMPARE(l_NotifyRangeListSpy.count(), 0);
686  QCOMPARE(l_NotifyUnitsListSpy.count(), 0);
687  QCOMPARE(l_NotifyDivisorListSpy.count(), 0);
688  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 0);
689  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 0);
690  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 0);
691 
692  // Retrieve the current parameters for this instrument.
693  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 0);
694  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 0);
695  QCOMPARE(l_NotifyOutputSelectSpy.count(), 0);
696  QCOMPARE(l_NotifySleepParmSpy.count(), 0);
697  QCOMPARE(l_NotifyUnitsSpy.count(), 0);
698  QCOMPARE(l_NotifyRangeParmsSpy.count(), 0);
699  QCOMPARE(l_NotifyCommFormatSpy.count(), 0);
700 
701  // Retrieve the operating mode and error list.
702  QCOMPARE(l_NotifyOperatingModeSpy.count(), 0);
703 
704  // Retrieve the error list.
705  QCOMPARE(l_NotifyErrorListSpy.count(), 1);
706  l_Arguments = l_NotifyErrorListSpy.takeFirst();
707  l_LatestErrors = qvariant_cast<CErrorList>(l_Arguments.at(0));
708  QCOMPARE(static_cast<int>(l_LatestErrors.size()), 1);
709 
710  std::cout << "- Invalid connection request returned error: " << l_LatestErrors[0].Code << ", " <<
711  l_LatestErrors[0].Description << ", " << l_LatestErrors[0].Context << std::endl;
712  std::cout << "- No longer connected" << std::endl;
713 
714  // Emit SetCurrentInstrument to select THM 1.
715  // Make sure we got all the appropriate signals, with non-null results.
716  Manager.SetCurrentInstrument(l_ResourceList[0]);
717 
718  // Wait for the operating mode to become Idle.
719  l_NotifyOperatingModeSpy.wait(THM1176_CONNECT_TIME);
720  QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
721  l_Arguments = l_NotifyOperatingModeSpy.takeFirst();
722  l_CurrentOperatingMode = qvariant_cast<eTHM1176OperatingMode>(l_Arguments.at(0));
723  QCOMPARE(l_CurrentOperatingMode, kTHM1176Idle);
724 
725  // Retrieve the current instrument.
726  l_FormerInstrument = l_CurrentInstrument;
727  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 1);
728  l_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
729  l_CurrentInstrument = qvariant_cast<tResourceName>(l_Arguments.at(0));
730  QCOMPARE(l_CurrentInstrument, l_ResourceList[0]);
731 
732  // Retrieve instrument information and parameter bounds for this THM.
733  QCOMPARE(l_NotifyIdentificationSpy.count(), 1);
734  l_Arguments = l_NotifyIdentificationSpy.takeFirst();
735  l_Identification = qvariant_cast<sIdentifier>(l_Arguments.at(0));
736  QVERIFY(!l_Identification.Manufacturer.empty() && !l_Identification.Model.empty() && l_Identification.SerialNumber != 0);
737 
738  QCOMPARE(l_NotifyRangeListSpy.count(), 1);
739  l_Arguments = l_NotifyRangeListSpy.takeFirst();
740  l_RangeList = qvariant_cast<CFluxList>(l_Arguments.at(0));
741  QVERIFY(!l_RangeList.empty());
742 
743  QCOMPARE(l_NotifyUnitsListSpy.count(), 1);
744  l_Arguments = l_NotifyUnitsListSpy.takeFirst();
745  l_UnitsList = qvariant_cast<CTHM1176UnitsList>(l_Arguments.at(0));
746  QVERIFY(!l_UnitsList.empty());
747 
748  QCOMPARE(l_NotifyDivisorListSpy.count(), 1);
749  l_Arguments = l_NotifyDivisorListSpy.takeFirst();
750  l_DivisorList = qvariant_cast<CDivisorList>(l_Arguments.at(0));
751  QVERIFY(!l_DivisorList.empty());
752 
753  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 1);
754  l_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
755  l_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(l_Arguments.at(0));
756  QVERIFY(l_AveragingBounds.NoPoints.Val != 0 && l_AveragingBounds.NoPoints.Min != 0 &&
757  l_AveragingBounds.NoPoints.Max != 0 && l_AveragingBounds.NoPoints.Def != 0);
758 
759  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 1);
760  l_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
761  l_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(l_Arguments.at(0));
762  QVERIFY(l_TriggerBounds.Period_s.Val != 0 && l_TriggerBounds.Period_s.Min != 0 &&
763  l_TriggerBounds.Period_s.Max != 0 && l_TriggerBounds.Period_s.Def != 0 &&
764  l_TriggerBounds.Count.Val != 0 && l_TriggerBounds.Count.Min != 0 &&
765  l_TriggerBounds.Count.Max != 0 && l_TriggerBounds.Count.Def != 0);
766 
767  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 1);
768  l_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
769  l_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(l_Arguments.at(0));
770  QVERIFY(l_RangeBounds.Range.Val != 0 && l_RangeBounds.Range.Min != 0 &&
771  l_RangeBounds.Range.Max != 0 && l_RangeBounds.Range.Def != 0);
772 
773  // Retrieve the current parameters for this instrument.
774  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 1);
775  l_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
776  l_AveragingParms = qvariant_cast<sAveraging<uParm>>(l_Arguments.at(0));
777  QVERIFY(l_AveragingParms.NoPoints > 0);
778 
779  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 1);
780  l_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
781  l_Trigger = qvariant_cast<sInputTrigger<uParm>>(l_Arguments.at(0));
782  QVERIFY(l_Trigger.Period_s > 0. && l_Trigger.Count > 0);
783 
784  QCOMPARE(l_NotifyOutputSelectSpy.count(), 1);
785  l_Arguments = l_NotifyOutputSelectSpy.takeFirst();
786  l_OutputSelect = qvariant_cast<sArbitraryMeasurements>(l_Arguments.at(0));
787 
788  QCOMPARE(l_NotifySleepParmSpy.count(), 1);
789  l_Arguments = l_NotifySleepParmSpy.takeFirst();
790  l_SleepParm = qvariant_cast<bool>(l_Arguments.at(0));
791 
792  QCOMPARE(l_NotifyUnitsSpy.count(), 1);
793  l_Arguments = l_NotifyUnitsSpy.takeFirst();
794  l_Units = qvariant_cast<eTHM1176Units>(l_Arguments.at(0));
795 
796  QCOMPARE(l_NotifyRangeParmsSpy.count(), 1);
797  l_Arguments = l_NotifyRangeParmsSpy.takeFirst();
798  l_RangeParms = qvariant_cast<sRange<uParm>>(l_Arguments.at(0));
799 
800  QCOMPARE(l_NotifyCommFormatSpy.count(), 1);
801  l_Arguments = l_NotifyCommFormatSpy.takeFirst();
802  l_CommFormat = qvariant_cast<eCommunicationFormat>(l_Arguments.at(0));
803 
804  // Retrieve the error list.
805  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
806 
807  std::cout << "- Connected to " << l_Identification.Model << ", S/N " << l_Identification.SerialNumber << std::endl;
808 
809  // - Emit SetOperatingMode to diconnect THM:
810  // Make sure we get signals with empty lists.
812 
813  // The last signal should be NotifyCommFormat.
814  l_NotifyCommFormatSpy.wait(THM1176_CONNECT_TIME);
815  QCOMPARE(l_NotifyCommFormatSpy.count(), 1);
816  l_Arguments = l_NotifyCommFormatSpy.takeFirst();
817  l_CommFormat = qvariant_cast<eCommunicationFormat>(l_Arguments.at(0));
818  QVERIFY(l_CommFormat == kComFormatAscii);
819 
820  // Retrieve the current instrument.
821  l_FormerInstrument = l_CurrentInstrument;
822  QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 1);
823  l_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
824  l_CurrentInstrument = qvariant_cast<tResourceName>(l_Arguments.at(0));
825  QVERIFY(l_CurrentInstrument.empty());
826 
827  // Retrieve instrument information and parameter bounds for this THM.
828  QCOMPARE(l_NotifyIdentificationSpy.count(), 1);
829  l_Arguments = l_NotifyIdentificationSpy.takeFirst();
830  l_Identification = qvariant_cast<sIdentifier>(l_Arguments.at(0));
831  QVERIFY(l_Identification.Manufacturer.empty() && l_Identification.Model.empty() && l_Identification.SerialNumber == 0);
832 
833  QCOMPARE(l_NotifyRangeListSpy.count(), 1);
834  l_Arguments = l_NotifyRangeListSpy.takeFirst();
835  l_RangeList = qvariant_cast<CFluxList>(l_Arguments.at(0));
836  QVERIFY(l_RangeList.empty());
837 
838  QCOMPARE(l_NotifyUnitsListSpy.count(), 1);
839  l_Arguments = l_NotifyUnitsListSpy.takeFirst();
840  l_UnitsList = qvariant_cast<CTHM1176UnitsList>(l_Arguments.at(0));
841  QVERIFY(l_UnitsList.empty());
842 
843  QCOMPARE(l_NotifyDivisorListSpy.count(), 1);
844  l_Arguments = l_NotifyDivisorListSpy.takeFirst();
845  l_DivisorList = qvariant_cast<CDivisorList>(l_Arguments.at(0));
846  QVERIFY(l_DivisorList.empty());
847 
848  QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 1);
849  l_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
850  l_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(l_Arguments.at(0));
851  QVERIFY(l_AveragingBounds.NoPoints.Val == 0 && l_AveragingBounds.NoPoints.Min == 0 &&
852  l_AveragingBounds.NoPoints.Max == 0 && l_AveragingBounds.NoPoints.Def == 0);
853 
854  QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 1);
855  l_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
856  l_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(l_Arguments.at(0));
857  QVERIFY(l_TriggerBounds.Period_s.Val == 0 && l_TriggerBounds.Period_s.Min == 0 &&
858  l_TriggerBounds.Period_s.Max == 0 && l_TriggerBounds.Period_s.Def == 0 &&
859  l_TriggerBounds.Count.Val == 0 && l_TriggerBounds.Count.Min == 0 &&
860  l_TriggerBounds.Count.Max == 0 && l_TriggerBounds.Count.Def == 0);
861 
862  QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 1);
863  l_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
864  l_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(l_Arguments.at(0));
865  QVERIFY(l_RangeBounds.Range.Val == 0 && l_RangeBounds.Range.Min == 0 &&
866  l_RangeBounds.Range.Max == 0 && l_RangeBounds.Range.Def == 0);
867 
868  // Retrieve the current parameters for this instrument.
869  QCOMPARE(l_NotifyAveragingParmsSpy.count(), 1);
870  l_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
871  l_AveragingParms = qvariant_cast<sAveraging<uParm>>(l_Arguments.at(0));
872  QVERIFY(l_AveragingParms.NoPoints == 0);
873 
874  QCOMPARE(l_NotifyTriggerParmsSpy.count(), 1);
875  l_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
876  l_Trigger = qvariant_cast<sInputTrigger<uParm>>(l_Arguments.at(0));
877  QVERIFY(l_Trigger.Period_s == 0. && l_Trigger.Count == 0);
878 
879  QCOMPARE(l_NotifyOutputSelectSpy.count(), 1);
880  l_Arguments = l_NotifyOutputSelectSpy.takeFirst();
881  l_OutputSelect = qvariant_cast<sArbitraryMeasurements>(l_Arguments.at(0));
882  QVERIFY(l_OutputSelect.Bx && l_OutputSelect.By && l_OutputSelect.Bz &&
883  l_OutputSelect.Temperature && l_OutputSelect.Timestamp &&
884  l_OutputSelect.NoMeasurements == 1);
885 
886  QCOMPARE(l_NotifySleepParmSpy.count(), 1);
887  l_Arguments = l_NotifySleepParmSpy.takeFirst();
888  l_SleepParm = qvariant_cast<bool>(l_Arguments.at(0));
889  QVERIFY(!l_SleepParm);
890 
891  QCOMPARE(l_NotifyUnitsSpy.count(), 1);
892  l_Arguments = l_NotifyUnitsSpy.takeFirst();
893  l_Units = qvariant_cast<eTHM1176Units>(l_Arguments.at(0));
894  QVERIFY(l_Units == MTL::kT);
895 
896  QCOMPARE(l_NotifyRangeParmsSpy.count(), 1);
897  l_Arguments = l_NotifyRangeParmsSpy.takeFirst();
898  l_RangeParms = qvariant_cast<sRange<uParm>>(l_Arguments.at(0));
899  QVERIFY(!l_RangeParms.Auto && l_RangeParms.Range == 0.f);
900 
901  // Retrieve the operating mode and error list.
902  QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
903  l_Arguments = l_NotifyOperatingModeSpy.takeFirst();
904  l_CurrentOperatingMode = qvariant_cast<eTHM1176OperatingMode>(l_Arguments.at(0));
905  QCOMPARE(l_CurrentOperatingMode, kTHM1176NotConnected);
906 
907  QCOMPARE(l_NotifyErrorListSpy.count(), 0);
908 
909  std::cout << "- No longer connected" << std::endl;
910 
911 } // THM1176IM_Test01_Connect::TestSetCurrentInstrument
912 
913 //----------------------------------------------------------------------//
914 // main() //
915 //----------------------------------------------------------------------//
916 QTEST_MAIN(THM1176IM_Test01_Connect)
917 
918 #include "THM1176IM_Test01_Connect.moc"
MTL::kT
@ kT
Tesla.
Definition: THM1176InstrumentManagerTypes.h:30
THM1176_PROMPT_TIME
#define THM1176_PROMPT_TIME
Definition: THM1176IM_Test01_Connect.cpp:18
MTL::Instrument::CResourceList
List of VISA resource names.
Definition: IEEE488InstrumentTypes.h:26
MTL::CTHM1176UnitsList
List of measurement units.
Definition: THM1176InstrumentManagerTypes.h:46
MTL::Instrument::THM1176Types::sRange::Range
ParmType< tFlux > Range
Measurement range, if auto-ranging is not enabled.
Definition: THM1176Types.h:460
THM1176_SILLY_RESOURCE_NAME
#define THM1176_SILLY_RESOURCE_NAME
Definition: THM1176IM_Test01_Connect.cpp:22
MTL::Instrument::THM1176Types::sInputTrigger::Period_s
ParmType< F64 > Period_s
Trigger period, for timed trigger.
Definition: THM1176Types.h:407
MTL::CTHM1176InstrumentManager::Stop
void Stop(void)
Shut down the THM1176 Instrument Manager.
Definition: CTHM1176InstrumentManager.cpp:1170
MTL::Instrument::THM1176Types::sArbitraryMeasurements
Specify the measurement data to be returned.
Definition: THM1176Types.h:572
MTL::Instrument::THM1176Types::sBoundedParm::Min
DataType Min
Lower bound.
Definition: THM1176Types.h:248
THM1176_SCAN_INTERVAL
#define THM1176_SCAN_INTERVAL
Definition: THM1176IM_Test01_Connect.cpp:21
MTL::Instrument::THM1176Types::sRange< sBoundedParm >
MTL::Instrument::THM1176Types::sBoundedParm::Max
DataType Max
Upper bound.
Definition: THM1176Types.h:249
MTL::Instrument::THM1176Types::kComFormatAscii
@ kComFormatAscii
Human-legible text.
Definition: THM1176Types.h:446
MTL::Instrument::THM1176Types::sArbitraryMeasurements::NoMeasurements
U32 NoMeasurements
Return this number of measurements.
Definition: THM1176Types.h:578
PromptAndWait
static void PromptAndWait(std::string Prompt)
Definition: THM1176IM_Test01_Connect.cpp:31
MTL::Instrument::THM1176Types::CDivisorList
List of divisors, one per measurement unit.
Definition: THM1176Types.h:203
MTL::CTHM1176InstrumentManager::SetOperatingMode
void SetOperatingMode(eTHM1176OperatingMode OperatingMode)
Set a new operating mode, for example to start measuring.
Definition: CTHM1176InstrumentManager.cpp:1631
Manager
static CTHM1176InstrumentManager Manager
Definition: THM1176IM_Test01_Connect.cpp:26
MTL::Instrument::THM1176Types::sIdentifier
Instrument's identification string - parsed version.
Definition: THM1176Types.h:336
MTL::Instrument::THM1176Types::sRange::Auto
bool Auto
Auto-ranging enabled.
Definition: THM1176Types.h:459
MTL::Instrument::THM1176Types::eCommunicationFormat
eCommunicationFormat
Enumeration of possible formats for returned data.
Definition: THM1176Types.h:445
MTL
Definition: CTHM1176InstrumentManager.h:179
MTL::CTHM1176InstrumentManager
THM1176 Instrument Manager class: public interface.
Definition: CTHM1176InstrumentManager.h:539
MTL::Instrument::THM1176Types::sInputTrigger::Count
ParmType< U16 > Count
Trigger count: take this many measurements before sending results.
Definition: THM1176Types.h:408
MTL::eTHM1176Units
eTHM1176Units
Enumeration of possible measurement units, including "ADC".
Definition: THM1176InstrumentManagerTypes.h:29
MTL::Instrument::THM1176Types::sBoundedParm::Val
DataType Val
Current value.
Definition: THM1176Types.h:247
THM1176IM_Test01_Connect::~THM1176IM_Test01_Connect
~THM1176IM_Test01_Connect()
Definition: THM1176IM_Test01_Connect.cpp:74
MTL::Instrument::THM1176Types::sArbitraryMeasurements::Bz
bool Bz
Return the flux density Z-component.
Definition: THM1176Types.h:575
MTL::Instrument::THM1176Types::sAveraging< sBoundedParm >
MTL::Instrument::THM1176Types::kInputTrigSrcImmediate
@ kInputTrigSrcImmediate
Immediate trigger: start measurement immediately after previous one completes.
Definition: THM1176Types.h:397
MTL::CTHM1176InstrumentManager::Start
void Start(void)
Initialize the THM1176 Instrument Manager.
Definition: CTHM1176InstrumentManager.cpp:1045
MTL::Instrument::THM1176Types::sIdentifier::Manufacturer
std::string Manufacturer
Manufacturer name ("Metrolab Technology SA")
Definition: THM1176Types.h:337
MTL::Instrument::THM1176Types::sArbitraryMeasurements::Timestamp
bool Timestamp
Return the timestamp.
Definition: THM1176Types.h:577
CTHM1176InstrumentManager.h
Interface definition for Metrolab THM1176/TFM1186 Instrument Manager.
MTL::Instrument::THM1176Types::sIdentifier::Model
std::string Model
Model name (e.g. "THM1176-MF")
Definition: THM1176Types.h:338
MTL::kTHM1176Idle
@ kTHM1176Idle
Place the instrument in idle mode.
Definition: THM1176InstrumentManagerTypes.h:20
THM1176IM_Test01_Connect::THM1176IM_Test01_Connect
THM1176IM_Test01_Connect()
Definition: THM1176IM_Test01_Connect.cpp:69
MTL::Instrument::tResourceName
std::string tResourceName
IEEE488 resource name.
Definition: IEEE488InstrumentTypes.h:22
MTL::Instrument::THM1176Types::sInputTrigger< sBoundedParm >
MTL::Instrument::THM1176Types::CFluxList
List of flux density values.
Definition: THM1176Types.h:170
MTL::eTHM1176OperatingMode
eTHM1176OperatingMode
Operating modes used to initiate actions or provide status.
Definition: THM1176InstrumentManagerTypes.h:17
MTL::Instrument::THM1176Types::sArbitraryMeasurements::Temperature
bool Temperature
Return the sensor temperature.
Definition: THM1176Types.h:576
THM1176_CONNECT_TIME
#define THM1176_CONNECT_TIME
Definition: THM1176IM_Test01_Connect.cpp:20
MTL::Instrument::THM1176Types::CErrorList
List of errors returned by the instrument.
Definition: THM1176Types.h:232
MTL::Instrument::THM1176Types::sInputTrigger::Source
eInputTriggerSource Source
Trigger source.
Definition: THM1176Types.h:406
MTL::Instrument::THM1176Types::sArbitraryMeasurements::Bx
bool Bx
Return the flux density X-component.
Definition: THM1176Types.h:573
THM1176IM_Test01_Connect
Definition: THM1176IM_Test01_Connect.cpp:44
THM1176_BOOT_N_SCAN_TIME
#define THM1176_BOOT_N_SCAN_TIME
Definition: THM1176IM_Test01_Connect.cpp:19
MTL::CTHM1176InstrumentManager::SetCurrentInstrument
void SetCurrentInstrument(tResourceName CurrentInstrument)
Connect a new instrument.
Definition: CTHM1176InstrumentManager.cpp:1607
MTL::Instrument::THM1176Types::sBoundedParm::Def
DataType Def
Default value.
Definition: THM1176Types.h:250
MTL::Instrument::THM1176Types::sAveraging::NoPoints
ParmType< U16 > NoPoints
Number of points in block average.
Definition: THM1176Types.h:368
MTL::kTHM1176NotConnected
@ kTHM1176NotConnected
Disconnect instrument.
Definition: THM1176InstrumentManagerTypes.h:18
MTL::Instrument::THM1176Types::sArbitraryMeasurements::By
bool By
Return the flux density Y-component.
Definition: THM1176Types.h:574
MTL::Instrument::THM1176Types::sIdentifier::SerialNumber
U32 SerialNumber
Serial number.
Definition: THM1176Types.h:339