| THM1176InstrumentDriver 1.2 C++ API for Metrolab THM1176

Loading...
Searching...
No Matches
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
45 CUSBTMCResourceManager::CUSBTMCResourceManager(void) :
46 m_pContext(nullptr)
47{
48
49} // CUSBTMCResourceManager::CUSBTMCResourceManager
50
51 CUSBTMCResourceManager::~CUSBTMCResourceManager(void)
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
69 bool CUSBTMCResourceManager::Initialize(void)
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.
88 catch (MTL::CException<CUSBTMCResourceManager> & rE)
89 {
90 MTL_Unused(rE)
91 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
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)
125 throw Exception(USBTMC_ERROR_FIND_RESRC_BAD_FILTER, MTL__LOCATION__);
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.
187 U8 l_String[USB_DESCRIPTOR_STRING_LENGTH];
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.
240 catch (MTL::CException<CUSBTMCResourceManager> & rE)
241 {
242 MTL_Unused(rE)
243 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
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 {
285 m_Status = USBTMC_ERROR_GET_RESRC_NOT_FOUND;
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
301std::string CUSBTMCResourceManager::StatusDescription (I32 Status)
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
308 return USBTMC_ERROR_EXPLANATION[Status];
309
310} // CUSBTMCResourceManager::StatusDescription
311
312 bool CUSBTMCResourceManager::Timeout(void)
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;
326 return MTL::CException<CUSBTMCResourceManager>(StatusDescription(Status), Location);
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.
378 class tControlRecord
379{
380 public:
381 std::timed_mutex Mutex;
382 U32 UseCount;
383 tControlRecord(void): UseCount(1)
384 { }
385 ~tControlRecord(void)
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
451} l_USBTMCAccessControl;
452
453//------------------------------------------//
454// Instrument management.
455
456// Constructors / destructors
457 CUSBTMCInstrument::CUSBTMCInstrument(CUSBTMCResourceManager & rRM, tResourceName Rsrc)
458 : CIEEE488Instrument(rRM, Rsrc), m_pDevice(nullptr), m_hDevice(nullptr),
459 m_ConfigurationNo(0), m_InterfaceNo(0), m_InterruptEndpoint(0), m_BulkInEndpoint(0), m_BulkOutEndpoint(0),
460 m_BulkInMaxPacketSize(0), m_bTag(0), m_ExclusiveLock(false), m_SRQEnable(false)
461{
462
463} // CUSBTMCInstrument::CUSBTMCInstrument
464
465 CUSBTMCInstrument::~CUSBTMCInstrument(void)
466{
467 // Make sure the device is closed.
468 CUSBTMCInstrument::Close();
469
470 // Make sure the lock is released.
471 CUSBTMCInstrument::Unlock();
472
473} // CUSBTMCInstrument::~CUSBTMCInstrument
474
475//------------------------------------------//
476// Connection
477 bool CUSBTMCInstrument::Open(void)
478{
479 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
480 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
481
482 struct libusb_config_descriptor * l_pConfig = nullptr;
483
484 try
485 {
486 // If the device is already open, we're done.
487 if (IsOpen()) return true;
488
489 // Get the device list entry.
490 if (!dynamic_cast<CUSBTMCResourceManager *>(&m_rRrsrcMan)->GetDeviceListEntry(m_Rsrc, m_pDevice))
491 throw Exception(USBTMC_ERROR_GET_RESRC_NOT_FOUND, MTL__LOCATION__);
492
493 // Get the device descriptor of this device.
494 struct libusb_device_descriptor l_USBDeviceDescriptor;
495 m_Status = libusb_get_device_descriptor(m_pDevice, &l_USBDeviceDescriptor);
496 if (m_Status != LIBUSB_SUCCESS)
497 throw Exception(m_Status, MTL__LOCATION__);
498
499 // Loop through the configurations and interfaces to find the USBTMC-USB488 interface.
500 bool l_FoundInterface = false;
501 for (U8 l_iConf = 0; l_iConf < l_USBDeviceDescriptor.bNumConfigurations; l_iConf++)
502 {
503 int l_ReturnValue = libusb_get_config_descriptor(m_pDevice, l_iConf, &l_pConfig);
504 if (l_ReturnValue < 0 && l_ReturnValue != LIBUSB_ERROR_NOT_FOUND)
505 continue;
506
507 // Loop through interfaces and check whether they are the USBTMC-USB488 interface.
508 for (int l_iIntfc = 0; l_iIntfc < l_pConfig->bNumInterfaces; l_iIntfc++)
509 {
510 const struct libusb_interface_descriptor * l_pIntfc = l_pConfig->interface[l_iIntfc].altsetting;
511 if (l_pIntfc->bInterfaceClass != LIBUSB_CLASS_APPLICATION ||
512 l_pIntfc->bInterfaceSubClass != SUBCLASS_USBTMC ||
513 l_pIntfc->bInterfaceProtocol != USBTMC_USB488)
514 continue;
515 m_ConfigurationNo = l_pConfig->bConfigurationValue;
516 m_InterfaceNo = l_pIntfc->bInterfaceNumber;
517
518 // Loop through the endpoints to identify BULKIN, BULKOUT, INETERRUPT.
519 for (int l_iEP = 0; l_iEP < l_pIntfc->bNumEndpoints; l_iEP++)
520 {
521 const struct libusb_endpoint_descriptor * l_pEndpoint = &l_pIntfc->endpoint[l_iEP];
522 if (l_pEndpoint->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
523 !(l_pEndpoint->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)))
524 {
525 m_BulkOutEndpoint = l_pEndpoint->bEndpointAddress;
526 }
527 if (l_pEndpoint->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
528 l_pEndpoint->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))
529 {
530 m_BulkInEndpoint = l_pEndpoint->bEndpointAddress;
531 }
532 if (l_pEndpoint->bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
533 l_pEndpoint->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))
534 {
535 m_InterruptEndpoint = l_pEndpoint->bEndpointAddress;
536 }
537 }
538
539 // Get the MaxPacketSize for the BulkIn endpoint.
540 m_BulkInMaxPacketSize = libusb_get_max_packet_size(m_pDevice, m_BulkInEndpoint);
541
542 // Flag that we found the interface.
543 l_FoundInterface = true;
544
545 } // Loop through interfaces
546
547 // Free the configuration descriptor.
548 libusb_free_config_descriptor(l_pConfig);
549 l_pConfig = nullptr;
550 if (l_FoundInterface) break;
551
552 } // Loop through configuration descriptors.
553
554 // Make sure we found the interface.
555 if (!l_FoundInterface)
556 throw Exception(USBTMC_ERROR_FIND_RESRC_NO_USBTMC_USB488, MTL__LOCATION__);
557
558 // Get the handle to the device.
559 m_Status = libusb_open(m_pDevice, &m_hDevice);
560 if (m_Status != LIBUSB_SUCCESS)
561 throw Exception(m_Status, MTL__LOCATION__);
562
563 // Set to detach the kernel driver automatically.
564 // Note: this might return LIBUSB_ERROR_NOT_SUPPORTED, but we don't care.
565 libusb_set_auto_detach_kernel_driver (m_hDevice, 1);
566
567 // Set the current configuration, if needed.
568 int l_CurrentConfig;
569 m_Status = libusb_get_configuration(m_hDevice, &l_CurrentConfig);
570 if (m_Status != LIBUSB_SUCCESS)
571 throw Exception(m_Status, MTL__LOCATION__);
572 if (l_CurrentConfig != m_ConfigurationNo)
573 {
574 m_Status =libusb_set_configuration(m_hDevice, m_ConfigurationNo);
575 if (m_Status != LIBUSB_SUCCESS)
576 throw Exception(m_Status, MTL__LOCATION__);
577 }
578
579 // Register the device with our access-control mechanism.
580 l_USBTMCAccessControl.Register(m_pDevice);
581 }
582
583 // Handle errors.
584 catch (MTL::CException<CUSBTMCInstrument> & rE)
585 {
586 MTL_Unused(rE)
587 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
588
589 if (l_pConfig != nullptr)
590 libusb_free_config_descriptor(l_pConfig);
591
592 if (m_hDevice != nullptr)
593 {
594 libusb_close(m_hDevice);
595 m_hDevice = nullptr;
596 }
597
598 if (m_pDevice != nullptr)
599 {
600 libusb_unref_device(m_pDevice);
601 m_pDevice = nullptr;
602
603 m_ConfigurationNo = 0;
604 m_InterfaceNo = 0;
605 m_InterruptEndpoint = 0;
606 m_BulkInEndpoint = 0;
607 m_BulkOutEndpoint = 0;
608 m_BulkInMaxPacketSize = 0;
609 m_bTag = 0;
610
611 Unlock();
612 }
613 return false;
614 }
615
616 return true;
617
618} // CUSBTMCInstrument::Open
619
620 void CUSBTMCInstrument::Close(void)
621{
622 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
623 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
624
625 // If the device is already closed, we're done.
626 if (!CUSBTMCInstrument::IsOpen()) return;
627
628 // Unlock the interface.
629 CUSBTMCInstrument::Unlock();
630
631 // Close the device.
632 if (m_hDevice != nullptr)
633 {
634 libusb_close(m_hDevice);
635 m_hDevice = nullptr;
636 }
637
638 // Unreference the device pointer.
639 if (m_pDevice != nullptr)
640 {
641 libusb_unref_device(m_pDevice);
642 m_pDevice = nullptr;
643 }
644
645 // Unregister the device from our access-control mechanism.
646 l_USBTMCAccessControl.Unregister(m_pDevice);
647
648 // Clear the other class variables.
649 m_ConfigurationNo = 0;
650 m_InterfaceNo = 0;
651 m_InterruptEndpoint = 0;
652 m_BulkInEndpoint = 0;
653 m_BulkOutEndpoint = 0;
654 m_BulkInMaxPacketSize = 0;
655 m_bTag = 0;
656
657} // CUSBTMCInstrument::Close
658
659 bool CUSBTMCInstrument::IsOpen(void)
660{
661 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
662 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
663
664 return (m_pDevice != nullptr && m_hDevice != nullptr);
665
666} // CUSBTMCInstrument::IsOpen
667
668//------------------------------------------//
669// Info
670std::string CUSBTMCInstrument::StatusDescription (I32 Status)
671{
672 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
673 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
674
675 if (Status <= 0)
676 return libusb_error_name(Status);
677 else
678 return USBTMC_ERROR_EXPLANATION[Status];
679
680} // CUSBTMCInstrument::StatusDescription
681
682 bool CUSBTMCInstrument::Timeout(void)
683{
684 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
685 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
686
687 return (m_Status == LIBUSB_ERROR_TIMEOUT);
688
689} // CUSBTMCInstrument::Timeout
690
691//------------------------------------------//
692// Write
693// Low-level write.
694 bool CUSBTMCInstrument::USBTMCWrite(U8 MessageID, const char * pData, const size_t Size, U8 TransferAttributes)
695{
696 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
697 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
698
699 bool l_InitialLockState = m_ExclusiveLock;
700 U8 * l_pBuffer = nullptr;
701 try
702 {
703 // Make sure this device is open.
704 if (!IsOpen())
705 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
706
707 // Lock the device.
708 if (!LockExclusive(m_Timeout))
709 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
710
711 // Allocate the buffer.
712 I32 l_Size = pData ? static_cast<I32>(Size) : 0;
713 I32 l_PaddedSize = (l_Size + USBTMC_BULK_HEADER_SIZE + 3) & ~0x3;
714 l_pBuffer = new U8[static_cast<size_t>(l_PaddedSize)];
715 if (!l_pBuffer)
716 throw Exception(LIBUSB_ERROR_NO_MEM, MTL__LOCATION__);
717
718 // Increment the bTag; ensure that it is in the valid range for ReadSTB.
719 if (++m_bTag < 2 || m_bTag > 127)
720 m_bTag = 2;
721
722 // Build the write buffer: header, data, padding.
723 USBTMCBulkOutHeaderWrite(l_pBuffer, MessageID, m_bTag, static_cast<U32>(Size), TransferAttributes, 0);
724 if (pData) std::memcpy(l_pBuffer + USBTMC_BULK_HEADER_SIZE, pData, static_cast<size_t>(l_Size));
725 std::memset(l_pBuffer + l_Size + USBTMC_BULK_HEADER_SIZE, 0, static_cast<size_t>(l_PaddedSize - l_Size - USBTMC_BULK_HEADER_SIZE));
726
727 // Transfer the data.
728 I32 l_Transferred;
729 m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
730 m_BulkOutEndpoint, // endpoint
731 l_pBuffer, // data
732 l_PaddedSize, // length
733 &l_Transferred, // transferred
734 static_cast<unsigned int>(m_Timeout)); // timeout
735 if (m_Status != LIBUSB_SUCCESS)
736 {
737 USBTMCClearBulkOut(m_bTag); // Clear the endpoint
738 Clear(); // Clear the device FIFOs
739 throw Exception(m_Status, MTL__LOCATION__);
740 }
741 if (l_Transferred != l_PaddedSize)
742 throw Exception(USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT, MTL__LOCATION__);
743 }
744
745 // Handle errors.
746 catch (MTL::CException<CUSBTMCInstrument> & rE)
747 {
748 MTL_Unused(rE)
749 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
750
751 // Restore the lock to its initial state.
752 if (!l_InitialLockState) Unlock();
753
754 return false;
755 }
756
757 // Restore the lock to its initial state.
758 if (!l_InitialLockState) Unlock();
759
760 // Deallocate the buffer.
761 if (l_pBuffer) delete l_pBuffer;
762
763 return true;
764
765} // CUSBTMCInstrument::USBTMCWrite
766
767 bool CUSBTMCInstrument::Write(const char * Str)
768{
769 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
770 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
771
772 return USBTMCWrite(DEV_DEP_MSG_OUT, Str, std::strlen(Str), EOM);
773
774} // CUSBTMCInstrument::Write(const char * Str)
775
776 bool CUSBTMCInstrument::Write(const std::string & rStr)
777{
778 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
779 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
780
781 return USBTMCWrite(DEV_DEP_MSG_OUT, rStr.c_str(), rStr.size(), EOM);
782
783} // CUSBTMCInstrument::Write(const std::string & rStr)
784
785 bool CUSBTMCInstrument::Write(const CSCPIBuffer & rBuf)
786{
787 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
788 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
789
790 return USBTMCWrite(DEV_DEP_MSG_OUT, rBuf.data(), rBuf.size(), EOM);
791
792} // CUSBTMCInstrument::Write(const CSCPIBuffer & rBuf)
793
794//------------------------------------------//
795// Read
796 bool CUSBTMCInstrument::Read(CSCPIBuffer & rBuf, bool Append)
797{
798 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
799 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
800
801 bool l_InitialLockState = m_ExclusiveLock;
802 try
803 {
804 // Make sure this device is open.
805 if (!IsOpen())
806 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
807
808 // Lock the device.
809 if (!LockExclusive(m_Timeout))
810 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
811
812 // Clear the buffer if we're not appending.
813 if (!Append) rBuf.clear();
814
815 // Write REQUEST_DEV_DEP_MSG_IN, with an enormous buffer size.
816 USBTMCWrite(REQUEST_DEV_DEP_MSG_IN, nullptr, INT32_MAX, 0);
817 if (m_Status != LIBUSB_SUCCESS)
818 throw Exception(m_Status, MTL__LOCATION__);
819
820 // Read the header and at least the beginning of the message.
821 // Note: since max packet size > header length, we can't read just the header.
822 // Note: sometimes, for reasons unknown, libusb_bulk_transfer returns success but l_Transferred = 0
823 // (does not appear to be a zero-length USB transfer). In this case, repeat the transfer.
824 assert(m_BulkInMaxPacketSize >= USBTMC_BULK_HEADER_SIZE);
825 I32 l_BufferLength = m_BulkInMaxPacketSize;
826 assert(l_BufferLength <= USBTMC_READ_BUFFER_SIZE);
827 U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
828 I32 l_Transferred = 0;
829 do
830 {
831 m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
832 m_BulkInEndpoint, // endpoint
833 l_ReadBuffer, // data
834 l_BufferLength, // length
835 &l_Transferred, // transferred
836 static_cast<unsigned int>(m_Timeout)); // timeout
837 if (m_Status < 0)
838 {
839 USBTMCClearBulkIn(m_bTag);
840 throw Exception(m_Status, MTL__LOCATION__);
841 }
842 } while (l_Transferred == 0);
843 if (l_Transferred < USBTMC_BULK_HEADER_SIZE)
844 throw Exception(USBTMC_ERROR_READ_INVALID_HEADER, MTL__LOCATION__);
845
846 // Parse and check the header.
847 I32 l_MessageSize;
848 U8 l_TransferAttributes;
849 if (!USBTMCBulkInHeaderRead(l_ReadBuffer, DEV_DEP_MSG_IN, m_bTag, l_MessageSize, l_TransferAttributes) ||
850 !(l_TransferAttributes & EOM))
851 throw Exception(USBTMC_ERROR_READ_INVALID_HEADER, MTL__LOCATION__);
852
853 // If necessary, adjust the buffer size to accenpt the entire message.
854 size_t l_BufSize = rBuf.size();
855 size_t l_BufCapacity = rBuf.capacity();
856 if (l_MessageSize > static_cast<I32>(l_BufCapacity - l_BufSize))
857 rBuf.reserve(l_BufSize + static_cast<size_t>(l_MessageSize));
858
859 // Copy the part of the message that we have already received.
860 size_t l_MessageReceived = static_cast<size_t>(l_Transferred) - USBTMC_BULK_HEADER_SIZE;
861 if (l_MessageReceived > 0)
862 std::memcpy(rBuf.data() + l_BufSize, l_ReadBuffer + USBTMC_BULK_HEADER_SIZE, l_MessageReceived);
863
864 // Read the rest of the message, if applicable.
865 size_t l_MessagePending = static_cast<size_t>(l_MessageSize) - l_MessageReceived;
866 if (l_MessagePending > 0)
867 {
868 // Note: small delay before second read. This alleviates a problem - probably host/device specific -
869 // where the device does not flush its FIFO.
870 std::this_thread::sleep_for(std::chrono::milliseconds(MTL_USBTMC_PAUSE_BETWEEN_READS));
871 U8 * l_pData = reinterpret_cast<U8 *>(rBuf.data() + l_BufSize + l_MessageReceived);
872 m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
873 m_BulkInEndpoint, // endpoint
874 l_pData, // data
875 static_cast<I32>(l_MessagePending), // length
876 &l_Transferred, // transferred
877 static_cast<unsigned int>(m_Timeout)); // timeout
878 if (m_Status < 0)
879 {
880 USBTMCClearBulkIn(m_bTag);
881 throw Exception(m_Status, MTL__LOCATION__);
882 }
883 if (l_Transferred != static_cast<I32>(l_MessagePending))
884 throw Exception(USBTMC_ERROR_READ_WRONG_MSG_SIZE, MTL__LOCATION__);
885 }
886
887 // Resize the buffer to the cumulated number of bytes read.
888 rBuf.resize(l_BufSize + static_cast<size_t>(l_MessageSize));
889 }
890
891 // Handle errors.
892 catch (MTL::CException<CUSBTMCInstrument> & rE)
893 {
894 MTL_Unused(rE)
895 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
896
897 // Restore the lock to its initial state.
898 if (!l_InitialLockState) Unlock();
899
900 return false;
901 }
902
903 // Restore the lock to its initial state.
904 if (!l_InitialLockState) Unlock();
905
906 return true;
907
908} // CUSBTMCInstrument::Read
909
910//------------------------------------------//
911// Other operations
912 bool CUSBTMCInstrument::USBTMCClearBulkIn(U8 bTag)
913{
914 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
915 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
916
917 try
918 {
919 // Clear the STALL condition, if any.
920 I32 l_ReturnValue = libusb_clear_halt(m_hDevice, m_BulkInEndpoint);
921 if (l_ReturnValue < 0)
922 throw Exception(l_ReturnValue, MTL__LOCATION__);
923
924 // Initiate the Abort BulkIn.
925 // Note: use default timeout, since user-supplied timeout may be unsuitable.
926 assert(USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
927 assert(USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
928 assert(m_BulkInMaxPacketSize <= USBTMC_READ_BUFFER_SIZE);
929 U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
930 l_ReturnValue = libusb_control_transfer(
931 m_hDevice, // dev_handle
932 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
933 INITIATE_ABORT_BULK_IN, // bRequest
934 static_cast<U16>(bTag), // wValue
935 m_BulkInEndpoint, // wIndex
936 l_ReadBuffer, // data
937 USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH, // wLength
938 IEEE488_DEFAULT_TIMEOUT); // timeout
939
940 // Check for errors.
941 if (l_ReturnValue < 0)
942 throw Exception(l_ReturnValue, MTL__LOCATION__);
943 if (l_ReturnValue != USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH ||
944 l_ReadBuffer[0] != USBTMC_STATUS_SUCCESS)
945 throw Exception(USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR, MTL__LOCATION__);
946
947 // Flush the device's transfer FIFO.
948 // Note: use default timeout, since user-supplied timeout may be unsuitable.
949 I32 l_BufferLength = m_BulkInMaxPacketSize;
950 I32 l_Transferred;
951 do
952 {
953 l_ReturnValue = libusb_bulk_transfer(
954 m_hDevice, // dev_handle
955 m_BulkInEndpoint, // endpoint
956 l_ReadBuffer, // data
957 l_BufferLength, // length
958 &l_Transferred, // transferred
959 IEEE488_DEFAULT_TIMEOUT); // timeout
960 if (l_ReturnValue < 0)
961 throw Exception(m_Status, MTL__LOCATION__);
962 } while (l_Transferred >= l_BufferLength);
963
964 // Loop to poll the Initiate BulkIn Abort status.
965 // Note: use default timeout, since user-supplied timeout may be unsuitable.
966 U8 l_Status;
967 do
968 {
969 l_ReturnValue = libusb_control_transfer(
970 m_hDevice, // dev_handle
971 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
972 CHECK_ABORT_BULK_IN_STATUS, // bRequest
973 0x0000, // wValue
974 m_BulkInEndpoint, // wIndex
975 l_ReadBuffer, // data
976 USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH, // wLength
977 IEEE488_DEFAULT_TIMEOUT); // timeout
978
979 if (l_ReturnValue < 0)
980 throw Exception(l_ReturnValue, MTL__LOCATION__);
981 if (l_ReturnValue != USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH ||
982 ((l_Status = l_ReadBuffer[0]) != USBTMC_STATUS_SUCCESS && l_Status != USBTMC_STATUS_PENDING) ||
983 l_ReadBuffer[1] != 0 || // BulkIn FIFO should be empty
984 l_ReadBuffer[2] != 0 || // Always zero
985 l_ReadBuffer[3] != 0) // Always zero
986 throw Exception(USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR, MTL__LOCATION__);
987
988 std::this_thread::sleep_for(std::chrono::milliseconds(USBTMC_CHECK_CLEAR_STATUS_INTERVAL));
989
990 } while (l_Status != USBTMC_STATUS_SUCCESS);
991 }
992
993 // Handle errors.
994 catch (MTL::CException<CUSBTMCInstrument> & rE)
995 {
996 MTL_Unused(rE)
997 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
998 return false;
999 }
1000
1001 return true;
1002
1003} // CUSBTMCInstrument::USBTMCClearBulkIn
1004
1005 bool CUSBTMCInstrument::USBTMCClearBulkOut(U8 bTag)
1006{
1007 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1008 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1009
1010 try
1011 {
1012 // Clear the STALL condition, if any.
1013 I32 l_ReturnValue = libusb_clear_halt(m_hDevice, m_BulkOutEndpoint);
1014 if (l_ReturnValue < 0)
1015 throw Exception(l_ReturnValue, MTL__LOCATION__);
1016
1017 // Initiate the Abort BulkOut.
1018 // Note: use default timeout, since user-supplied timeout may be unsuitable.
1019 assert(USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
1020 assert(USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
1021 U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
1022 l_ReturnValue = libusb_control_transfer(
1023 m_hDevice, // dev_handle
1024 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
1025 INITIATE_ABORT_BULK_OUT, // bRequest
1026 static_cast<U16>(bTag), // wValue
1027 m_BulkOutEndpoint, // wIndex
1028 l_ReadBuffer, // data
1029 USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH, // wLength
1030 IEEE488_DEFAULT_TIMEOUT); // timeout
1031
1032 // Check for errors.
1033 if (l_ReturnValue < 0)
1034 throw Exception(l_ReturnValue, MTL__LOCATION__);
1035 if (l_ReturnValue != USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH ||
1036 l_ReadBuffer[0] != USBTMC_STATUS_SUCCESS)
1037 throw Exception(USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR, MTL__LOCATION__);
1038
1039 // Loop to poll the Initiate BulkOut Abort status.
1040 // Note: use default timeout, since user-supplied timeout may be unsuitable.
1041 U8 l_Status;
1042 do
1043 {
1044 l_ReturnValue = libusb_control_transfer(
1045 m_hDevice, // dev_handle
1046 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP, // bmRequestType
1047 CHECK_ABORT_BULK_OUT_STATUS, // bRequest
1048 0x0000, // wValue
1049 m_BulkOutEndpoint, // wIndex
1050 l_ReadBuffer, // data
1051 USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH, // wLength
1052 IEEE488_DEFAULT_TIMEOUT); // timeout
1053
1054 if (l_ReturnValue < 0)
1055 throw Exception(l_ReturnValue, MTL__LOCATION__);
1056 if (l_ReturnValue != USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH ||
1057 ((l_Status = l_ReadBuffer[0]) != USBTMC_STATUS_SUCCESS && l_Status != USBTMC_STATUS_PENDING) ||
1058 l_ReadBuffer[1] != 0 || // Always zero
1059 l_ReadBuffer[2] != 0 || // Always zero
1060 l_ReadBuffer[3] != 0) // Always zero
1061 throw Exception(USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR, MTL__LOCATION__);
1062
1063 std::this_thread::sleep_for(std::chrono::milliseconds(USBTMC_CHECK_CLEAR_STATUS_INTERVAL));
1064
1065 } while (l_Status != USBTMC_STATUS_SUCCESS);
1066
1067 }
1068
1069 // Handle errors.
1070 catch (MTL::CException<CUSBTMCInstrument> & rE)
1071 {
1072 MTL_Unused(rE)
1073 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
1074 return false;
1075 }
1076
1077 return true;
1078
1079} // CUSBTMCInstrument::USBTMCClearBulkOut
1080
1081 bool CUSBTMCInstrument::Clear(void)
1082{
1083 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1084 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1085
1086 bool l_InitialLockState = m_ExclusiveLock;
1087 try
1088 {
1089 // Make sure this device is open.
1090 if (!IsOpen())
1091 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
1092
1093 // Lock the device.
1094 if (!LockExclusive(m_Timeout))
1095 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
1096
1097 // Initiate the Clear.
1098 // Note: use default timeout, since user-supplied timeout may be unsuitable.
1099 assert(USBTMC_INITIATE_CLEAR_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
1100 assert(USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
1101 U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
1102 I32 l_ReturnValue = libusb_control_transfer(
1103 m_hDevice, // dev_handle
1104 USBTMC_BM_REQUEST_TYPE_IN_CLS_IF, // bmRequestType
1105 INITIATE_CLEAR, // bRequest
1106 0x0000, // wValue
1107 USB_CONTROL_ENDPOINT_NUMBER, // wIndex
1108 l_ReadBuffer, // data
1109 USBTMC_INITIATE_CLEAR_RESP_LENGTH, // wLength
1110 IEEE488_DEFAULT_TIMEOUT); // timeout
1111
1112 // Check for errors.
1113 if (l_ReturnValue < 0)
1114 throw Exception(l_ReturnValue, MTL__LOCATION__);
1115 if (l_ReturnValue != USBTMC_INITIATE_CLEAR_RESP_LENGTH ||
1116 l_ReadBuffer[0] != USBTMC_STATUS_SUCCESS)
1117 throw Exception(USBTMC_ERROR_CLEAR_RESPONSE_ERROR, MTL__LOCATION__);
1118
1119 // Loop to poll the clear status.
1120 // Note: use default timeout, since user-supplied timeout may be unsuitable.
1121 U8 l_Status, l_Clear;
1122 do
1123 {
1124 l_ReturnValue = libusb_control_transfer(
1125 m_hDevice, // dev_handle
1126 USBTMC_BM_REQUEST_TYPE_IN_CLS_IF, // bmRequestType
1127 CHECK_CLEAR_STATUS, // bRequest
1128 0x0000, // wValue
1129 USB_CONTROL_ENDPOINT_NUMBER, // wIndex
1130 l_ReadBuffer, // data
1131 USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH, // wLength
1132 IEEE488_DEFAULT_TIMEOUT); // timeout
1133
1134 if (l_ReturnValue < 0)
1135 throw Exception(l_ReturnValue, MTL__LOCATION__);
1136 if (l_ReturnValue != USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH ||
1137 ((l_Status = l_ReadBuffer[0]) != USBTMC_STATUS_SUCCESS && l_Status != USBTMC_STATUS_PENDING) ||
1138 ((l_Clear = l_ReadBuffer[1]) != 0 && l_Clear != BULKIN_FIFO_BYTES) )
1139 throw Exception(USBTMC_ERROR_CLEAR_RESPONSE_ERROR, MTL__LOCATION__);
1140
1141 std::this_thread::sleep_for(std::chrono::milliseconds(USBTMC_CHECK_CLEAR_STATUS_INTERVAL));
1142
1143 } while (l_Status != USBTMC_STATUS_SUCCESS);
1144
1145 // Clear the BulkOut Halt condition.
1146 l_ReturnValue = libusb_clear_halt(m_hDevice, m_BulkOutEndpoint);
1147 if (l_ReturnValue < 0)
1148 throw Exception(l_ReturnValue, MTL__LOCATION__);
1149
1150 // If necessary, clear the BulkIn endpoint.
1151 if (l_Clear == BULKIN_FIFO_BYTES)
1152 USBTMCClearBulkIn(m_bTag);
1153 }
1154
1155 // Handle errors.
1156 catch (MTL::CException<CUSBTMCInstrument> & rE)
1157 {
1158 MTL_Unused(rE)
1159 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
1160
1161 // Restore the lock to its initial state.
1162 if (!l_InitialLockState) Unlock();
1163
1164 return false;
1165 }
1166
1167 // Restore the lock to its initial state.
1168 if (!l_InitialLockState) Unlock();
1169
1170 return true;
1171
1172} // CUSBTMCInstrument::Clear
1173
1174 bool CUSBTMCInstrument::ReadSTB(U16 & rSTB)
1175{
1176 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1177 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1178
1179 bool l_InitialLockState = m_ExclusiveLock;
1180 try
1181 {
1182 // Make sure this device is open.
1183 if (!IsOpen())
1184 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
1185
1186 // Lock the device.
1187 if (!LockExclusive(m_Timeout))
1188 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
1189
1190 // Loop to read the Status Byte.
1191 // Since we don't handle Service Requests at the moment (TODO), just flush them.
1192 // Note that Service Requests have the same packet length, but the bTag is 0x01 instead of the one we specify.
1193 assert(USBTMC_READSTB_CTRL_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
1194 assert(USBTMC_READSTB_INTR_RESP_LENGTH <= USBTMC_READ_BUFFER_SIZE);
1195 bool l_GotSTB = false;
1196 bool l_WriteCommand = true;
1197 bool l_Success = false;
1198 bool l_InterruptInBusy = false;
1199 t_InterruptInData l_InterruptInPacket;
1200 do
1201 {
1202 // Write the READ_STATUS_BYTE command only if required.
1203 if (l_WriteCommand)
1204 {
1205 // Increment the bTag; ensure that it is in the valid range for ReadSTB.
1206 if (++m_bTag < 2 || m_bTag > 127)
1207 m_bTag = 2;
1208
1209 // Send the READ_STATUS_BYTE command.
1210 U8 l_ReadBuffer[USBTMC_READ_BUFFER_SIZE];
1211 I32 l_ReturnValue = libusb_control_transfer(
1212 m_hDevice, // dev_handle
1213 USBTMC_BM_REQUEST_TYPE_IN_CLS_IF, // bmRequestType
1214 READ_STATUS_BYTE, // bRequest
1215 m_bTag, // wValue
1216 USB_CONTROL_ENDPOINT_NUMBER, // wIndex
1217 l_ReadBuffer, // data
1218 USBTMC_READSTB_CTRL_RESP_LENGTH, // wLength
1219 static_cast<unsigned int>(m_Timeout)); // timeout
1220
1221 // Check for errors.
1222 if (l_ReturnValue < 0)
1223 throw Exception(l_ReturnValue, MTL__LOCATION__);
1224 l_Success = USBTMCReadSTBResponse(l_ReadBuffer, USBTMC_STATUS_SUCCESS, m_bTag, 0);
1225 l_InterruptInBusy = USBTMCReadSTBResponse(l_ReadBuffer, USBTMC_STATUS_INTERRUPT_IN_BUSY, m_bTag, 0);
1226 if (l_ReturnValue != USBTMC_READSTB_CTRL_RESP_LENGTH ||
1227 !(l_Success || l_InterruptInBusy))
1228 throw Exception(USBTMC_ERROR_READSTB_CONTROL_RESPONSE_ERROR, MTL__LOCATION__);
1229
1230 // Do not write another READ_STATUS_BYTE command unless asked to.
1231 l_WriteCommand = false;
1232 }
1233
1234 // Read the next packet from the Interrupt-In endpoint.
1235 I32 l_Transferred;
1236 I32 l_ReturnValue = libusb_interrupt_transfer(
1237 m_hDevice, // dev_handle
1238 m_InterruptEndpoint, // endpoint
1239 reinterpret_cast<U8 *>(&l_InterruptInPacket), // data
1240 USBTMC_READSTB_INTR_RESP_LENGTH, // length
1241 &l_Transferred, // transferred
1242 static_cast<unsigned int>(m_Timeout)); // timeout
1243
1244 // If we had an "Interrupt-In Busy" warning and the Interrupt-In FIFO is now empty,
1245 // set up to send another READ_STATUS_BYTE command.
1246 if (l_InterruptInBusy && l_ReturnValue == LIBUSB_ERROR_TIMEOUT)
1247 {
1248 l_WriteCommand = true;
1249 continue;
1250 }
1251
1252 // Check for other errors.
1253 if (l_ReturnValue < 0)
1254 throw Exception(l_ReturnValue, MTL__LOCATION__);
1255 if (l_Transferred != USBTMC_READSTB_INTR_RESP_LENGTH)
1256 throw Exception(USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR, MTL__LOCATION__);
1257
1258 // If enabled, Service Requests are enqueued; otherwise they are discarded.
1259 if (l_InterruptInPacket.bNotify1 == 0x81)
1260 {
1261 if (m_SRQEnable) m_SRQQueue.push(l_InterruptInPacket);
1262 continue;
1263 }
1264
1265 // Validate the Read STB response.
1266 if (l_InterruptInPacket.bNotify1 != (0x80 | m_bTag))
1267 throw Exception(USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR, MTL__LOCATION__);
1268
1269 // Return the status byte.
1270 rSTB = l_InterruptInPacket.bNotify2;
1271 l_GotSTB = true;
1272 } while (!l_GotSTB);
1273
1274 }
1275
1276 // Handle errors.
1277 catch (MTL::CException<CUSBTMCInstrument> & rE)
1278 {
1279 MTL_Unused(rE)
1280 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
1281
1282 // Restore the lock to its initial state.
1283 if (!l_InitialLockState) Unlock();
1284
1285 return false;
1286 }
1287
1288 // Restore the lock to its initial state.
1289 if (!l_InitialLockState) Unlock();
1290
1291 return true;
1292
1293} // CUSBTMCInstrument::ReadSTB
1294
1295 bool CUSBTMCInstrument::AssertTrigger(void)
1296{
1297 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1298 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1299
1300 bool l_InitialLockState = m_ExclusiveLock;
1301 try
1302 {
1303 // Make sure this device is open.
1304 if (!IsOpen())
1305 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
1306
1307 // Lock the device.
1308 if (!LockExclusive(m_Timeout))
1309 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
1310
1311 // Increment the bTag; ensure that it is in the valid range for ReadSTB.
1312 if (++m_bTag < 2 || m_bTag > 127)
1313 m_bTag = 2;
1314
1315 // Build the write buffer: everything except MsgID, bTag, and ~bTag is zero.
1316 U8 l_Buffer[USBTMC_BULK_TRIGGER_MSG_SIZE];
1317 USBTMCBulkOutHeaderWrite(l_Buffer, TRIGGER, m_bTag, 0, 0, 0);
1318
1319 // Transfer the data.
1320 I32 l_Transferred;
1321 m_Status = libusb_bulk_transfer(m_hDevice, // dev_handle
1322 m_BulkOutEndpoint, // endpoint
1323 l_Buffer, // data
1324 USBTMC_BULK_TRIGGER_MSG_SIZE, // length
1325 &l_Transferred, // transferred
1326 static_cast<unsigned int>(m_Timeout)); // timeout
1327 if (m_Status != LIBUSB_SUCCESS)
1328 {
1329 USBTMCClearBulkOut(m_bTag); // Clear the endpoint
1330 Clear(); // Clear the device FIFOs
1331 throw Exception(m_Status, MTL__LOCATION__);
1332 }
1333 if (l_Transferred != USBTMC_BULK_TRIGGER_MSG_SIZE)
1334 throw Exception(USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT, MTL__LOCATION__);
1335 }
1336
1337 // Handle errors.
1338 catch (MTL::CException<CUSBTMCInstrument> & rE)
1339 {
1340 MTL_Unused(rE)
1341 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
1342
1343 // Restore the lock to its initial state.
1344 if (!l_InitialLockState) Unlock();
1345
1346 return false;
1347 }
1348
1349 // Restore the lock to its initial state.
1350 if (!l_InitialLockState) Unlock();
1351
1352 return true;
1353
1354} // CUSBTMCInstrument::AssertTrigger
1355
1356//------------------------------------------//
1357// Lock / Unlock
1358 bool CUSBTMCInstrument::LockExclusive(U32 Timeout)
1359{
1360 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1361 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1362
1363 // If it is already locked, we're done.
1364 if (m_ExclusiveLock) return true;
1365
1366 // Try to claim the interface.
1367 if (!l_USBTMCAccessControl.Claim(m_pDevice, Timeout))
1368 {
1369 m_Status = USBTMC_ERROR_INSTRUMENT_LOCKED;
1370 return false;
1371 }
1372
1373 // Tell libusb to claim the interface.
1374 I32 l_ReturnCode = libusb_claim_interface(m_hDevice, m_InterfaceNo);
1375 if (l_ReturnCode != LIBUSB_SUCCESS)
1376 {
1377 m_Status = l_ReturnCode;
1378 l_USBTMCAccessControl.Release(m_pDevice);
1379 return false;
1380 }
1381
1382 // Lock succeeded.
1383 m_ExclusiveLock = true;
1384 return true;
1385
1386} // CUSBTMCInstrument::LockExclusive
1387
1388 bool CUSBTMCInstrument::Unlock(void)
1389{
1390 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1391 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1392
1393 // If it is already unlocked, we're done.
1394 if (!m_ExclusiveLock) return true;
1395
1396 // Tell libusb to release the interface.
1397 I32 l_ReturnCode = libusb_release_interface(m_hDevice, m_InterfaceNo);
1398 if (l_ReturnCode != LIBUSB_SUCCESS)
1399 {
1400 m_Status = l_ReturnCode;
1401 return false;
1402 }
1403
1404 // Release the claim to the interface.
1405 l_USBTMCAccessControl.Release(m_pDevice);
1406
1407 m_ExclusiveLock = false;
1408 return true;
1409
1410} // CUSBTMCInstrument::Unlock
1411
1412 bool CUSBTMCInstrument::LockedExclusive(void)
1413{
1414 return m_ExclusiveLock;
1415
1416} // CUSBTMCInstrument::Locked
1417
1418
1419//------------------------------------------//
1420// Exception
1421 MTL::CException<CUSBTMCInstrument> CUSBTMCInstrument::Exception(I32 Status, std::string Location)
1422{
1423 m_Status = Status;
1424 return MTL::CException<CUSBTMCInstrument>(StatusDescription(Status), Location);
1425}
1426
1427//------------------------------------------//
1428// Service requests
1429 bool CUSBTMCInstrument::EnableEvent (void)
1430{
1431 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1432 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1433
1434 m_SRQEnable = true;
1435 return true;
1436
1437} // CUSBTMCInstrument::EnableEvent
1438
1439 bool CUSBTMCInstrument::DisableEvent (void)
1440{
1441 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1442 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1443
1444 m_SRQEnable = false;
1445 return true;
1446
1447} // CUSBTMCInstrument::DisableEvent
1448
1449 bool CUSBTMCInstrument::WaitOnEvent (U32 Timeout)
1450{
1451 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1452 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1453
1454 bool l_InitialLockState = m_ExclusiveLock;
1455 try
1456 {
1457 // Make sure this device is open.
1458 if (!IsOpen())
1459 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
1460
1461 // Make sure Service Requests are enabled.
1462 if (!m_SRQEnable)
1463 throw Exception(USBTMC_ERROR_SRQ_NOT_ENABLED, MTL__LOCATION__);
1464
1465 // If we have one, take a queued-up Service Request.
1466 if (m_SRQQueue.size() > 0)
1467 {
1468 m_SRQQueue.pop();
1469 }
1470
1471 // Else read the next packet from the Interrupt-In endpoint.
1472 else
1473 {
1474 // Lock the device.
1475 if (!LockExclusive(m_Timeout))
1476 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
1477
1478 // Read the Interrupt-In packet.
1479 t_InterruptInData l_InterruptInPacket;
1480 I32 l_Transferred;
1481 I32 l_ReturnValue = libusb_interrupt_transfer(
1482 m_hDevice, // dev_handle
1483 m_InterruptEndpoint, // endpoint
1484 reinterpret_cast<U8 *>(&l_InterruptInPacket), // data
1485 USBTMC_READSTB_INTR_RESP_LENGTH, // length
1486 &l_Transferred, // transferred
1487 static_cast<unsigned int>(Timeout)); // timeout
1488
1489 // Check for errors.
1490 if (l_ReturnValue < 0)
1491 throw Exception(l_ReturnValue, MTL__LOCATION__);
1492 if (l_Transferred != USBTMC_READSTB_INTR_RESP_LENGTH ||
1493 l_InterruptInPacket.bNotify1 != 0x81)
1494 throw Exception(USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR, MTL__LOCATION__);
1495 }
1496 }
1497
1498 // Handle errors.
1499 catch (MTL::CException<CUSBTMCInstrument> & rE)
1500 {
1501 MTL_Unused(rE)
1502 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
1503
1504 // Restore the lock to its initial state.
1505 if (!l_InitialLockState) Unlock();
1506
1507 return false;
1508 }
1509
1510 // Restore the lock to its initial state.
1511 if (!l_InitialLockState) Unlock();
1512
1513 return true;
1514
1515} // CUSBTMCInstrument::WaitOnEvent
1516
1517 bool CUSBTMCInstrument::DiscardEvents (void)
1518{
1519 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1520 CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
1521
1522 bool l_InitialLockState = m_ExclusiveLock;
1523 try
1524 {
1525 // Make sure this device is open.
1526 if (!IsOpen())
1527 throw Exception(USBTMC_ERROR_DEVICE_NOT_OPEN, MTL__LOCATION__);
1528
1529 // Make sure Service Requests are enabled.
1530 if (!m_SRQEnable)
1531 throw Exception(USBTMC_ERROR_SRQ_NOT_ENABLED, MTL__LOCATION__);
1532
1533 // Lock the device.
1534 if (!LockExclusive(m_Timeout))
1535 throw Exception(USBTMC_ERROR_INSTRUMENT_LOCKED, MTL__LOCATION__);
1536
1537 // Flush the Service-Request queue.
1538 while (m_SRQQueue.size() > 0)
1539 m_SRQQueue.pop();
1540
1541 // Flush the instrument's Interrupt-In FIFO.
1542 while (true)
1543 {
1544 // Read an Interrupt-In packet.
1545 t_InterruptInData l_InterruptInPacket;
1546 I32 l_Transferred;
1547 I32 l_ReturnValue = libusb_interrupt_transfer(
1548 m_hDevice, // dev_handle
1549 m_InterruptEndpoint, // endpoint
1550 reinterpret_cast<U8 *>(&l_InterruptInPacket), // data
1551 USBTMC_READSTB_INTR_RESP_LENGTH, // length
1552 &l_Transferred, // transferred
1553 static_cast<unsigned int>(m_Timeout)); // timeout
1554
1555 // We're done if we get a timeout error.
1556 if (l_ReturnValue == LIBUSB_ERROR_TIMEOUT)
1557 break;
1558
1559 // Check for other errors.
1560 if (l_ReturnValue < 0)
1561 throw Exception(l_ReturnValue, MTL__LOCATION__);
1562 if (l_Transferred != USBTMC_READSTB_INTR_RESP_LENGTH ||
1563 l_InterruptInPacket.bNotify1 != 0x81)
1564 throw Exception(USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR, MTL__LOCATION__);
1565 }
1566 }
1567
1568 // Handle errors.
1569 catch (MTL::CException<CUSBTMCInstrument> & rE)
1570 {
1571 MTL_Unused(rE)
1572 MTL_USBTMC_INSTRUMENT_DEBUG_CERR(rE.what());
1573
1574 // Restore the lock to its initial state.
1575 if (!l_InitialLockState) Unlock();
1576
1577 return false;
1578 }
1579
1580 // Restore the lock to its initial state.
1581 if (!l_InitialLockState) Unlock();
1582
1583 return true;
1584
1585} // CUSBTMCInstrument::DiscardEvents
Helpers.h
Collection of utility macros for error messages.
MTL_Unused
#define MTL_Unused(x)
Definition Helpers.h:47
MTL__LOCATION__
#define MTL__LOCATION__
Definition Helpers.h:22
OSDefines.h
Platform Dependent Definitions.
U8
unsigned char U8
Unsigned byte.
Definition OSDefines.h:29
I32
int I32
32-bit signed integer.
Definition OSDefines.h:27
U32
unsigned int U32
32-bit unsigned integer.
Definition OSDefines.h:31
U16
unsigned short U16
16-bit unsigned integer.
Definition OSDefines.h:30
Register
bool Register(libusb_device *pDevice)
Definition USBTMCInstrument.cpp:394
USBTMCBulkOutHeaderWrite
static void USBTMCBulkOutHeaderWrite(U8 *pHeader, U8 MsgID, U8 bTag, U32 TransferSize, U8 bmTransferAttributes, char TermChar)
Definition USBTMCInstrument.cpp:343
USBTMCBulkInHeaderRead
static bool USBTMCBulkInHeaderRead(U8 *pHeader, U8 MsgID, U8 bTag, I32 &TransferSize, U8 &bmTransferAttributes)
Definition USBTMCInstrument.cpp:360
MTL_USBTMC_PAUSE_BETWEEN_READS
#define MTL_USBTMC_PAUSE_BETWEEN_READS
Definition USBTMCInstrument.cpp:36
MTL_USBTMC_INSTRUMENT_DEBUG_COUT
#define MTL_USBTMC_INSTRUMENT_DEBUG_COUT(__X__)
Definition USBTMCInstrument.cpp:33
Release
bool Release(libusb_device *pDevice)
Definition USBTMCInstrument.cpp:438
l_USBTMCAccessControl
l_USBTMCAccessControl
Definition USBTMCInstrument.cpp:451
Claim
bool Claim(libusb_device *pDevice, U32 Timeout=0)
Definition USBTMCInstrument.cpp:429
MTL_USBTMC_INSTRUMENT_DEBUG_CERR
#define MTL_USBTMC_INSTRUMENT_DEBUG_CERR(__X__)
Definition USBTMCInstrument.cpp:34
USBTMCReadSTBResponse
static bool USBTMCReadSTBResponse(U8 *pResponse, U8 USBTMC_status, U8 bTag, U8 StatusByte)
Definition USBTMCInstrument.cpp:333
Unregister
bool Unregister(libusb_device *pDevice)
Definition USBTMCInstrument.cpp:410
USBTMCInstrument.h
USBTMC driver based on libusb: interface definition.
USBTMCPrivate.h
BULKIN_FIFO_BYTES
static const U8 BULKIN_FIFO_BYTES
Definition USBTMCPrivate.h:91
USBTMC_READSTB_CTRL_RESP_LENGTH
static const U16 USBTMC_READSTB_CTRL_RESP_LENGTH
Definition USBTMCPrivate.h:41
DEV_DEP_MSG_IN
static const U8 DEV_DEP_MSG_IN
Definition USBTMCPrivate.h:83
DEV_DEP_MSG_OUT
static const U8 DEV_DEP_MSG_OUT
Definition USBTMCPrivate.h:81
W8
#define W8(p, x)
Definition USBTMCPrivate.h:282
USBTMC_BULK_TRIGGER_MSG_SIZE
static const I32 USBTMC_BULK_TRIGGER_MSG_SIZE
Definition USBTMCPrivate.h:78
USB_CONTROL_ENDPOINT_NUMBER
static const U16 USB_CONTROL_ENDPOINT_NUMBER
Definition USBTMCPrivate.h:36
USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH
static const U16 USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH
Definition USBTMCPrivate.h:46
REQUEST_DEV_DEP_MSG_IN
static const U8 REQUEST_DEV_DEP_MSG_IN
Definition USBTMCPrivate.h:82
USBTMC_READSTB_INTR_RESP_LENGTH
static const U16 USBTMC_READSTB_INTR_RESP_LENGTH
Definition USBTMCPrivate.h:42
USB_MAX_PORT_DEPTH
static const I32 USB_MAX_PORT_DEPTH
Definition USBTMCPrivate.h:35
R8
#define R8(x)
Memory access macros.
Definition USBTMCPrivate.h:142
RL32
#define RL32(x)
Definition USBTMCPrivate.h:193
EOM
static const U8 EOM
Definition USBTMCPrivate.h:87
TRIGGER
static const U8 TRIGGER
Definition USBTMCPrivate.h:84
SUBCLASS_USBTMC
static const U8 SUBCLASS_USBTMC
Constants for USBTMC and USB488.
Definition USBTMCPrivate.h:13
USB_DESCRIPTOR_STRING_LENGTH
static const U32 USB_DESCRIPTOR_STRING_LENGTH
Definition USBTMCPrivate.h:37
USBTMC_STATUS_SUCCESS
@ USBTMC_STATUS_SUCCESS
Definition USBTMCPrivate.h:54
USBTMC_STATUS_INTERRUPT_IN_BUSY
@ USBTMC_STATUS_INTERRUPT_IN_BUSY
Definition USBTMCPrivate.h:56
USBTMC_STATUS_PENDING
@ USBTMC_STATUS_PENDING
Definition USBTMCPrivate.h:55
USBTMC_INITIATE_CLEAR_RESP_LENGTH
static const U16 USBTMC_INITIATE_CLEAR_RESP_LENGTH
Definition USBTMCPrivate.h:43
USBTMC_READ_BUFFER_SIZE
static const U16 USBTMC_READ_BUFFER_SIZE
Definition USBTMCPrivate.h:40
USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH
Definition USBTMCPrivate.h:47
USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH
Definition USBTMCPrivate.h:49
USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH
Definition USBTMCPrivate.h:44
USBTMC_USB488
static const U8 USBTMC_USB488
Definition USBTMCPrivate.h:14
WL32
#define WL32(p, x)
Definition USBTMCPrivate.h:315
USBTMC_BM_REQUEST_TYPE_IN_CLS_IF
static const U8 USBTMC_BM_REQUEST_TYPE_IN_CLS_IF
Definition USBTMCPrivate.h:38
USBTMC_ERROR_EXPLANATION
static const char * USBTMC_ERROR_EXPLANATION[]
Error explanations.
Definition USBTMCPrivate.h:115
USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR
@ USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR
Definition USBTMCPrivate.h:106
USBTMC_ERROR_GET_RESRC_NOT_FOUND
@ USBTMC_ERROR_GET_RESRC_NOT_FOUND
Definition USBTMCPrivate.h:99
USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT
@ USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT
Definition USBTMCPrivate.h:100
USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR
@ USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR
Definition USBTMCPrivate.h:108
USBTMC_ERROR_READSTB_CONTROL_RESPONSE_ERROR
@ USBTMC_ERROR_READSTB_CONTROL_RESPONSE_ERROR
Definition USBTMCPrivate.h:107
USBTMC_ERROR_READ_INVALID_HEADER
@ USBTMC_ERROR_READ_INVALID_HEADER
Definition USBTMCPrivate.h:102
USBTMC_ERROR_CLEAR_RESPONSE_ERROR
@ USBTMC_ERROR_CLEAR_RESPONSE_ERROR
Definition USBTMCPrivate.h:104
USBTMC_ERROR_READ_WRONG_MSG_SIZE
@ USBTMC_ERROR_READ_WRONG_MSG_SIZE
Definition USBTMCPrivate.h:103
USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR
@ USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR
Definition USBTMCPrivate.h:105
USBTMC_ERROR_FIND_RESRC_BAD_FILTER
@ USBTMC_ERROR_FIND_RESRC_BAD_FILTER
Definition USBTMCPrivate.h:97
USBTMC_ERROR_DEVICE_NOT_OPEN
@ USBTMC_ERROR_DEVICE_NOT_OPEN
Definition USBTMCPrivate.h:110
USBTMC_ERROR_SRQ_NOT_ENABLED
@ USBTMC_ERROR_SRQ_NOT_ENABLED
Definition USBTMCPrivate.h:111
USBTMC_ERROR_INSTRUMENT_LOCKED
@ USBTMC_ERROR_INSTRUMENT_LOCKED
Definition USBTMCPrivate.h:109
USBTMC_ERROR_FIND_RESRC_NO_USBTMC_USB488
@ USBTMC_ERROR_FIND_RESRC_NO_USBTMC_USB488
Definition USBTMCPrivate.h:98
USBTMC_BM_REQUEST_TYPE_IN_CLS_EP
static const U8 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP
Definition USBTMCPrivate.h:39
USBTMC_BULK_HEADER_SIZE
static const I32 USBTMC_BULK_HEADER_SIZE
Definition USBTMCPrivate.h:76
WL16
#define WL16(p, x)
Definition USBTMCPrivate.h:297
USBTMC_CHECK_CLEAR_STATUS_INTERVAL
static const U32 USBTMC_CHECK_CLEAR_STATUS_INTERVAL
Definition USBTMCPrivate.h:45
USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH
static const U16 USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH
Definition USBTMCPrivate.h:48
READ_STATUS_BYTE
@ READ_STATUS_BYTE
Definition USBTMCPrivate.h:28
INITIATE_CLEAR
@ INITIATE_CLEAR
Definition USBTMCPrivate.h:22
INITIATE_ABORT_BULK_OUT
@ INITIATE_ABORT_BULK_OUT
Definition USBTMCPrivate.h:18
CHECK_ABORT_BULK_IN_STATUS
@ CHECK_ABORT_BULK_IN_STATUS
Definition USBTMCPrivate.h:21
CHECK_CLEAR_STATUS
@ CHECK_CLEAR_STATUS
Definition USBTMCPrivate.h:23
CHECK_ABORT_BULK_OUT_STATUS
@ CHECK_ABORT_BULK_OUT_STATUS
Definition USBTMCPrivate.h:19
INITIATE_ABORT_BULK_IN
@ INITIATE_ABORT_BULK_IN
Definition USBTMCPrivate.h:20
MTL::CException
Exception to be thrown.
Definition Exception.h:17
MTL::CException::what
virtual const char * what() const noexcept
Return string describing what happened.
Definition Exception.h:34
MTL::Instrument::CIEEE488Instrument::m_Lock
CRecursiveMutex m_Lock
Lock onto the class interface.
Definition IEEE488Instrument.h:68
MTL::Instrument::CIEEE488Instrument::m_Rsrc
tResourceName m_Rsrc
Resource name of the instrument.
Definition IEEE488Instrument.h:70
MTL::Instrument::CIEEE488Instrument::m_Timeout
U32 m_Timeout
Timeout for operations.
Definition IEEE488Instrument.h:72
MTL::Instrument::CIEEE488Instrument::Status
I32 Status(void)
Definition IEEE488Instrument.h:93
MTL::Instrument::CIEEE488Instrument::m_rRrsrcMan
CIEEE488ResourceManager & m_rRrsrcMan
Reference to the associated resource manager.
Definition IEEE488Instrument.h:69
MTL::Instrument::CIEEE488Instrument::CIEEE488Instrument
CIEEE488Instrument(CIEEE488ResourceManager &rRM, tResourceName Rsrc)
Constructor.
Definition IEEE488Instrument.h:79
MTL::Instrument::CIEEE488Instrument::IEEE488_DEFAULT_TIMEOUT
static const I32 IEEE488_DEFAULT_TIMEOUT
Default timeout (ms).
Definition IEEE488Instrument.h:65
MTL::Instrument::CIEEE488Instrument::m_Status
I32 m_Status
Status of last operation.
Definition IEEE488Instrument.h:71
MTL::Instrument::CIEEE488ResourceManager::m_Lock
CMutex m_Lock
Lock onto the resource manager.
Definition IEEE488Instrument.h:25
MTL::Instrument::CIEEE488ResourceManager::Status
I32 Status(void)
Definition IEEE488Instrument.h:46
MTL::Instrument::CIEEE488ResourceManager::m_Status
I32 m_Status
Status of last operation.
Definition IEEE488Instrument.h:26
MTL::Instrument::CResourceList
List of VISA resource names.
Definition IEEE488InstrumentTypes.h:26
MTL::Instrument::CSCPIBuffer
Instrument Buffer.
Definition SCPIInstrumentBuffer.h:44
MTL::Instrument::CSCPIBuffer::resize
void resize(size_t size)
Resize the buffer.
Definition SCPIInstrumentBuffer.h:93
MTL::Instrument::CSCPIBuffer::data
MTL_INSTRUMENT_BUFFER_TYPE * data() noexcept
Return a pointer to the data.
Definition SCPIInstrumentBuffer.h:154
MTL::Instrument::CSCPIBuffer::reserve
void reserve(size_t capacity)
Allocate at least a given amount of space.
Definition SCPIInstrumentBuffer.h:83
MTL::Instrument::CSCPIBuffer::clear
void clear()
Clear by setting the buffer size to zero.
Definition SCPIInstrumentBuffer.h:74
MTL::Instrument::CSCPIBuffer::capacity
size_t capacity() const
Return the buffer capacity (allocated size).
Definition SCPIInstrumentBuffer.h:114
MTL::Instrument::CSCPIBuffer::size
size_t size() const
Return the buffer size.
Definition SCPIInstrumentBuffer.h:106
MTL::Instrument::CUSBTMCInstrument::CUSBTMCInstrument
CUSBTMCInstrument(CUSBTMCResourceManager &rRM, tResourceName Rsrc)
Constructor.
Definition USBTMCInstrument.cpp:457
MTL::Instrument::CUSBTMCInstrument::Timeout
virtual bool Timeout(void)
Last operation timed out.
Definition USBTMCInstrument.cpp:682
MTL::Instrument::CUSBTMCInstrument::Read
virtual bool Read(CSCPIBuffer &rBuf, bool Append=false)
Read from a USBTMC instrument: SCPI buffer class variant.
Definition USBTMCInstrument.cpp:796
MTL::Instrument::CUSBTMCInstrument::DiscardEvents
virtual bool DiscardEvents(void)
Discard service requests.
Definition USBTMCInstrument.cpp:1517
MTL::Instrument::CUSBTMCInstrument::IsOpen
virtual bool IsOpen(void)
Check whether a session to this instrument is open.
Definition USBTMCInstrument.cpp:659
MTL::Instrument::CUSBTMCInstrument::LockedExclusive
virtual bool LockedExclusive(void)
Check whether session is locked exclusively.
Definition USBTMCInstrument.cpp:1412
MTL::Instrument::CUSBTMCInstrument::Close
virtual void Close(void)
Close this VXI-11 instrument.
Definition USBTMCInstrument.cpp:620
MTL::Instrument::CUSBTMCInstrument::~CUSBTMCInstrument
virtual ~CUSBTMCInstrument(void)
Destructor.
Definition USBTMCInstrument.cpp:465
MTL::Instrument::CUSBTMCInstrument::WaitOnEvent
virtual bool WaitOnEvent(U32 Timeout)
Wait for a service request.
Definition USBTMCInstrument.cpp:1449
MTL::Instrument::CUSBTMCInstrument::LockExclusive
virtual bool LockExclusive(U32 Timeout)
Obtain an exclusive lock for this session.
Definition USBTMCInstrument.cpp:1358
MTL::Instrument::CUSBTMCInstrument::Unlock
virtual bool Unlock(void)
Unlock the session.
Definition USBTMCInstrument.cpp:1388
MTL::Instrument::CUSBTMCInstrument::DisableEvent
virtual bool DisableEvent(void)
Disable service requests.
Definition USBTMCInstrument.cpp:1439
MTL::Instrument::CUSBTMCInstrument::AssertTrigger
virtual bool AssertTrigger(void)
Assert a trigger.
Definition USBTMCInstrument.cpp:1295
MTL::Instrument::CUSBTMCInstrument::Clear
virtual bool Clear(void)
Clear the instrument.
Definition USBTMCInstrument.cpp:1081
MTL::Instrument::CUSBTMCInstrument::ReadSTB
virtual bool ReadSTB(U16 &rSTB)
Read status byte.
Definition USBTMCInstrument.cpp:1174
MTL::Instrument::CUSBTMCInstrument::Write
virtual bool Write(const char *Str)
Write to a USBTMC instrument: C string variant.
Definition USBTMCInstrument.cpp:767
MTL::Instrument::CUSBTMCInstrument::StatusDescription
virtual std::string StatusDescription(I32 Status)
Return description of status word.
Definition USBTMCInstrument.cpp:670
MTL::Instrument::CUSBTMCInstrument::EnableEvent
virtual bool EnableEvent(void)
Enable service requests.
Definition USBTMCInstrument.cpp:1429
MTL::Instrument::CUSBTMCInstrument::Open
virtual bool Open(void)
Open this USBTMC instrument.
Definition USBTMCInstrument.cpp:477
MTL::Instrument::CUSBTMCResourceManager
USBTMC Resource Manager class.
Definition USBTMCInstrument.h:31
MTL::Instrument::CUSBTMCResourceManager::Timeout
virtual bool Timeout(void)
Last operation timed out.
Definition USBTMCInstrument.cpp:312
MTL::Instrument::CUSBTMCResourceManager::StatusDescription
virtual std::string StatusDescription(I32 Status)
Return description of status word.
Definition USBTMCInstrument.cpp:301
MTL::Instrument::CUSBTMCResourceManager::CUSBTMCResourceManager
CUSBTMCResourceManager(void)
Constructor.
Definition USBTMCInstrument.cpp:45
MTL::Instrument::CUSBTMCResourceManager::~CUSBTMCResourceManager
virtual ~CUSBTMCResourceManager(void)
Destructor.
Definition USBTMCInstrument.cpp:51
MTL::Instrument::CUSBTMCResourceManager::FindResources
virtual bool FindResources(CResourceList &rList, std::string Filter="?*")
Find USBTMC resources.
Definition USBTMCInstrument.cpp:103
MTL::Instrument::CUSBTMCResourceManager::Initialize
virtual bool Initialize(void)
Initialize the Resource Manager.
Definition USBTMCInstrument.cpp:69
MTL::Synchronization::CLockGuard
Lock.
Definition Synchronization.h:74
tControlRecord
Definition USBTMCInstrument.cpp:379
tControlRecord::UseCount
U32 UseCount
Definition USBTMCInstrument.cpp:382
tControlRecord::~tControlRecord
~tControlRecord(void)
Definition USBTMCInstrument.cpp:385
tControlRecord::tControlRecord
tControlRecord(void)
Definition USBTMCInstrument.cpp:383
tControlRecord::Mutex
std::timed_mutex Mutex
Definition USBTMCInstrument.cpp:381
MTL::Instrument
Definition THM1176.h:74
MTL::Instrument::tResourceName
std::string tResourceName
IEEE488 resource name.
Definition IEEE488InstrumentTypes.h:22
MTL::Instrument::eEventType::Exception
@ Exception
Error condition has occured during an operation.
Definition VISAInstrumentTypes.h:69
MTL::Synchronization::CMutex
std::mutex CMutex
Mutex.
Definition Synchronization.h:16