THM1176InstrumentManager  1.0
Qt Object abstraction for Metrolab THM1176
IEEE488InstrumentOpenCloseTest.h
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 #pragma once
9 
10 #include <gtest/gtest.h>
11 #include <regex>
12 #include <future>
13 
14 #include "IEEE488InstrumentTest.h"
15 
16 using namespace testing;
17 
18 class IEEE488InstrumentOpenCloseLockTest : public ::testing::Test
19 {
20 protected:
21  static IEEE4888_TEST_RESOURCE_MANAGER_CLASS * pResourceManager;
22 
23  static void SetUpTestCase()
24  {
25  pResourceManager = new IEEE4888_TEST_RESOURCE_MANAGER_CLASS;
26  ASSERT_NE(nullptr, pResourceManager);
27  ASSERT_EQ(true, pResourceManager->Initialize());
28  }
29 
30  static void TearDownTestCase()
31  {
32  delete pResourceManager;
33  pResourceManager = nullptr;
34  }
35 };
36 
37 static const U32 IEEE488_TEST_DURATION = 5; // s
38 IEEE4888_TEST_RESOURCE_MANAGER_CLASS * IEEE488InstrumentOpenCloseLockTest::pResourceManager = nullptr;
39 
42 static void l_OpenLoopQueryClose(IEEE4888_TEST_RESOURCE_MANAGER_CLASS * pResourceManager,
43  std::string InstrumentName,
44  U32 NSeconds,
45  std::promise<bool> & rSucceeded,
46  std::promise<U32> & rNLoopsPerformed)
47 {
48  bool l_Status = true;
49  U32 l_LoopCount = 0;
50  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = nullptr;
51  try
52  {
53  // Make sure we got a non-null Resource Manager
54  if (nullptr == pResourceManager) throw;
55 
56  // Create an Instrument object and open it.
57  l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, InstrumentName);
58  if (nullptr == l_pInstrument ||
59  !l_pInstrument->Open() ||
60  !l_pInstrument->SetTimeout(1000*NSeconds))
61  throw;
62 
63  // Perform queries for the requested time period.
64  auto l_EndTime = std::chrono::system_clock::now() + std::chrono::seconds(NSeconds);
65  do
66  {
67  if (!l_pInstrument->LockExclusive(1000*NSeconds)) throw;
68  if (!l_pInstrument->Write ("*IDN?")) throw;
69  CSCPIBuffer l_Buffer;
70  if (!l_pInstrument->Read (l_Buffer)) throw;
71  if (!CheckIDNResponse (l_Buffer)) throw;
72  if (!l_pInstrument->Unlock()) throw;
73  ++l_LoopCount;
74  } while (std::chrono::system_clock::now() < l_EndTime);
75 
76  }
77  catch (...)
78  {
79  l_Status = false;
80  }
81 
82  // Close and delete the instrument.
83  if (nullptr != l_pInstrument)
84  {
85  l_pInstrument->Close();
86  delete l_pInstrument;
87  }
88 
89  // Return the promised parameters.
90  rSucceeded.set_value(l_Status);
91  rNLoopsPerformed.set_value(l_LoopCount);
92 }
93 
96 static void l_OpenLockWaitClose(IEEE4888_TEST_RESOURCE_MANAGER_CLASS * pResourceManager,
97  std::string InstrumentName,
98  U32 NSeconds,
99  std::promise<bool> & rSucceeded)
100 {
101  bool l_Status = true;
102  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = nullptr;
103  try
104  {
105  // Make sure we got a non-null Resource Manager
106  if (nullptr == pResourceManager)
107  throw;
108 
109  // Create an Instrument object, open it, and lock it.
110  l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, InstrumentName);
111  if (nullptr == l_pInstrument ||
112  !l_pInstrument->Open() ||
113  !l_pInstrument->LockExclusive(1000))
114  throw;
115 
116  // Keep it locked for the specified amount of time.
117  std::this_thread::sleep_for(std::chrono::seconds(NSeconds));
118  }
119  catch (...)
120  {
121  l_Status = false;
122  }
123 
124  // Close and delete the instrument.
125  if (nullptr != l_pInstrument)
126  {
127  l_pInstrument->Close();
128  delete l_pInstrument;
129  }
130 
131  // Return the promised status flag.
132  rSucceeded.set_value(l_Status);
133 }
134 
137 {
138  // Find all THM1176 instruments.
139  CResourceList l_InstrumentList;
140  ASSERT_EQ(true, pResourceManager->FindResources(l_InstrumentList, IEEE4888_TEST_RESOURCE_FILTER));
141  ASSERT_EQ(false, l_InstrumentList.empty());
142 
143  // Create the Instrument. Run the tests on the first one in the list.
144  std::string l_InstrumentName = l_InstrumentList.front();
145  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, l_InstrumentName);
146  ASSERT_NE(nullptr, l_pInstrument);
147  ASSERT_EQ(false, l_pInstrument->IsOpen());
148 
149  // Open the instrument.
150  ASSERT_EQ(true, l_pInstrument->Open());
151  ASSERT_EQ(true, l_pInstrument->IsOpen());
152 
153  // Check the status.
154  I32 l_Status = l_pInstrument->Status();
155  ASSERT_EQ(0, l_Status);
156  std::string l_StatusDescription = l_pInstrument->StatusDescription(l_Status);
157  std::regex l_Regex(".*Success.*", std::regex::icase);
158  std::smatch l_Match;
159  EXPECT_EQ(true, std::regex_match(l_StatusDescription, l_Match, l_Regex));
160 
161  // Close the instrument.
162  l_pInstrument->Close();
163  ASSERT_EQ(false, l_pInstrument->IsOpen());
164 
165  // Destroy the object.
166  delete l_pInstrument;
167 
168 }
169 
172 {
173  // Find all THM1176 instruments.
174  CResourceList l_InstrumentList;
175  ASSERT_EQ(true, pResourceManager->FindResources(l_InstrumentList, IEEE4888_TEST_RESOURCE_FILTER));
176  ASSERT_EQ(false, l_InstrumentList.empty());
177 
178  // Create the Instrument. Run the tests on the first one in the list.
179  std::string l_InstrumentName = l_InstrumentList.front();
180  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, l_InstrumentName);
181  ASSERT_NE(nullptr, l_pInstrument);
182  ASSERT_EQ(false, l_pInstrument->IsOpen());
183 
184  // Open the instrument.
185  ASSERT_EQ(true, l_pInstrument->Open());
186  ASSERT_EQ(true, l_pInstrument->IsOpen());
187 
188  // Check the status.
189  I32 l_Status = l_pInstrument->Status();
190  ASSERT_EQ(0, l_Status);
191  std::string l_StatusDescription = l_pInstrument->StatusDescription(l_Status);
192  std::regex l_Regex(".*Success.*", std::regex::icase);
193  std::smatch l_Match;
194  EXPECT_EQ(true, std::regex_match(l_StatusDescription, l_Match, l_Regex));
195 
196  // Close the instrument.
197  l_pInstrument->Close();
198  ASSERT_EQ(false, l_pInstrument->IsOpen());
199 
200  // Open the instrument.
201  ASSERT_EQ(true, l_pInstrument->Open());
202  ASSERT_EQ(true, l_pInstrument->IsOpen());
203 
204  // Check the status.
205  l_Status = l_pInstrument->Status();
206  ASSERT_EQ(0, l_Status);
207  l_StatusDescription = l_pInstrument->StatusDescription(l_Status);
208  l_Regex = std::regex(".*Success.*", std::regex::icase);
209  EXPECT_EQ(true, std::regex_match(l_StatusDescription, l_Match, l_Regex));
210 
211  // Try to open it again - should just sail through.
212  ASSERT_EQ(true, l_pInstrument->Open());
213 
214  // Close the instrument.
215  l_pInstrument->Close();
216  ASSERT_EQ(false, l_pInstrument->IsOpen());
217 
218  // Try to close it again - should just sail through.
219  l_pInstrument->Close();
220  ASSERT_EQ(0, l_pInstrument->Status());
221 
222  // Destroy the object.
223  delete l_pInstrument;
224 
225 }
226 
229 {
230  // Find the THM1176 instrument.
231  CResourceList l_InstrumentList;
232  ASSERT_EQ(true, pResourceManager->FindResources(l_InstrumentList, IEEE4888_TEST_RESOURCE_FILTER));
233  ASSERT_EQ(false, l_InstrumentList.empty());
234 
235  // Create the Instrument. Run the tests on the first one in the list.
236  std::string l_InstrumentName = l_InstrumentList.front();
237  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, l_InstrumentName);
238  ASSERT_NE(nullptr, l_pInstrument);
239 
240  // Launch a thread to perform queries during the specified time period.
241  std::promise<bool> l_PromisedStatus;
242  std::future<bool> l_FutureStatus = l_PromisedStatus.get_future();
243  std::promise<U32> l_PromisedLoopCount;
244  std::future<U32> l_FutureLoopcount = l_PromisedLoopCount.get_future();
245  std::thread l_Thread(l_OpenLoopQueryClose, pResourceManager, l_InstrumentName, IEEE488_TEST_DURATION, std::ref(l_PromisedStatus), std::ref(l_PromisedLoopCount));
246 
247  // Open the instrument.
248  EXPECT_EQ(true, l_pInstrument->Open());
249  EXPECT_EQ(true, l_pInstrument->SetTimeout(1000*IEEE488_TEST_DURATION));
250 
251  // Perform queries for the requested time period.
252  // Note: With NI-VISA and Qt, there seems to be a timing issue; hence the sleep_for() calls.
253  // From USB protocol analysis, it looks like it's related to periodic calls to assert REN (Remote ENable);
254  // the following Write/Read cycle tends to fail. The mechanism is not at all clear.
255  U32 l_LoopCount = 0;
256  auto l_EndTime = std::chrono::system_clock::now() + std::chrono::seconds(IEEE488_TEST_DURATION);
257  do
258  {
259  ASSERT_EQ(true, l_pInstrument->LockExclusive(1000*IEEE488_TEST_DURATION));
260  ASSERT_EQ(true, l_pInstrument->Write ("*IDN?"));
261  std::this_thread::sleep_for(std::chrono::milliseconds(10));
262  CSCPIBuffer l_Buffer;
263  ASSERT_EQ(true, l_pInstrument->Read (l_Buffer));
264  std::this_thread::sleep_for(std::chrono::milliseconds(10));
265  EXPECT_EQ(true, CheckIDNResponse (l_Buffer));
266  ASSERT_EQ(true, l_pInstrument->Unlock());
267  ++l_LoopCount;
268  } while (std::chrono::system_clock::now() < l_EndTime);
269 
270  // Wait for the child thread to end and check whether it returned success,
271  // and whether the loop counts were both positive.
272  EXPECT_GT(l_LoopCount, 10);
273  EXPECT_EQ(true, l_FutureStatus.get());
274  EXPECT_GT(l_FutureLoopcount.get(), 10);
275  l_Thread.join();
276 
277  // Close and delete the instrument.
278  l_pInstrument->Close();
279  delete l_pInstrument;
280 }
281 
284 {
285  // Find the THM1176 instrument.
286  CResourceList l_InstrumentList;
287  ASSERT_EQ(true, pResourceManager->FindResources(l_InstrumentList, IEEE4888_TEST_RESOURCE_FILTER));
288  ASSERT_EQ(false, l_InstrumentList.empty());
289 
290  // Create the Instrument. Run the tests on the first one in the list.
291  std::string l_InstrumentName = l_InstrumentList.front();
292  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, l_InstrumentName);
293 
294  // Launch a thread to keep the instrument locked for the specified test duration, giving it a second to start.
295  std::promise<bool> l_PromisedStatus;
296  std::future<bool> l_FutureStatus = l_PromisedStatus.get_future();
297  std::thread l_Thread(l_OpenLockWaitClose, pResourceManager, l_InstrumentName, IEEE488_TEST_DURATION, std::ref(l_PromisedStatus));
298  std::this_thread::sleep_for(std::chrono::seconds(1));
299 
300  // Open the instrument and obtain a lock.
301  // Should fail because we time out before the other thread closes the instrument.
302  ASSERT_EQ(true, l_pInstrument->Open());
303  auto l_StartTime = std::chrono::system_clock::now();
304  EXPECT_EQ(false, l_pInstrument->LockExclusive(1000*(IEEE488_TEST_DURATION-2)));
305  auto l_StopTime = std::chrono::system_clock::now();
306  std::chrono::duration<F64> l_Duration = l_StopTime - l_StartTime;
307  EXPECT_NEAR(static_cast<F64>(IEEE488_TEST_DURATION-2), l_Duration.count(), 0.1);
308 
309  // Wait for the child thread to end and check whether it returned success.
310  EXPECT_EQ(true, l_FutureStatus.get());
311  l_Thread.join();
312 
313  // Close and delete the instrument.
314  l_pInstrument->Close();
315  delete l_pInstrument;
316 }
317 
320 {
321  // Find the THM1176 instrument.
322  CResourceList l_InstrumentList;
323  ASSERT_EQ(true, pResourceManager->FindResources(l_InstrumentList, IEEE4888_TEST_RESOURCE_FILTER));
324  ASSERT_EQ(false, l_InstrumentList.empty());
325 
326  // Create the Instrument. Run the tests on the first one in the list.
327  std::string l_InstrumentName = l_InstrumentList.front();
328  IEEE4888_TEST_INSTRUMENT_CLASS * l_pInstrument = new IEEE4888_TEST_INSTRUMENT_CLASS(*pResourceManager, l_InstrumentName);
329 
330  // Launch a thread to keep the instrument locked for the specified test duration, giving it a second to start.
331  std::promise<bool> l_PromisedStatus;
332  std::future<bool> l_FutureStatus = l_PromisedStatus.get_future();
333  std::thread l_Thread(l_OpenLockWaitClose, pResourceManager, l_InstrumentName, IEEE488_TEST_DURATION, std::ref(l_PromisedStatus));
334  std::this_thread::sleep_for(std::chrono::seconds(1));
335 
336  // Open the instrument and obtain a lock.
337  // Should succeed when the other thread closes its instrument.
338  ASSERT_EQ(true, l_pInstrument->Open());
339  auto l_StartTime = std::chrono::system_clock::now();
340  EXPECT_EQ(true, l_pInstrument->LockExclusive(1000*(IEEE488_TEST_DURATION+1)));
341  auto l_StopTime = std::chrono::system_clock::now();
342  std::chrono::duration<F64> l_Duration = l_StopTime - l_StartTime;
343  EXPECT_NEAR(static_cast<F64>(IEEE488_TEST_DURATION-1), l_Duration.count(), 0.1);
344 
345  // Wait for the child thread to end and check whether it returned success.
346  EXPECT_EQ(true, l_FutureStatus.get());
347  l_Thread.join();
348 
349  // Close and delete the instrument.
350  l_pInstrument->Close();
351  delete l_pInstrument;
352 }
IEEE488InstrumentOpenCloseLockTest::pResourceManager
static IEEE4888_TEST_RESOURCE_MANAGER_CLASS * pResourceManager
Definition: IEEE488InstrumentOpenCloseTest.h:21
IEEE488InstrumentOpenCloseLockTest::TearDownTestCase
static void TearDownTestCase()
Definition: IEEE488InstrumentOpenCloseTest.h:30
MTL::Instrument::CResourceList
List of VISA resource names.
Definition: IEEE488InstrumentTypes.h:26
IEEE488InstrumentOpenCloseLockTest
Definition: IEEE488InstrumentOpenCloseTest.h:19
l_OpenLoopQueryClose
static void l_OpenLoopQueryClose(IEEE4888_TEST_RESOURCE_MANAGER_CLASS *pResourceManager, std::string InstrumentName, U32 NSeconds, std::promise< bool > &rSucceeded, std::promise< U32 > &rNLoopsPerformed)
Utility function to be run in a separate thread: open an instrument, do an *IDN?, wait a while and th...
Definition: IEEE488InstrumentOpenCloseTest.h:42
IEEE488InstrumentTest.h
Utility functions used to test IEEE488Instrument API.
l_OpenLockWaitClose
static void l_OpenLockWaitClose(IEEE4888_TEST_RESOURCE_MANAGER_CLASS *pResourceManager, std::string InstrumentName, U32 NSeconds, std::promise< bool > &rSucceeded)
Utility function to be run in a separate thread: keep an instrument locked for a while.
Definition: IEEE488InstrumentOpenCloseTest.h:96
TEST_F
TEST_F(IEEE488InstrumentOpenCloseLockTest, OpenClose)
Test Instrument object creation/destruction, Open, Close, Status, StatusDescription.
Definition: IEEE488InstrumentOpenCloseTest.h:136
I32
int I32
32-bit signed integer.
Definition: OSDefines.h:28
IEEE488InstrumentOpenCloseLockTest::SetUpTestCase
static void SetUpTestCase()
Definition: IEEE488InstrumentOpenCloseTest.h:23
CheckIDNResponse
bool CheckIDNResponse(const CSCPIBuffer &rBuffer)
Sanity-check of the response to an *IDN? query.
Definition: IEEE488InstrumentTest.cpp:70
IEEE488_TEST_DURATION
static const U32 IEEE488_TEST_DURATION
Definition: IEEE488InstrumentOpenCloseTest.h:37
MTL::Instrument::CSCPIBuffer
Instrument Buffer.
Definition: SCPIInstrumentBuffer.h:44
F64
double F64
64-bit floating-point number.
Definition: OSDefines.h:35
U32
unsigned int U32
32-bit unsigned integer.
Definition: OSDefines.h:32