THM1176InstrumentManager  1.0
Qt Object abstraction for Metrolab THM1176
USBTMCInstrument.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 // Standard includes
9 #include <string>
10 #include <cstring>
11 #include <regex>
12 #include <map>
13 #include <chrono>
14 #include <thread>
15 
16 // Personal includes
17 #include "USBTMCInstrument.h"
18 #include "USBTMCPrivate.h"
19 #include "OSDefines.h"
20 #include "Helpers.h"
21 
22 // Definitions
23 #define DEBUG_MTL_USBTMC_INSTRUMENT 0
24 #define DEBUG_MTL_USBTMC_INSTRUMENT_ERRORS_ONLY 0
25 #if (defined(_DEBUG) && defined(DEBUG_MTL_USBTMC_INSTRUMENT) && DEBUG_MTL_USBTMC_INSTRUMENT)
26  #if (defined(DEBUG_MTL_USBTMC_INSTRUMENT_ERRORS_ONLY) && DEBUG_MTL_USBTMC_INSTRUMENT_ERRORS_ONLY)
27  #define MTL_USBTMC_INSTRUMENT_DEBUG_COUT(__X__)
28  #else
29  #define MTL_USBTMC_INSTRUMENT_DEBUG_COUT(__X__) COUT(__X__)
30  #endif
31  #define MTL_USBTMC_INSTRUMENT_DEBUG_CERR(__X__) CERR(__X__)
32 #else
33  #define MTL_USBTMC_INSTRUMENT_DEBUG_COUT(__X__)
34  #define MTL_USBTMC_INSTRUMENT_DEBUG_CERR(__X__)
35 #endif
36 #define MTL_USBTMC_PAUSE_BETWEEN_READS 2 // ms
37 
38 using namespace MTL::Instrument;
39 
40 //----------------------------------------------------------------------//
41 // Resource Manager //
42 //----------------------------------------------------------------------//
43 //------------------------------------------//
44 // Constructors / destructors
46  m_pContext(nullptr)
47 {
48 
49 } // CUSBTMCResourceManager::CUSBTMCResourceManager
50 
52 {
53  // Close the devices on the device list.
54  for (auto l_pDeviceListEntry = m_DeviceList.begin(); l_pDeviceListEntry != m_DeviceList.end(); l_pDeviceListEntry++)
55  {
56  if (l_pDeviceListEntry->pDevice != nullptr)
57  libusb_unref_device(l_pDeviceListEntry->pDevice);
58  }
59  m_DeviceList.clear();
60 
61  // Shut down libusb.
62  if (m_pContext != nullptr)
63  libusb_exit(m_pContext);
64 
65 } // CUSBTMCResourceManager::~CUSBTMCResourceManager
66 
67 //------------------------------------------//
68 // Initialization
70 {
71  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
72  CLockGuard<CMutex> l_LockGuard(m_Lock);
73 
74  try
75  {
76  // Initialize libusb.
77  m_Status = libusb_init (&m_pContext);
78  if (m_Status != LIBUSB_SUCCESS)
79  throw Exception(m_Status, MTL__LOCATION__);
80 
81  // Set the log level.
82  m_Status = libusb_set_option (m_pContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING);
83  if (m_Status != LIBUSB_SUCCESS)
84  throw Exception(m_Status, MTL__LOCATION__);
85  }
86 
87  // Handle errors.
89  {
90  MTL_Unused(rE)
92  if (m_pContext != nullptr)
93  libusb_exit (m_pContext);
94  return false;
95  }
96 
97  return true;
98 
99 } // CUSBTMCResourceManager::Initialize
100 
101 //------------------------------------------//
102 // Find resources
103 bool CUSBTMCResourceManager::FindResources(CResourceList & rList, std::string Filter)
104 {
105  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
106  CLockGuard<CMutex> l_LockGuard(m_Lock);
107 
108  libusb_device ** l_USBDeviceList = nullptr;
109  libusb_device_handle * l_hDevice = nullptr;
110  tUSBTMCDeviceListEntry l_NewDeviceListEntry;
111  l_NewDeviceListEntry.clear();
112 
113  try
114  {
115  // Clear the resource lists.
116  rList.clear();
117  for (auto l_pDeviceListEntry = m_DeviceList.begin(); l_pDeviceListEntry != m_DeviceList.end(); l_pDeviceListEntry++)
118  l_pDeviceListEntry->PluggedIn = false;
119 
120  // Retrieve the Vendor ID and Product ID from the Filter.
121  const std::regex l_RegexVID_PID("([0-9]+):([0-9]+)");
122  std::smatch l_MatchVID_PID;
123  if (!std::regex_match(Filter, l_MatchVID_PID, l_RegexVID_PID) ||
124  l_MatchVID_PID.size() != 3)
126 
127  U16 l_VID = static_cast<U16>(stoi(l_MatchVID_PID[1].str()));
128  U16 l_PID = static_cast<U16>(stoi(l_MatchVID_PID[2].str()));
129 
130  // List connected USB devices.
131  ssize_t l_DeviceCount = libusb_get_device_list(nullptr, &l_USBDeviceList);
132  if (l_DeviceCount < 0)
133  throw Exception(static_cast<I32>(l_DeviceCount), MTL__LOCATION__);
134 
135  // Loop through the devices to check whether any of them match VID:PID.
136  for (ssize_t i = 0; i < l_DeviceCount; i++)
137  {
138  // Clear the device pointer, in case of exception.
139  l_NewDeviceListEntry.clear();
140 
141  // Get the device descriptor of this device.
142  libusb_device * l_pUSBDevice = l_USBDeviceList[i];
143  struct libusb_device_descriptor l_USBDeviceDescriptor;
144  m_Status = libusb_get_device_descriptor(l_pUSBDevice, &l_USBDeviceDescriptor);
145  if (m_Status != LIBUSB_SUCCESS)
146  throw Exception(m_Status, MTL__LOCATION__);
147 
148  // Bail if this descriptor does not match VID:PID.
149  if (l_USBDeviceDescriptor.idVendor != l_VID ||
150  l_USBDeviceDescriptor.idProduct != l_PID)
151  continue;
152 
153  // Get the port-path for this device.
154  U8 l_PortNumbers[USB_MAX_PORT_DEPTH];
155  I32 l_PathLength = libusb_get_port_numbers(l_pUSBDevice, l_PortNumbers, USB_MAX_PORT_DEPTH);
156  if (l_PathLength < 0)
157  throw Exception(l_PathLength, MTL__LOCATION__);
158  std::vector<U8> l_PortPath;
159  for (I32 i = 0; i < l_PathLength; i++)
160  l_PortPath.push_back(l_PortNumbers[i]);
161 
162  // If this device is already in the device list, copy the resource name to the output,
163  // mark the device as plugged in, and bail.
164  auto l_pDeviceListEntry = m_DeviceList.begin();
165  for (; l_pDeviceListEntry != m_DeviceList.end(); l_pDeviceListEntry++)
166  if (l_PortPath == l_pDeviceListEntry->PortPath) break;
167  if (l_pDeviceListEntry != m_DeviceList.end())
168  {
169  rList.push_back(l_pDeviceListEntry->ResourceName);
170  l_pDeviceListEntry->PluggedIn = true;
171  continue;
172  }
173 
174  // Get the handle for this device.
175  // This could fail, for example, if the wrong driver is assigned.
176  m_Status = libusb_open(l_pUSBDevice, &l_hDevice);
177  if (m_Status != LIBUSB_SUCCESS)
178  continue;
179 
180  // Set up the new device list.
181  libusb_ref_device(l_pUSBDevice);
182  l_NewDeviceListEntry.pDevice = l_pUSBDevice;
183  l_NewDeviceListEntry.PortPath = l_PortPath;
184  l_NewDeviceListEntry.PluggedIn = true;
185 
186  // Fetch the manufacturer, product and serial number.
188  I32 l_StringLength;
189  l_StringLength = libusb_get_string_descriptor_ascii (l_hDevice, l_USBDeviceDescriptor.iManufacturer, l_String, USB_DESCRIPTOR_STRING_LENGTH);
190  if (l_StringLength < 0)
191  throw Exception(l_StringLength, MTL__LOCATION__);
192  std::string l_Manufacturer = std::string(reinterpret_cast<char *>(l_String), static_cast<size_t>(l_StringLength));
193 
194  l_StringLength = libusb_get_string_descriptor_ascii (l_hDevice, l_USBDeviceDescriptor.iProduct, l_String, USB_DESCRIPTOR_STRING_LENGTH);
195  if (l_StringLength < 0)
196  throw Exception(l_StringLength, MTL__LOCATION__);
197  std::string l_Product = std::string(reinterpret_cast<char *>(l_String), static_cast<size_t>(l_StringLength));
198 
199  l_StringLength = libusb_get_string_descriptor_ascii (l_hDevice, l_USBDeviceDescriptor.iSerialNumber, l_String, USB_DESCRIPTOR_STRING_LENGTH);
200  if (l_StringLength < 0)
201  throw Exception(l_StringLength, MTL__LOCATION__);
202  std::string l_SerialNumber = std::string(reinterpret_cast<char *>(l_String), static_cast<size_t>(l_StringLength));
203 
204  l_NewDeviceListEntry.ResourceName = l_Manufacturer + " " + l_Product + " " + l_SerialNumber;
205 
206  // Close the device.
207  libusb_close(l_hDevice);
208  l_hDevice = nullptr;
209 
210  // Add the device to the list.
211  m_DeviceList.push_back(l_NewDeviceListEntry);
212  rList.push_back(l_NewDeviceListEntry.ResourceName);
213 
214  } // Loop through the devices
215 
216  // Free the list of connected USB devices, unreferencing the devices.
217  libusb_free_device_list(l_USBDeviceList, 1);
218 
219  // Delete Device List entries for devices that are no longer connected.
220  for (auto l_pDeviceListEntry = m_DeviceList.begin(); l_pDeviceListEntry != m_DeviceList.end();)
221  {
222  if (!l_pDeviceListEntry->PluggedIn)
223  {
224  libusb_unref_device(l_pDeviceListEntry->pDevice);
225  l_pDeviceListEntry = m_DeviceList.erase(l_pDeviceListEntry);
226  }
227  else
228  {
229  ++l_pDeviceListEntry;
230  }
231  } // Loop to delete device list entries of devices that have been unplugged.
232 
233  // Set an error status if the device list is empty.
234  if (rList.size() == 0)
235  m_Status = LIBUSB_ERROR_NO_DEVICE;
236 
237  } // try
238 
239  // Handle errors. Deallocate all the resources we may have allocated.
241  {
242  MTL_Unused(rE)
244 
245  if (l_USBDeviceList != nullptr)
246  libusb_free_device_list(l_USBDeviceList, 1);
247  if (l_hDevice != nullptr)
248  libusb_close(l_hDevice);
249  if (l_NewDeviceListEntry.pDevice != nullptr)
250  libusb_unref_device(l_NewDeviceListEntry.pDevice);
251  rList.clear();
252  for (auto l_pDeviceListEntry = m_DeviceList.begin(); l_pDeviceListEntry != m_DeviceList.end(); l_pDeviceListEntry++)
253  {
254  libusb_unref_device(l_pDeviceListEntry->pDevice);
255  }
256  m_DeviceList.clear();
257 
258  return false;
259  }
260 
261  return true;
262 
263 } // CUSBTMCResourceManager::FindResources
264 
265 // Retrieve a device list entry from a previous call to FindResources.
266 bool CUSBTMCResourceManager::GetDeviceListEntry(const tResourceName ResourceName, libusb_device * & pDevice)
267 {
268  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
269  CLockGuard<CMutex> l_LockGuard(m_Lock);
270 
271  // Search the list for the given resource name.
272  tUSBTMCDeviceListEntry * l_pDeviceListEntry = nullptr;
273  for (auto l_pDeviceList = m_DeviceList.begin(); l_pDeviceList != m_DeviceList.end(); l_pDeviceList++)
274  {
275  if (l_pDeviceList->ResourceName == ResourceName)
276  {
277  l_pDeviceListEntry = &(*l_pDeviceList);
278  break;
279  }
280  }
281 
282  // If not found, return an error.
283  if (l_pDeviceListEntry == nullptr)
284  {
286  return false;
287  }
288 
289  // Return the device pointer.
290  // Note: must increment the reference count here for thread safety: this is the only place
291  // where CUSBTMCResourceManager and CUSBTMCInstrument are both blocked.
292  pDevice = l_pDeviceListEntry->pDevice;
293  libusb_ref_device(pDevice);
294 
295  return true;
296 
297 } // CUSBTMCResourceManager::GetDeviceListEntry
298 
299 //------------------------------------------//
300 // Info
302 {
303  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
304 
305  if (Status <= 0)
306  return libusb_error_name(Status);
307  else
309 
310 } // CUSBTMCResourceManager::StatusDescription
311 
313 {
314  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
315  CLockGuard<CMutex> l_LockGuard(m_Lock);
316 
317  return (m_Status == LIBUSB_ERROR_TIMEOUT);
318 
319 } // CUSBTMCResourceManager::Timeout
320 
321 //------------------------------------------//
322 // Exception
323 MTL::CException<CUSBTMCResourceManager> CUSBTMCResourceManager::Exception(I32 Status, std::string Location)
324 {
325  m_Status = Status;
327 }
328 
329 //----------------------------------------------------------------------//
330 // Instrument //
331 //----------------------------------------------------------------------//
332 // Utility functions to build write headers and check read headers and responses.
333 static bool USBTMCReadSTBResponse(U8 * pResponse,
334  U8 USBTMC_status,
335  U8 bTag,
336  U8 StatusByte)
337 {
338  return (R8(pResponse + 0) == USBTMC_status &&
339  R8(pResponse + 1) == bTag &&
340  R8(pResponse + 2) == StatusByte);
341 }
342 
343 static void USBTMCBulkOutHeaderWrite(U8 * pHeader,
344  U8 MsgID,
345  U8 bTag,
346  U32 TransferSize,
347  U8 bmTransferAttributes,
348  char TermChar)
349 {
350  W8 (pHeader + 0, MsgID);
351  W8 (pHeader + 1, bTag);
352  W8 (pHeader + 2, ~bTag);
353  W8 (pHeader + 3, 0);
354  WL32(pHeader + 4, TransferSize);
355  W8 (pHeader + 8, bmTransferAttributes);
356  W8 (pHeader + 9, TermChar);
357  WL16(pHeader + 10, 0);
358 }
359 
360 static bool USBTMCBulkInHeaderRead(U8 * pHeader,
361  U8 MsgID,
362  U8 bTag,
363  I32 & TransferSize,
364  U8 & bmTransferAttributes)
365 {
366  if (R8(pHeader + 0) != MsgID ||
367  R8(pHeader + 1) != bTag ||
368  R8(pHeader + 2) != (unsigned char)~bTag)
369  return false;
370  TransferSize = RL32(pHeader + 4);
371  bmTransferAttributes = R8(pHeader + 8);
372 
373  return true;
374 }
375 
376 //------------------------------------------//
377 // Utility classes for device access control.
379 {
380 public:
381  std::timed_mutex Mutex;
383  tControlRecord(void): UseCount(1)
384  { }
386  { assert (0 == UseCount); }
387 };
388 
389 static class: public std::map<libusb_device *, tControlRecord *>
390 {
391 private:
392  CMutex m_Lock;
393 public:
394  bool Register(libusb_device * pDevice)
395  {
396  CLockGuard<CMutex> l_LockGuard(m_Lock);
397  auto l_pClaimCheck = find(pDevice);
398  if (l_pClaimCheck != end())
399  {
400  l_pClaimCheck->second->UseCount++;
401  }
402  else
403  {
404  tControlRecord * l_pNewControlRecord = new tControlRecord;
405  emplace(pDevice, l_pNewControlRecord);
406  libusb_ref_device(pDevice);
407  }
408  return true;
409  }
410  bool Unregister(libusb_device * pDevice)
411  {
412  auto l_pClaimCheck = find(pDevice);
413  if (l_pClaimCheck != end())
414  {
415  l_pClaimCheck->second->UseCount--;
416  if (0 == l_pClaimCheck->second->UseCount)
417  {
418  delete l_pClaimCheck->second;
419  erase(l_pClaimCheck);
420  libusb_unref_device(pDevice);
421  }
422  return true;
423  }
424  else
425  {
426  return false;
427  }
428  }
429  bool Claim(libusb_device * pDevice, U32 Timeout = 0)
430  {
431  m_Lock.lock();
432  auto l_pClaimCheck = find(pDevice);
433  if (l_pClaimCheck == end())
434  return false;
435  m_Lock.unlock();
436  return l_pClaimCheck->second->Mutex.try_lock_for(std::chrono::milliseconds(Timeout));
437  }
438  bool Release(libusb_device * pDevice)
439  {
440  CLockGuard<CMutex> l_LockGuard(m_Lock);
441  auto l_pClaimCheck = find(pDevice);
442  if (l_pClaimCheck != end())
443  {
444  l_pClaimCheck->second->Mutex.unlock();
445  return true;
446  }
447  else
448  return false;
449  }
450 
452 
453 //------------------------------------------//
454 // Constructors / destructors
456  : CIEEE488Instrument(rRM, Rsrc), m_pDevice(nullptr), m_hDevice(nullptr),
457  m_ConfigurationNo(0), m_InterfaceNo(0), m_InterruptEndpoint(0), m_BulkInEndpoint(0), m_BulkOutEndpoint(0),
458  m_BulkInMaxPacketSize(0), m_bTag(0), m_ExclusiveLock(false)
459 {
460 
461 } // CUSBTMCInstrument::CUSBTMCInstrument
462 
464 {
465  // Make sure the device is closed.
466  Close();
467 
468  // Make sure the lock is released.
469  Unlock();
470 
471 } // CUSBTMCInstrument::~CUSBTMCInstrument
472 
473 //------------------------------------------//
474 // Connection
476 {
477  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
478  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
479 
480  struct libusb_config_descriptor * l_pConfig = nullptr;
481 
482  try
483  {
484  // If the device is already open, we're done.
485  if (IsOpen()) return true;
486 
487  // Get the device list entry.
488  if (!dynamic_cast<CUSBTMCResourceManager *>(&m_rRrsrcMan)->GetDeviceListEntry(m_Rsrc, m_pDevice))
490 
491  // Get the device descriptor of this device.
492  struct libusb_device_descriptor l_USBDeviceDescriptor;
493  m_Status = libusb_get_device_descriptor(m_pDevice, &l_USBDeviceDescriptor);
494  if (m_Status != LIBUSB_SUCCESS)
495  throw Exception(m_Status, MTL__LOCATION__);
496 
497  // Loop through the configurations and interfaces to find the USBTMC-USB488 interface.
498  bool l_FoundInterface = false;
499  for (U8 l_iConf = 0; l_iConf < l_USBDeviceDescriptor.bNumConfigurations; l_iConf++)
500  {
501  int l_ReturnValue = libusb_get_config_descriptor(m_pDevice, l_iConf, &l_pConfig);
502  if (l_ReturnValue < 0 && l_ReturnValue != LIBUSB_ERROR_NOT_FOUND)
503  continue;
504 
505  // Loop through interfaces and check whether they are the USBTMC-USB488 interface.
506  for (int l_iIntfc = 0; l_iIntfc < l_pConfig->bNumInterfaces; l_iIntfc++)
507  {
508  const struct libusb_interface_descriptor * l_pIntfc = l_pConfig->interface[l_iIntfc].altsetting;
509  if (l_pIntfc->bInterfaceClass != LIBUSB_CLASS_APPLICATION ||
510  l_pIntfc->bInterfaceSubClass != SUBCLASS_USBTMC ||
511  l_pIntfc->bInterfaceProtocol != USBTMC_USB488)
512  continue;
513  m_ConfigurationNo = l_pConfig->bConfigurationValue;
514  m_InterfaceNo = l_pIntfc->bInterfaceNumber;
515 
516  // Loop through the endpoints to identify BULKIN, BULKOUT, INETERRUPT.
517  for (int l_iEP = 0; l_iEP < l_pIntfc->bNumEndpoints; l_iEP++)
518  {
519  const struct libusb_endpoint_descriptor * l_pEndpoint = &l_pIntfc->endpoint[l_iEP];
520  if (l_pEndpoint->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
521  !(l_pEndpoint->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)))
522  {
523  m_BulkOutEndpoint = l_pEndpoint->bEndpointAddress;
524  }
525  if (l_pEndpoint->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
526  l_pEndpoint->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))
527  {
528  m_BulkInEndpoint = l_pEndpoint->bEndpointAddress;
529  }
530  if (l_pEndpoint->bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
531  l_pEndpoint->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))
532  {
533  m_InterruptEndpoint = l_pEndpoint->bEndpointAddress;
534  }
535  }
536 
537  // Get the MaxPacketSize for the BulkIn endpoint.
538  m_BulkInMaxPacketSize = libusb_get_max_packet_size(m_pDevice, m_BulkInEndpoint);
539 
540  // Flag that we found the interface.
541  l_FoundInterface = true;
542 
543  } // Loop through interfaces
544 
545  // Free the configuration descriptor.
546  libusb_free_config_descriptor(l_pConfig);
547  l_pConfig = nullptr;
548  if (l_FoundInterface) break;
549 
550  } // Loop through configuration descriptors.
551 
552  // Make sure we found the interface.
553  if (!l_FoundInterface)
555 
556  // Get the handle to the device.
557  m_Status = libusb_open(m_pDevice, &m_hDevice);
558  if (m_Status != LIBUSB_SUCCESS)
559  throw Exception(m_Status, MTL__LOCATION__);
560 
561  // Set to detach the kernel driver automatically.
562  // Note: this might return LIBUSB_ERROR_NOT_SUPPORTED, but we don't care.
563  libusb_set_auto_detach_kernel_driver (m_hDevice, 1);
564 
565  // Set the current configuration, if needed.
566  int l_CurrentConfig;
567  m_Status = libusb_get_configuration(m_hDevice, &l_CurrentConfig);
568  if (m_Status != LIBUSB_SUCCESS)
569  throw Exception(m_Status, MTL__LOCATION__);
570  if (l_CurrentConfig != m_ConfigurationNo)
571  {
572  m_Status =libusb_set_configuration(m_hDevice, m_ConfigurationNo);
573  if (m_Status != LIBUSB_SUCCESS)
574  throw Exception(m_Status, MTL__LOCATION__);
575  }
576 
577  // Register the device with our access-control mechanism.
578  l_USBTMCAccessControl.Register(m_pDevice);
579  }
580 
581  // Handle errors.
583  {
584  MTL_Unused(rE)
586 
587  if (l_pConfig != nullptr)
588  libusb_free_config_descriptor(l_pConfig);
589 
590  if (m_hDevice != nullptr)
591  {
592  libusb_close(m_hDevice);
593  m_hDevice = nullptr;
594  }
595 
596  if (m_pDevice != nullptr)
597  {
598  libusb_unref_device(m_pDevice);
599  m_pDevice = nullptr;
600 
601  m_ConfigurationNo = 0;
602  m_InterfaceNo = 0;
603  m_InterruptEndpoint = 0;
604  m_BulkInEndpoint = 0;
605  m_BulkOutEndpoint = 0;
606  m_BulkInMaxPacketSize = 0;
607  m_bTag = 0;
608 
609  Unlock();
610  }
611  return false;
612  }
613 
614  return true;
615 
616 } // CUSBTMCInstrument::Open
617 
619 {
620  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
621  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
622 
623  // If the device is already closed, we're done.
624  if (!IsOpen()) return;
625 
626  // Unlock the interface.
627  Unlock();
628 
629  // Close the device.
630  if (m_hDevice != nullptr)
631  {
632  libusb_close(m_hDevice);
633  m_hDevice = nullptr;
634  }
635 
636  // Unreference the device pointer.
637  if (m_pDevice != nullptr)
638  {
639  libusb_unref_device(m_pDevice);
640  m_pDevice = nullptr;
641  }
642 
643  // Unregister the device from our access-control mechanism.
644  l_USBTMCAccessControl.Unregister(m_pDevice);
645 
646  // Clear the other class variables.
647  m_ConfigurationNo = 0;
648  m_InterfaceNo = 0;
649  m_InterruptEndpoint = 0;
650  m_BulkInEndpoint = 0;
651  m_BulkOutEndpoint = 0;
652  m_BulkInMaxPacketSize = 0;
653  m_bTag = 0;
654 
655 } // CUSBTMCInstrument::Close
656 
658 {
659  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
660  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
661 
662  return (m_pDevice != nullptr && m_hDevice != nullptr);
663 
664 } // CUSBTMCInstrument::IsOpen
665 
666 //------------------------------------------//
667 // Info
669 {
670  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
671  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
672 
673  if (Status <= 0)
674  return libusb_error_name(Status);
675  else
677 
678 } // CUSBTMCInstrument::StatusDescription
679 
681 {
682  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
683  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
684 
685  return (m_Status == LIBUSB_ERROR_TIMEOUT);
686 
687 } // CUSBTMCInstrument::Timeout
688 
689 //------------------------------------------//
690 // Write
691 // Low-level write.
692 bool CUSBTMCInstrument::USBTMCWrite(U8 MessageID, const char * pData, const size_t Size, U8 TransferAttributes)
693 {
694  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
695  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
696 
697  bool l_InitialLockState = m_ExclusiveLock;
698  U8 * l_pBuffer = nullptr;
699  try
700  {
701  // Make sure this device is open.
702  if (!IsOpen())
704 
705  // Lock the device.
706  if (!LockExclusive(m_Timeout))
708 
709  // Allocate the buffer.
710  I32 l_Size = pData ? static_cast<I32>(Size) : 0;
711  I32 l_PaddedSize = (l_Size + USBTMC_BULK_HEADER_SIZE + 3) & ~0x3;
712  l_pBuffer = new U8[static_cast<size_t>(l_PaddedSize)];
713  if (!l_pBuffer)
714  throw Exception(LIBUSB_ERROR_NO_MEM, MTL__LOCATION__);
715 
716  // Increment the bTag; ensure that it is in the valid range for ReadSTB.
717  if (++m_bTag < 2 || m_bTag > 127)
718  m_bTag = 2;
719 
720  // Build the write buffer: header, data, padding.
721  USBTMCBulkOutHeaderWrite(l_pBuffer, MessageID, m_bTag, static_cast<U32>(Size), TransferAttributes, 0);
722  if (pData) std::memcpy(l_pBuffer + USBTMC_BULK_HEADER_SIZE, pData, static_cast<size_t>(l_Size));
723  std::memset(l_pBuffer + l_Size + USBTMC_BULK_HEADER_SIZE, 0, static_cast<size_t>(l_PaddedSize - l_Size - USBTMC_BULK_HEADER_SIZE));
724 
725  // Transfer the data.
726  I32 l_Transferred;
727  m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
728  m_BulkOutEndpoint, // endpoint
729  l_pBuffer, // data
730  l_PaddedSize, // length
731  &l_Transferred, // transferred
732  static_cast<unsigned int>(m_Timeout)); // timeout
733  if (m_Status != LIBUSB_SUCCESS)
734  {
735  USBTMCClearBulkOut(m_bTag); // Clear the endpoint
736  Clear(); // Clear the device FIFOs
737  throw Exception(m_Status, MTL__LOCATION__);
738  }
739  if (l_Transferred != l_PaddedSize)
741  }
742 
743  // Handle errors.
745  {
746  MTL_Unused(rE)
748 
749  // Restore the lock to its initial state.
750  if (!l_InitialLockState) Unlock();
751 
752  return false;
753  }
754 
755  // Restore the lock to its initial state.
756  if (!l_InitialLockState) Unlock();
757 
758  // Deallocate the buffer.
759  if (l_pBuffer) delete l_pBuffer;
760 
761  return true;
762 
763 } // CUSBTMCInstrument::USBTMCWrite
764 
765 bool CUSBTMCInstrument::Write(const char * Str)
766 {
767  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
768  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
769 
770  return USBTMCWrite(DEV_DEP_MSG_OUT, Str, std::strlen(Str), EOM);
771 
772 } // CUSBTMCInstrument::Write(const char * Str)
773 
774 bool CUSBTMCInstrument::Write(const std::string & rStr)
775 {
776  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
777  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
778 
779  return USBTMCWrite(DEV_DEP_MSG_OUT, rStr.c_str(), rStr.size(), EOM);
780 
781 } // CUSBTMCInstrument::Write(const std::string & rStr)
782 
784 {
785  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
786  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
787 
788  return USBTMCWrite(DEV_DEP_MSG_OUT, rBuf.data(), rBuf.size(), EOM);
789 
790 } // CUSBTMCInstrument::Write(const CSCPIBuffer & rBuf)
791 
792 //------------------------------------------//
793 // Read
794 bool CUSBTMCInstrument::Read(CSCPIBuffer & rBuf, bool Append)
795 {
796  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
797  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
798 
799  bool l_InitialLockState = m_ExclusiveLock;
800  try
801  {
802  // Make sure this device is open.
803  if (!IsOpen())
805 
806  // Lock the device.
807  if (!LockExclusive(m_Timeout))
809 
810  // Clear the buffer if we're not appending.
811  if (!Append) rBuf.clear();
812 
813  // Write REQUEST_DEV_DEP_MSG_IN, with an enormous buffer size.
814  USBTMCWrite(REQUEST_DEV_DEP_MSG_IN, nullptr, INT32_MAX, 0);
815  if (m_Status != LIBUSB_SUCCESS)
816  throw Exception(m_Status, MTL__LOCATION__);
817 
818  // Read the header and at least the beginning of the message.
819  // Note: since max packet size > header length, we can't read just the header.
820  // Note: sometimes, for reasons unknown, libusb_bulk_transfer returns success but l_Transferred = 0
821  // (does not appear to be a zero-length USB transfer). In this case, repeat the transfer.
822  assert(m_BulkInMaxPacketSize >= USBTMC_BULK_HEADER_SIZE);
823  I32 l_BufferLength = m_BulkInMaxPacketSize;
824  assert(l_BufferLength <= USBTMC_READ_BUFFER_SIZE);
825  U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
826  I32 l_Transferred = 0;
827  do
828  {
829  m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
830  m_BulkInEndpoint, // endpoint
831  l_ReadBuffer, // data
832  l_BufferLength, // length
833  &l_Transferred, // transferred
834  static_cast<unsigned int>(m_Timeout)); // timeout
835  if (m_Status < 0)
836  {
837  USBTMCClearBulkIn(m_bTag);
838  throw Exception(m_Status, MTL__LOCATION__);
839  }
840  } while (l_Transferred == 0);
841  if (l_Transferred < USBTMC_BULK_HEADER_SIZE)
843 
844  // Parse and check the header.
845  I32 l_MessageSize;
846  U8 l_TransferAttributes;
847  if (!USBTMCBulkInHeaderRead(l_ReadBuffer, DEV_DEP_MSG_IN, m_bTag, l_MessageSize, l_TransferAttributes) ||
848  !(l_TransferAttributes & EOM))
850 
851  // If necessary, adjust the buffer size to accenpt the entire message.
852  size_t l_BufSize = rBuf.size();
853  size_t l_BufCapacity = rBuf.capacity();
854  if (l_MessageSize > static_cast<I32>(l_BufCapacity - l_BufSize))
855  rBuf.reserve(l_BufSize + static_cast<size_t>(l_MessageSize));
856 
857  // Copy the part of the message that we have already received.
858  size_t l_MessageReceived = static_cast<size_t>(l_Transferred) - USBTMC_BULK_HEADER_SIZE;
859  if (l_MessageReceived > 0)
860  std::memcpy(rBuf.data() + l_BufSize, l_ReadBuffer + USBTMC_BULK_HEADER_SIZE, l_MessageReceived);
861 
862  // Read the rest of the message, if applicable.
863  size_t l_MessagePending = static_cast<size_t>(l_MessageSize) - l_MessageReceived;
864  if (l_MessagePending > 0)
865  {
866  // Note: small delay before second read. This alleviates a problem - probably host/device specific -
867  // where the device does not flush its FIFO.
868  std::this_thread::sleep_for(std::chrono::milliseconds(MTL_USBTMC_PAUSE_BETWEEN_READS));
869  U8 * l_pData = reinterpret_cast<U8 *>(rBuf.data() + l_BufSize + l_MessageReceived);
870  m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
871  m_BulkInEndpoint, // endpoint
872  l_pData, // data
873  static_cast<I32>(l_MessagePending), // length
874  &l_Transferred, // transferred
875  static_cast<unsigned int>(m_Timeout)); // timeout
876  if (m_Status < 0)
877  {
878  USBTMCClearBulkIn(m_bTag);
879  throw Exception(m_Status, MTL__LOCATION__);
880  }
881  if (l_Transferred != static_cast<I32>(l_MessagePending))
883  }
884 
885  // Resize the buffer to the cumulated number of bytes read.
886  rBuf.resize(l_BufSize + static_cast<size_t>(l_MessageSize));
887  }
888 
889  // Handle errors.
891  {
892  MTL_Unused(rE)
894 
895  // Restore the lock to its initial state.
896  if (!l_InitialLockState) Unlock();
897 
898  return false;
899  }
900 
901  // Restore the lock to its initial state.
902  if (!l_InitialLockState) Unlock();
903 
904  return true;
905 
906 } // CUSBTMCInstrument::Read
907 
908 //------------------------------------------//
909 // Other operations
910 bool CUSBTMCInstrument::USBTMCClearBulkIn(U8 bTag)
911 {
912  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
913  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
914 
915  try
916  {
917  // Initiate the Abort BulkIn.
920  assert(m_BulkInMaxPacketSize <= USBTMC_READ_BUFFER_SIZE);
921  U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
922  I32 l_ReturnValue =
923  libusb_control_transfer(m_hDevice, // dev_handle
924  USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
925  INITIATE_ABORT_BULK_IN, // bRequest
926  static_cast<U16>(bTag), // wValue
927  m_BulkInEndpoint, // wIndex
928  l_ReadBuffer, // data
930  static_cast<unsigned int>(m_Timeout)); // timeout
931 
932  // Check for errors.
933  if (l_ReturnValue < 0)
934  throw Exception(l_ReturnValue, MTL__LOCATION__);
935  if (l_ReturnValue != USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH ||
936  l_ReadBuffer[0] != USBTMC_STATUS_SUCCESS)
938 
939  // Flush the device's transfer FIFO.
940  I32 l_BufferLength = m_BulkInMaxPacketSize;
941  I32 l_Transferred;
942  do
943  {
944  l_ReturnValue =
945  libusb_bulk_transfer(m_hDevice, // dev_handle
946  m_BulkInEndpoint, // endpoint
947  l_ReadBuffer, // data
948  l_BufferLength, // length
949  &l_Transferred, // transferred
950  static_cast<unsigned int>(m_Timeout)); // timeout
951  if (l_ReturnValue < 0)
952  throw Exception(m_Status, MTL__LOCATION__);
953  } while (l_Transferred >= l_BufferLength);
954 
955  // Loop to poll the Initiate BulkIn Abort status.
956  U8 l_Status;
957  do
958  {
959  l_ReturnValue =
960  libusb_control_transfer(m_hDevice, // dev_handle
961  USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
962  CHECK_ABORT_BULK_IN_STATUS, // bRequest
963  0x0000, // wValue
964  m_BulkInEndpoint, // wIndex
965  l_ReadBuffer, // data
967  static_cast<unsigned int>(m_Timeout)); // timeout
968 
969  if (l_ReturnValue < 0)
970  throw Exception(l_ReturnValue, MTL__LOCATION__);
971  if (l_ReturnValue != USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH ||
972  ((l_Status = l_ReadBuffer[0]) != USBTMC_STATUS_SUCCESS && l_Status != USBTMC_STATUS_PENDING) ||
973  l_ReadBuffer[1] != 0 || // BulkIn FIFO should be empty
974  l_ReadBuffer[2] != 0 || // Always zero
975  l_ReadBuffer[3] != 0) // Always zero
977 
978  std::this_thread::sleep_for(std::chrono::milliseconds(USBTMC_CHECK_CLEAR_STATUS_INTERVAL));
979 
980  } while (l_Status != USBTMC_STATUS_SUCCESS);
981 
982  l_ReturnValue = libusb_clear_halt(m_hDevice, m_BulkInEndpoint);
983  if (l_ReturnValue < 0)
984  throw Exception(l_ReturnValue, MTL__LOCATION__);
985  }
986 
987  // Handle errors.
989  {
990  MTL_Unused(rE)
992  return false;
993  }
994 
995  return true;
996 
997 } // CUSBTMCInstrument::USBTMCClearBulkIn
998 
999 bool CUSBTMCInstrument::USBTMCClearBulkOut(U8 bTag)
1000 {
1001  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1002  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1003 
1004  try
1005  {
1006  // Initiate the Abort BulkOut.
1009  U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
1010  I32 l_ReturnValue =
1011  libusb_control_transfer(m_hDevice, // dev_handle
1012  USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
1013  INITIATE_ABORT_BULK_OUT, // bRequest
1014  static_cast<U16>(bTag), // wValue
1015  m_BulkOutEndpoint, // wIndex
1016  l_ReadBuffer, // data
1018  static_cast<unsigned int>(m_Timeout)); // timeout
1019 
1020  // Check for errors.
1021  if (l_ReturnValue < 0)
1022  throw Exception(l_ReturnValue, MTL__LOCATION__);
1023  if (l_ReturnValue != USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH ||
1024  l_ReadBuffer[0] != USBTMC_STATUS_SUCCESS)
1026 
1027  // Loop to poll the Initiate BulkOut Abort status.
1028  U8 l_Status;
1029  do
1030  {
1031  l_ReturnValue =
1032  libusb_control_transfer(m_hDevice, // dev_handle
1033  USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
1034  CHECK_ABORT_BULK_OUT_STATUS, // bRequest
1035  0x0000, // wValue
1036  m_BulkOutEndpoint, // wIndex
1037  l_ReadBuffer, // data
1039  static_cast<unsigned int>(m_Timeout)); // timeout
1040 
1041  if (l_ReturnValue < 0)
1042  throw Exception(l_ReturnValue, MTL__LOCATION__);
1043  if (l_ReturnValue != USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH ||
1044  ((l_Status = l_ReadBuffer[0]) != USBTMC_STATUS_SUCCESS && l_Status != USBTMC_STATUS_PENDING) ||
1045  l_ReadBuffer[1] != 0 || // Always zero
1046  l_ReadBuffer[2] != 0 || // Always zero
1047  l_ReadBuffer[3] != 0) // Always zero
1049 
1050  std::this_thread::sleep_for(std::chrono::milliseconds(USBTMC_CHECK_CLEAR_STATUS_INTERVAL));
1051 
1052  } while (l_Status != USBTMC_STATUS_SUCCESS);
1053 
1054  l_ReturnValue = libusb_clear_halt(m_hDevice, m_BulkOutEndpoint);
1055  if (l_ReturnValue < 0)
1056  throw Exception(l_ReturnValue, MTL__LOCATION__);
1057 
1058  }
1059 
1060  // Handle errors.
1062  {
1063  MTL_Unused(rE)
1065  return false;
1066  }
1067 
1068  return true;
1069 
1070 } // CUSBTMCInstrument::USBTMCClearBulkOut
1071 
1073 {
1074  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1075  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1076 
1077  bool l_InitialLockState = m_ExclusiveLock;
1078  try
1079  {
1080  // Make sure this device is open.
1081  if (!IsOpen())
1083 
1084  // Lock the device.
1085  if (!LockExclusive(m_Timeout))
1087 
1088  // Initiate the Clear.
1091  U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
1092  I32 l_ReturnValue =
1093  libusb_control_transfer(m_hDevice, // dev_handle
1094  USBTMC_BM_REQUEST_TYPE_IN_CLS_IF, // bmRequestType
1095  INITIATE_CLEAR, // bRequest
1096  0x0000, // wValue
1097  USB_CONTROL_ENDPOINT_NUMBER, // wIndex
1098  l_ReadBuffer, // data
1100  static_cast<unsigned int>(m_Timeout)); // timeout
1101 
1102  // Check for errors.
1103  if (l_ReturnValue < 0)
1104  throw Exception(l_ReturnValue, MTL__LOCATION__);
1105  if (l_ReturnValue != USBTMC_INITIATE_CLEAR_RESP_LENGTH ||
1106  l_ReadBuffer[0] != USBTMC_STATUS_SUCCESS)
1108 
1109  // Loop to poll the clear status.
1110  U8 l_Status, l_Clear;
1111  do
1112  {
1113  l_ReturnValue =
1114  libusb_control_transfer(m_hDevice, // dev_handle
1115  USBTMC_BM_REQUEST_TYPE_IN_CLS_IF, // bmRequestType
1116  CHECK_CLEAR_STATUS, // bRequest
1117  0x0000, // wValue
1118  USB_CONTROL_ENDPOINT_NUMBER, // wIndex
1119  l_ReadBuffer, // data
1121  static_cast<unsigned int>(m_Timeout)); // timeout
1122 
1123  if (l_ReturnValue < 0)
1124  throw Exception(l_ReturnValue, MTL__LOCATION__);
1125  if (l_ReturnValue != USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH ||
1126  ((l_Status = l_ReadBuffer[0]) != USBTMC_STATUS_SUCCESS && l_Status != USBTMC_STATUS_PENDING) ||
1127  ((l_Clear = l_ReadBuffer[1]) != 0 && l_Clear != BULKIN_FIFO_BYTES) )
1129 
1130  std::this_thread::sleep_for(std::chrono::milliseconds(USBTMC_CHECK_CLEAR_STATUS_INTERVAL));
1131 
1132  } while (l_Status != USBTMC_STATUS_SUCCESS);
1133 
1134  // Clear the BulkOut Halt condition.
1135  l_ReturnValue = libusb_clear_halt(m_hDevice, m_BulkOutEndpoint);
1136  if (l_ReturnValue < 0)
1137  throw Exception(l_ReturnValue, MTL__LOCATION__);
1138 
1139  // If necessary, clear the BulkIn endpoint.
1140  if (l_Clear == BULKIN_FIFO_BYTES)
1141  USBTMCClearBulkIn(m_bTag);
1142  }
1143 
1144  // Handle errors.
1146  {
1147  MTL_Unused(rE)
1149 
1150  // Restore the lock to its initial state.
1151  if (!l_InitialLockState) Unlock();
1152 
1153  return false;
1154  }
1155 
1156  // Restore the lock to its initial state.
1157  if (!l_InitialLockState) Unlock();
1158 
1159  return true;
1160 
1161 } // CUSBTMCInstrument::Clear
1162 
1164 {
1165  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1166  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1167 
1168  bool l_InitialLockState = m_ExclusiveLock;
1169  try
1170  {
1171  // Make sure this device is open.
1172  if (!IsOpen())
1174 
1175  // Lock the device.
1176  if (!LockExclusive(m_Timeout))
1178 
1179  // Loop to read the Status Byte.
1180  // Since we don't handle Service Requests at the moment (TODO), just flush them.
1181  // Note that Service Requests have the same packet length, but the bTag is 0x01 instead of the one we specify.
1184  U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
1185  bool l_GotSTB = false;
1186  do
1187  {
1188  // Increment the bTag; ensure that it is in the valid range for ReadSTB.
1189  if (++m_bTag < 2 || m_bTag > 127)
1190  m_bTag = 2;
1191 
1192  // Send the READ_STATUS_BYTE control.
1193  I32 l_ReturnValue =
1194  libusb_control_transfer(m_hDevice, // dev_handle
1195  USBTMC_BM_REQUEST_TYPE_IN_CLS_IF, // bmRequestType
1196  READ_STATUS_BYTE, // bRequest
1197  m_bTag, // wValue
1198  USB_CONTROL_ENDPOINT_NUMBER, // wIndex
1199  l_ReadBuffer, // data
1201  static_cast<unsigned int>(m_Timeout)); // timeout
1202 
1203  // Check for errors.
1204  if (l_ReturnValue < 0)
1205  throw Exception(l_ReturnValue, MTL__LOCATION__);
1206  bool l_Success = USBTMCReadSTBResponse(l_ReadBuffer, USBTMC_STATUS_SUCCESS, m_bTag, 0);
1207  bool l_InterruptInBusy = USBTMCReadSTBResponse(l_ReadBuffer, USBTMC_STATUS_INTERRUPT_IN_BUSY, m_bTag, 0);
1208  if (l_ReturnValue != USBTMC_READSTB_CTRL_RESP_LENGTH ||
1209  !(l_Success || l_InterruptInBusy))
1211 
1212  // Read the next packet from the interrupt endpoint.
1213  I32 l_Transferred;
1214  l_ReturnValue =
1215  libusb_interrupt_transfer(m_hDevice, // dev_handle
1216  m_InterruptEndpoint, // endpoint
1217  l_ReadBuffer, // data
1219  &l_Transferred, // transferred
1220  static_cast<unsigned int>(m_Timeout)); // timeout
1221 
1222  // Check for errors.
1223  if (l_ReturnValue < 0)
1224  throw Exception(l_ReturnValue, MTL__LOCATION__);
1225  if (l_Transferred != USBTMC_READSTB_INTR_RESP_LENGTH)
1227 
1228  // Flush any Service Requests.
1229  if (l_InterruptInBusy && l_ReadBuffer[0] == 0x81)
1230  continue;
1231 
1232  // Validate the Read STB response.
1233  if (l_ReadBuffer[0] != (0x80 | m_bTag))
1235 
1236  l_GotSTB = true;
1237  } while (!l_GotSTB);
1238 
1239  // Return the status byte.
1240  rSTB = l_ReadBuffer[1];
1241  }
1242 
1243  // Handle errors.
1245  {
1246  MTL_Unused(rE)
1248 
1249  // Restore the lock to its initial state.
1250  if (!l_InitialLockState) Unlock();
1251 
1252  return false;
1253  }
1254 
1255  // Restore the lock to its initial state.
1256  if (!l_InitialLockState) Unlock();
1257 
1258  return true;
1259 
1260 } // CUSBTMCInstrument::ReadSTB
1261 
1263 {
1264  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1265  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1266 
1267  bool l_InitialLockState = m_ExclusiveLock;
1268  try
1269  {
1270  // Make sure this device is open.
1271  if (!IsOpen())
1273 
1274  // Lock the device.
1275  if (!LockExclusive(m_Timeout))
1277 
1278  // Increment the bTag; ensure that it is in the valid range for ReadSTB.
1279  if (++m_bTag < 2 || m_bTag > 127)
1280  m_bTag = 2;
1281 
1282  // Build the write buffer: everything except MsgID, bTag, and ~bTag is zero.
1283  U8 l_Buffer[USBTMC_BULK_TRIGGER_MSG_SIZE];
1284  USBTMCBulkOutHeaderWrite(l_Buffer, TRIGGER, m_bTag, 0, 0, 0);
1285 
1286  // Transfer the data.
1287  I32 l_Transferred;
1288  m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
1289  m_BulkOutEndpoint, // endpoint
1290  l_Buffer, // data
1291  USBTMC_BULK_TRIGGER_MSG_SIZE, // length
1292  &l_Transferred, // transferred
1293  static_cast<unsigned int>(m_Timeout)); // timeout
1294  if (m_Status != LIBUSB_SUCCESS)
1295  {
1296  USBTMCClearBulkOut(m_bTag); // Clear the endpoint
1297  Clear(); // Clear the device FIFOs
1298  throw Exception(m_Status, MTL__LOCATION__);
1299  }
1300  if (l_Transferred != USBTMC_BULK_TRIGGER_MSG_SIZE)
1302  }
1303 
1304  // Handle errors.
1306  {
1307  MTL_Unused(rE)
1309 
1310  // Restore the lock to its initial state.
1311  if (!l_InitialLockState) Unlock();
1312 
1313  return false;
1314  }
1315 
1316  // Restore the lock to its initial state.
1317  if (!l_InitialLockState) Unlock();
1318 
1319  return true;
1320 
1321 } // CUSBTMCInstrument::AssertTrigger
1322 
1323 //------------------------------------------//
1324 // Lock / Unlock
1326 {
1327  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1328  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1329 
1330  // If it is already locked, we're done.
1331  if (m_ExclusiveLock) return true;
1332 
1333  // Try to claim the interface.
1334  if (!l_USBTMCAccessControl.Claim(m_pDevice, Timeout))
1335  {
1337  return false;
1338  }
1339 
1340  // Tell libusb to claim the interface.
1341  I32 l_ReturnCode = libusb_claim_interface(m_hDevice, m_InterfaceNo);
1342  if (l_ReturnCode != LIBUSB_SUCCESS)
1343  {
1344  m_Status = l_ReturnCode;
1345  l_USBTMCAccessControl.Release(m_pDevice);
1346  return false;
1347  }
1348 
1349  // Lock succeeded.
1350  m_ExclusiveLock = true;
1351  return true;
1352 
1353 } // CUSBTMCInstrument::LockExclusive
1354 
1356 {
1357  MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1358  CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1359 
1360  // If it is already unlocked, we're done.
1361  if (!m_ExclusiveLock) return true;
1362 
1363  // Tell libusb to release the interface.
1364  I32 l_ReturnCode = libusb_release_interface(m_hDevice, m_InterfaceNo);
1365  if (l_ReturnCode != LIBUSB_SUCCESS)
1366  {
1367  m_Status = l_ReturnCode;
1368  return false;
1369  }
1370 
1371  // Release the claim to the interface.
1372  l_USBTMCAccessControl.Release(m_pDevice);
1373 
1374  m_ExclusiveLock = false;
1375  return true;
1376 
1377 } // CUSBTMCInstrument::Unlock
1378 
1380 {
1381  return m_ExclusiveLock;
1382 
1383 } // CUSBTMCInstrument::Locked
1384 
1385 
1386 //------------------------------------------//
1387 // Exception
1388 MTL::CException<CUSBTMCInstrument> CUSBTMCInstrument::Exception(I32 Status, std::string Location)
1389 {
1390  m_Status = Status;
1392 }
EOM
static const U8 EOM
Definition: USBTMCPrivate.h:87
BULKIN_FIFO_BYTES
static const U8 BULKIN_FIFO_BYTES
Definition: USBTMCPrivate.h:91
USBTMC_ERROR_FIND_RESRC_BAD_FILTER
@ USBTMC_ERROR_FIND_RESRC_BAD_FILTER
Definition: USBTMCPrivate.h:97
USBTMC_BM_REQUEST_TYPE_IN_CLS_EP
static const U8 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP
Definition: USBTMCPrivate.h:39
INITIATE_CLEAR
@ INITIATE_CLEAR
Definition: USBTMCPrivate.h:22
MTL::Instrument::CResourceList
List of VISA resource names.
Definition: IEEE488InstrumentTypes.h:26
MTL::Instrument::CUSBTMCInstrument::Clear
virtual bool Clear(void)
Clear the instrument.
Definition: USBTMCInstrument.cpp:1072
USBTMC_ERROR_GET_RESRC_NOT_FOUND
@ USBTMC_ERROR_GET_RESRC_NOT_FOUND
Definition: USBTMCPrivate.h:99
MTL::Instrument::CUSBTMCInstrument::Open
virtual bool Open(void)
Open this USBTMC instrument.
Definition: USBTMCInstrument.cpp:475
USB_MAX_PORT_DEPTH
static const I32 USB_MAX_PORT_DEPTH
Definition: USBTMCPrivate.h:35
MTL::Instrument::CUSBTMCResourceManager::StatusDescription
virtual std::string StatusDescription(I32 Status)
Return description of status word.
Definition: USBTMCInstrument.cpp:301
USBTMC_READSTB_INTR_RESP_LENGTH
static const U16 USBTMC_READSTB_INTR_RESP_LENGTH
Definition: USBTMCPrivate.h:42
MTL::Instrument::CUSBTMCInstrument::Read
virtual bool Read(CSCPIBuffer &rBuf, bool Append=false)
Read from a USBTMC instrument: SCPI buffer class variant.
Definition: USBTMCInstrument.cpp:794
MTL::Instrument::CIEEE488Instrument::m_Timeout
U32 m_Timeout
Timeout for operations.
Definition: IEEE488Instrument.h:72
USBTMC_ERROR_INSTRUMENT_LOCKED
@ USBTMC_ERROR_INSTRUMENT_LOCKED
Definition: USBTMCPrivate.h:109
USBTMC_ERROR_READSTB_CONTROL_RESPONSE_ERROR
@ USBTMC_ERROR_READSTB_CONTROL_RESPONSE_ERROR
Definition: USBTMCPrivate.h:107
USBTMC_ERROR_CLEAR_RESPONSE_ERROR
@ USBTMC_ERROR_CLEAR_RESPONSE_ERROR
Definition: USBTMCPrivate.h:104
INITIATE_ABORT_BULK_OUT
@ INITIATE_ABORT_BULK_OUT
Definition: USBTMCPrivate.h:18
MTL::Instrument::CSCPIBuffer::reserve
void reserve(size_t capacity)
Allocate at least a given amount of space.
Definition: SCPIInstrumentBuffer.h:83
USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH
static const U16 USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH
Definition: USBTMCPrivate.h:48
USBTMC_READSTB_CTRL_RESP_LENGTH
static const U16 USBTMC_READSTB_CTRL_RESP_LENGTH
Definition: USBTMCPrivate.h:41
MTL::Instrument::CUSBTMCResourceManager::Timeout
virtual bool Timeout(void)
Last operation timed out.
Definition: USBTMCInstrument.cpp:312
MTL::Instrument::CUSBTMCResourceManager::Initialize
virtual bool Initialize(void)
Initialize the Resource Manager.
Definition: USBTMCInstrument.cpp:69
USBTMC_STATUS_SUCCESS
@ USBTMC_STATUS_SUCCESS
Definition: USBTMCPrivate.h:54
WL32
#define WL32(p, x)
Definition: USBTMCPrivate.h:313
USBTMC_ERROR_READ_WRONG_MSG_SIZE
@ USBTMC_ERROR_READ_WRONG_MSG_SIZE
Definition: USBTMCPrivate.h:103
MTL::Instrument::CUSBTMCInstrument::Close
virtual void Close(void)
Close this USBTMC instrument.
Definition: USBTMCInstrument.cpp:618
MTL::Instrument::CIEEE488ResourceManager::m_Lock
CMutex m_Lock
Lock onto the resource manager.
Definition: IEEE488Instrument.h:25
MTL::Instrument::CSCPIBuffer::size
size_t size() const
Return the buffer size.
Definition: SCPIInstrumentBuffer.h:106
INITIATE_ABORT_BULK_IN
@ INITIATE_ABORT_BULK_IN
Definition: USBTMCPrivate.h:20
USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH
static const U16 USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH
Definition: USBTMCPrivate.h:46
MTL::Instrument::CUSBTMCInstrument::LockExclusive
virtual bool LockExclusive(U32 Timeout)
Obtain an exclusive lock for this session.
Definition: USBTMCInstrument.cpp:1325
USBTMC_USB488
static const U8 USBTMC_USB488
Definition: USBTMCPrivate.h:14
USBTMC_STATUS_PENDING
@ USBTMC_STATUS_PENDING
Definition: USBTMCPrivate.h:55
RL32
#define RL32(x)
Definition: USBTMCPrivate.h:191
USBTMC_STATUS_INTERRUPT_IN_BUSY
@ USBTMC_STATUS_INTERRUPT_IN_BUSY
Definition: USBTMCPrivate.h:56
REQUEST_DEV_DEP_MSG_IN
static const U8 REQUEST_DEV_DEP_MSG_IN
Definition: USBTMCPrivate.h:82
MTL::Instrument::CUSBTMCInstrument::Timeout
virtual bool Timeout(void)
Last operation timed out.
Definition: USBTMCInstrument.cpp:680
MTL::Instrument::CUSBTMCResourceManager
USBTMC Resource Manager class.
Definition: USBTMCInstrument.h:30
WL16
#define WL16(p, x)
Definition: USBTMCPrivate.h:295
TRIGGER
static const U8 TRIGGER
Definition: USBTMCPrivate.h:84
Unregister
bool Unregister(libusb_device *pDevice)
Definition: USBTMCInstrument.cpp:410
MTL::Instrument::CUSBTMCInstrument::ReadSTB
virtual bool ReadSTB(U16 &rSTB)
Read status byte.
Definition: USBTMCInstrument.cpp:1163
MTL::Instrument::CIEEE488ResourceManager::m_Status
I32 m_Status
Status of last operation.
Definition: IEEE488Instrument.h:26
MTL::Synchronization::CMutex
std::mutex CMutex
Mutex.
Definition: Synchronization.h:16
USBTMC_BM_REQUEST_TYPE_IN_CLS_IF
static const U8 USBTMC_BM_REQUEST_TYPE_IN_CLS_IF
Definition: USBTMCPrivate.h:38
Helpers.h
Collection of utility macros for error messages.
USBTMC_BULK_TRIGGER_MSG_SIZE
static const I32 USBTMC_BULK_TRIGGER_MSG_SIZE
Definition: USBTMCPrivate.h:78
MTL::Instrument::CSCPIBuffer::resize
void resize(size_t size)
Resize the buffer.
Definition: SCPIInstrumentBuffer.h:93
MTL::Instrument::CSCPIBuffer::capacity
size_t capacity() const
Return the buffer capacity (allocated size).
Definition: SCPIInstrumentBuffer.h:114
MTL_USBTMC_INSTRUMENT_DEBUG_CERR
#define MTL_USBTMC_INSTRUMENT_DEBUG_CERR(__X__)
Definition: USBTMCInstrument.cpp:34
READ_STATUS_BYTE
@ READ_STATUS_BYTE
Definition: USBTMCPrivate.h:28
USBTMC_BULK_HEADER_SIZE
static const I32 USBTMC_BULK_HEADER_SIZE
Definition: USBTMCPrivate.h:76
SUBCLASS_USBTMC
static const U8 SUBCLASS_USBTMC
Constants for USBTMC and USB488.
Definition: USBTMCPrivate.h:13
tControlRecord
Definition: USBTMCInstrument.cpp:379
Register
bool Register(libusb_device *pDevice)
Definition: USBTMCInstrument.cpp:394
USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR
@ USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR
Definition: USBTMCPrivate.h:108
USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT
@ USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT
Definition: USBTMCPrivate.h:100
MTL::Instrument::CUSBTMCInstrument::Write
virtual bool Write(const char *Str)
Write to a USBTMC instrument: C string variant.
Definition: USBTMCInstrument.cpp:765
MTL::Instrument::CUSBTMCInstrument::LockedExclusive
virtual bool LockedExclusive(void)
Check whether session is locked exclusively.
Definition: USBTMCInstrument.cpp:1379
MTL::Instrument::CIEEE488Instrument::m_Rsrc
tResourceName m_Rsrc
Resource name of the instrument.
Definition: IEEE488Instrument.h:70
MTL_USBTMC_INSTRUMENT_DEBUG_COUT
#define MTL_USBTMC_INSTRUMENT_DEBUG_COUT(__X__)
Definition: USBTMCInstrument.cpp:33
MTL::Instrument
Definition: THM1176.h:75
DEV_DEP_MSG_OUT
static const U8 DEV_DEP_MSG_OUT
Definition: USBTMCPrivate.h:81
MTL::Instrument::CUSBTMCInstrument::~CUSBTMCInstrument
virtual ~CUSBTMCInstrument(void)
Destructor.
Definition: USBTMCInstrument.cpp:463
MTL::Instrument::CUSBTMCInstrument::StatusDescription
virtual std::string StatusDescription(I32 Status)
Return description of status word.
Definition: USBTMCInstrument.cpp:668
MTL::Instrument::CUSBTMCResourceManager::CUSBTMCResourceManager
CUSBTMCResourceManager(void)
Constructor.
Definition: USBTMCInstrument.cpp:45
USBTMC_READ_BUFFER_SIZE
static const U16 USBTMC_READ_BUFFER_SIZE
Definition: USBTMCPrivate.h:40
tControlRecord::Mutex
std::timed_mutex Mutex
Definition: USBTMCInstrument.cpp:381
USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR
@ USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR
Definition: USBTMCPrivate.h:105
I32
int I32
32-bit signed integer.
Definition: OSDefines.h:28
CHECK_CLEAR_STATUS
@ CHECK_CLEAR_STATUS
Definition: USBTMCPrivate.h:23
USBTMCPrivate.h
USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH
Definition: USBTMCPrivate.h:44
tControlRecord::tControlRecord
tControlRecord(void)
Definition: USBTMCInstrument.cpp:383
MTL::Instrument::CUSBTMCInstrument::Unlock
virtual bool Unlock(void)
Unlock the session.
Definition: USBTMCInstrument.cpp:1355
MTL::Instrument::CIEEE488Instrument
IEEE488 instrument class.
Definition: IEEE488Instrument.h:63
USBTMCReadSTBResponse
static bool USBTMCReadSTBResponse(U8 *pResponse, U8 USBTMC_status, U8 bTag, U8 StatusByte)
Definition: USBTMCInstrument.cpp:333
MTL::Instrument::CIEEE488Instrument::m_Lock
CRecursiveMutex m_Lock
Lock onto the class interface.
Definition: IEEE488Instrument.h:68
USB_CONTROL_ENDPOINT_NUMBER
static const U16 USB_CONTROL_ENDPOINT_NUMBER
Definition: USBTMCPrivate.h:36
MTL::CException
Exception to be thrown.
Definition: Exception.h:17
USBTMC_ERROR_FIND_RESRC_NO_USBTMC_USB488
@ USBTMC_ERROR_FIND_RESRC_NO_USBTMC_USB488
Definition: USBTMCPrivate.h:98
MTL::CException::what
virtual const char * what() const noexcept
Return string describing what happened.
Definition: Exception.h:34
USBTMC_INITIATE_CLEAR_RESP_LENGTH
static const U16 USBTMC_INITIATE_CLEAR_RESP_LENGTH
Definition: USBTMCPrivate.h:43
USBTMCInstrument.h
USBTMC driver based on libusb: interface definition.
Claim
bool Claim(libusb_device *pDevice, U32 Timeout=0)
Definition: USBTMCInstrument.cpp:429
USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH
Definition: USBTMCPrivate.h:49
DEV_DEP_MSG_IN
static const U8 DEV_DEP_MSG_IN
Definition: USBTMCPrivate.h:83
USBTMC_CHECK_CLEAR_STATUS_INTERVAL
static const U32 USBTMC_CHECK_CLEAR_STATUS_INTERVAL
Definition: USBTMCPrivate.h:45
MTL::Instrument::tResourceName
std::string tResourceName
IEEE488 resource name.
Definition: IEEE488InstrumentTypes.h:22
MTL::Instrument::CUSBTMCInstrument::IsOpen
virtual bool IsOpen(void)
Check whether a session to this instrument is open.
Definition: USBTMCInstrument.cpp:657
MTL::Instrument::CIEEE488ResourceManager::Status
I32 Status(void)
Definition: IEEE488Instrument.h:46
USBTMCBulkOutHeaderWrite
static void USBTMCBulkOutHeaderWrite(U8 *pHeader, U8 MsgID, U8 bTag, U32 TransferSize, U8 bmTransferAttributes, char TermChar)
Definition: USBTMCInstrument.cpp:343
CHECK_ABORT_BULK_IN_STATUS
@ CHECK_ABORT_BULK_IN_STATUS
Definition: USBTMCPrivate.h:21
tControlRecord::~tControlRecord
~tControlRecord(void)
Definition: USBTMCInstrument.cpp:385
MTL::Instrument::CIEEE488Instrument::m_rRrsrcMan
CIEEE488ResourceManager & m_rRrsrcMan
Reference to the associated resource manager.
Definition: IEEE488Instrument.h:69
MTL::Instrument::CSCPIBuffer::clear
void clear()
Clear by setting the buffer size to zero.
Definition: SCPIInstrumentBuffer.h:74
USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH
Definition: USBTMCPrivate.h:47
MTL::Instrument::CUSBTMCInstrument::AssertTrigger
virtual bool AssertTrigger(void)
Assert a trigger.
Definition: USBTMCInstrument.cpp:1262
MTL::Instrument::CSCPIBuffer::data
MTL_INSTRUMENT_BUFFER_TYPE * data() noexcept
Return a pointer to the data.
Definition: SCPIInstrumentBuffer.h:154
tControlRecord::UseCount
U32 UseCount
Definition: USBTMCInstrument.cpp:382
USBTMC_ERROR_READ_INVALID_HEADER
@ USBTMC_ERROR_READ_INVALID_HEADER
Definition: USBTMCPrivate.h:102
MTL::Instrument::CUSBTMCResourceManager::FindResources
virtual bool FindResources(CResourceList &rList, std::string Filter="?*")
Find USBTMC resources.
Definition: USBTMCInstrument.cpp:103
USBTMCBulkInHeaderRead
static bool USBTMCBulkInHeaderRead(U8 *pHeader, U8 MsgID, U8 bTag, I32 &TransferSize, U8 &bmTransferAttributes)
Definition: USBTMCInstrument.cpp:360
U8
unsigned char U8
Unsigned byte.
Definition: OSDefines.h:30
MTL::Instrument::CIEEE488Instrument::m_Status
I32 m_Status
Status of last operation.
Definition: IEEE488Instrument.h:71
MTL::Synchronization::CLockGuard
Lock.
Definition: Synchronization.h:63
W8
#define W8(p, x)
Definition: USBTMCPrivate.h:280
U16
unsigned short U16
16-bit unsigned integer.
Definition: OSDefines.h:31
MTL::Instrument::CUSBTMCInstrument::CUSBTMCInstrument
CUSBTMCInstrument(CUSBTMCResourceManager &rRM, tResourceName Rsrc)
Constructor.
Definition: USBTMCInstrument.cpp:455
OSDefines.h
Platform Dependent Definitions.
MTL::Instrument::CSCPIBuffer
Instrument Buffer.
Definition: SCPIInstrumentBuffer.h:44
USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR
@ USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR
Definition: USBTMCPrivate.h:106
USBTMC_ERROR_DEVICE_NOT_OPEN
@ USBTMC_ERROR_DEVICE_NOT_OPEN
Definition: USBTMCPrivate.h:110
MTL_Unused
#define MTL_Unused(x)
Definition: Helpers.h:47
USBTMC_ERROR_EXPLANATION
static const char * USBTMC_ERROR_EXPLANATION[]
Error explanations.
Definition: USBTMCPrivate.h:114
U32
unsigned int U32
32-bit unsigned integer.
Definition: OSDefines.h:32
MTL::Instrument::CUSBTMCResourceManager::~CUSBTMCResourceManager
virtual ~CUSBTMCResourceManager(void)
Destructor.
Definition: USBTMCInstrument.cpp:51
MTL_USBTMC_PAUSE_BETWEEN_READS
#define MTL_USBTMC_PAUSE_BETWEEN_READS
Definition: USBTMCInstrument.cpp:36
MTL::Instrument::CIEEE488Instrument::Status
I32 Status(void)
Definition: IEEE488Instrument.h:93
R8
#define R8(x)
Memory access macros.
Definition: USBTMCPrivate.h:140
MTL__LOCATION__
#define MTL__LOCATION__
Definition: Helpers.h:22
l_USBTMCAccessControl
l_USBTMCAccessControl
Definition: USBTMCInstrument.cpp:451
Release
bool Release(libusb_device *pDevice)
Definition: USBTMCInstrument.cpp:438
CHECK_ABORT_BULK_OUT_STATUS
@ CHECK_ABORT_BULK_OUT_STATUS
Definition: USBTMCPrivate.h:19
USB_DESCRIPTOR_STRING_LENGTH
static const U32 USB_DESCRIPTOR_STRING_LENGTH
Definition: USBTMCPrivate.h:37