THM1176InstrumentDriver 1.1
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
38using 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)
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)
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
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)
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.
266bool 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
323MTL::CException<CUSBTMCResourceManager> CUSBTMCResourceManager::Exception(I32 Status, std::string Location)
324{
327}
328
329//----------------------------------------------------------------------//
330// Instrument //
331//----------------------------------------------------------------------//
332// Utility functions to build write headers and check read headers and responses.
333static 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
343static 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
360static 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{
380public:
381 std::timed_mutex Mutex;
384 { }
386 { assert (0 == UseCount); }
387};
388
389static class: public std::map<libusb_device *, tControlRecord *>
390{
391private:
392 CMutex m_Lock;
393public:
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// Instrument management.
455
456// Constructors / destructors
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
466{
467 // Make sure the device is closed.
469
470 // Make sure the lock is released.
472
473} // CUSBTMCInstrument::~CUSBTMCInstrument
474
475//------------------------------------------//
476// Connection
478{
479 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
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))
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)
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)
557
558 // Get the handle to the device.
559 m_Status = libusb_open(m_pDevice, &m_hDevice);
560 if (m_Status != LIBUSB_SUCCESS)
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)
572 if (l_CurrentConfig != m_ConfigurationNo)
573 {
574 m_Status =libusb_set_configuration(m_hDevice, m_ConfigurationNo);
575 if (m_Status != LIBUSB_SUCCESS)
577 }
578
579 // Register the device with our access-control mechanism.
580 l_USBTMCAccessControl.Register(m_pDevice);
581 }
582
583 // Handle errors.
585 {
586 MTL_Unused(rE)
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
621{
622 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
624
625 // If the device is already closed, we're done.
626 if (!CUSBTMCInstrument::IsOpen()) return;
627
628 // Unlock the interface.
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
660{
661 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
663
664 return (m_pDevice != nullptr && m_hDevice != nullptr);
665
666} // CUSBTMCInstrument::IsOpen
667
668//------------------------------------------//
669// Info
671{
672 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
674
675 if (Status <= 0)
676 return libusb_error_name(Status);
677 else
679
680} // CUSBTMCInstrument::StatusDescription
681
683{
684 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
686
687 return (m_Status == LIBUSB_ERROR_TIMEOUT);
688
689} // CUSBTMCInstrument::Timeout
690
691//------------------------------------------//
692// Write
693// Low-level write.
694bool 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);
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())
706
707 // Lock the device.
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
740 }
741 if (l_Transferred != l_PaddedSize)
743 }
744
745 // Handle errors.
747 {
748 MTL_Unused(rE)
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
767bool CUSBTMCInstrument::Write(const char * Str)
768{
769 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
771
772 return USBTMCWrite(DEV_DEP_MSG_OUT, Str, std::strlen(Str), EOM);
773
774} // CUSBTMCInstrument::Write(const char * Str)
775
776bool CUSBTMCInstrument::Write(const std::string & rStr)
777{
778 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
780
781 return USBTMCWrite(DEV_DEP_MSG_OUT, rStr.c_str(), rStr.size(), EOM);
782
783} // CUSBTMCInstrument::Write(const std::string & rStr)
784
786{
787 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
789
790 return USBTMCWrite(DEV_DEP_MSG_OUT, rBuf.data(), rBuf.size(), EOM);
791
792} // CUSBTMCInstrument::Write(const CSCPIBuffer & rBuf)
793
794//------------------------------------------//
795// Read
796bool CUSBTMCInstrument::Read(CSCPIBuffer & rBuf, bool Append)
797{
798 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
800
801 bool l_InitialLockState = m_ExclusiveLock;
802 try
803 {
804 // Make sure this device is open.
805 if (!IsOpen())
807
808 // Lock the device.
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)
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);
841 }
842 } while (l_Transferred == 0);
843 if (l_Transferred < USBTMC_BULK_HEADER_SIZE)
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))
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);
882 }
883 if (l_Transferred != static_cast<I32>(l_MessagePending))
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.
893 {
894 MTL_Unused(rE)
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
912bool CUSBTMCInstrument::USBTMCClearBulkIn(U8 bTag)
913{
914 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
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.
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
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)
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)
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
977 IEEE488_DEFAULT_TIMEOUT); // timeout
978
979 if (l_ReturnValue < 0)
980 throw Exception(l_ReturnValue, MTL__LOCATION__);
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
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)
998 return false;
999 }
1000
1001 return true;
1002
1003} // CUSBTMCInstrument::USBTMCClearBulkIn
1004
1005bool 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.
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
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)
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
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
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)
1074 return false;
1075 }
1076
1077 return true;
1078
1079} // CUSBTMCInstrument::USBTMCClearBulkOut
1080
1082{
1083 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1085
1086 bool l_InitialLockState = m_ExclusiveLock;
1087 try
1088 {
1089 // Make sure this device is open.
1090 if (!IsOpen())
1092
1093 // Lock the device.
1096
1097 // Initiate the Clear.
1098 // Note: use default timeout, since user-supplied timeout may be unsuitable.
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
1108 l_ReadBuffer, // data
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)
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
1130 l_ReadBuffer, // data
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) )
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.
1157 {
1158 MTL_Unused(rE)
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
1175{
1176 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1178
1179 bool l_InitialLockState = m_ExclusiveLock;
1180 try
1181 {
1182 // Make sure this device is open.
1183 if (!IsOpen())
1185
1186 // Lock the device.
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.
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
1217 l_ReadBuffer, // data
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))
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
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)
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))
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.
1278 {
1279 MTL_Unused(rE)
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
1296{
1297 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1299
1300 bool l_InitialLockState = m_ExclusiveLock;
1301 try
1302 {
1303 // Make sure this device is open.
1304 if (!IsOpen())
1306
1307 // Lock the device.
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.
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
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
1332 }
1333 if (l_Transferred != USBTMC_BULK_TRIGGER_MSG_SIZE)
1335 }
1336
1337 // Handle errors.
1339 {
1340 MTL_Unused(rE)
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
1359{
1360 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
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 {
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
1389{
1390 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
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
1413{
1414 return m_ExclusiveLock;
1415
1416} // CUSBTMCInstrument::Locked
1417
1418
1419//------------------------------------------//
1420// Exception
1421MTL::CException<CUSBTMCInstrument> CUSBTMCInstrument::Exception(I32 Status, std::string Location)
1422{
1423 m_Status = Status;
1425}
1426
1427//------------------------------------------//
1428// Service requests
1430{
1431 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1433
1434 m_SRQEnable = true;
1435 return true;
1436
1437} // CUSBTMCInstrument::EnableEvent
1438
1440{
1441 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1443
1444 m_SRQEnable = false;
1445 return true;
1446
1447} // CUSBTMCInstrument::DisableEvent
1448
1450{
1451 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1453
1454 bool l_InitialLockState = m_ExclusiveLock;
1455 try
1456 {
1457 // Make sure this device is open.
1458 if (!IsOpen())
1460
1461 // Make sure Service Requests are enabled.
1462 if (!m_SRQEnable)
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.
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
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)
1495 }
1496 }
1497
1498 // Handle errors.
1500 {
1501 MTL_Unused(rE)
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
1518{
1519 MTL_USBTMC_INSTRUMENT_DEBUG_COUT(MTL__FUNCTION_NAME__ << std::endl);
1521
1522 bool l_InitialLockState = m_ExclusiveLock;
1523 try
1524 {
1525 // Make sure this device is open.
1526 if (!IsOpen())
1528
1529 // Make sure Service Requests are enabled.
1530 if (!m_SRQEnable)
1532
1533 // Lock the device.
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
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)
1565 }
1566 }
1567
1568 // Handle errors.
1570 {
1571 MTL_Unused(rE)
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
Collection of utility macros for error messages.
#define MTL_Unused(x)
Definition Helpers.h:47
#define MTL__LOCATION__
Definition Helpers.h:22
Platform Dependent Definitions.
unsigned char U8
Unsigned byte.
Definition OSDefines.h:29
int I32
32-bit signed integer.
Definition OSDefines.h:27
unsigned int U32
32-bit unsigned integer.
Definition OSDefines.h:31
unsigned short U16
16-bit unsigned integer.
Definition OSDefines.h:30
bool Register(libusb_device *pDevice)
static void USBTMCBulkOutHeaderWrite(U8 *pHeader, U8 MsgID, U8 bTag, U32 TransferSize, U8 bmTransferAttributes, char TermChar)
static bool USBTMCBulkInHeaderRead(U8 *pHeader, U8 MsgID, U8 bTag, I32 &TransferSize, U8 &bmTransferAttributes)
#define MTL_USBTMC_PAUSE_BETWEEN_READS
#define MTL_USBTMC_INSTRUMENT_DEBUG_COUT(__X__)
bool Release(libusb_device *pDevice)
l_USBTMCAccessControl
bool Claim(libusb_device *pDevice, U32 Timeout=0)
#define MTL_USBTMC_INSTRUMENT_DEBUG_CERR(__X__)
static bool USBTMCReadSTBResponse(U8 *pResponse, U8 USBTMC_status, U8 bTag, U8 StatusByte)
bool Unregister(libusb_device *pDevice)
USBTMC driver based on libusb: interface definition.
static const U8 BULKIN_FIFO_BYTES
static const U16 USBTMC_READSTB_CTRL_RESP_LENGTH
static const U8 DEV_DEP_MSG_IN
static const U8 DEV_DEP_MSG_OUT
#define W8(p, x)
static const I32 USBTMC_BULK_TRIGGER_MSG_SIZE
static const U16 USB_CONTROL_ENDPOINT_NUMBER
static const U16 USBTMC_INITIATE_ABORT_BULKIN_RESP_LENGTH
static const U8 REQUEST_DEV_DEP_MSG_IN
static const U16 USBTMC_READSTB_INTR_RESP_LENGTH
static const I32 USB_MAX_PORT_DEPTH
#define R8(x)
Memory access macros.
#define RL32(x)
static const U8 EOM
static const U8 TRIGGER
static const U8 SUBCLASS_USBTMC
Constants for USBTMC and USB488.
static const U32 USB_DESCRIPTOR_STRING_LENGTH
@ USBTMC_STATUS_SUCCESS
@ USBTMC_STATUS_INTERRUPT_IN_BUSY
@ USBTMC_STATUS_PENDING
static const U16 USBTMC_INITIATE_CLEAR_RESP_LENGTH
static const U16 USBTMC_READ_BUFFER_SIZE
static const U16 USBTMC_CHECK_ABORT_BULKIN_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_ABORT_BULKOUT_STATUS_RESP_LENGTH
static const U16 USBTMC_CHECK_CLEAR_STATUS_RESP_LENGTH
static const U8 USBTMC_USB488
#define WL32(p, x)
static const U8 USBTMC_BM_REQUEST_TYPE_IN_CLS_IF
static const char * USBTMC_ERROR_EXPLANATION[]
Error explanations.
@ USBTMC_ERROR_CLEAR_BULKOUT_RESPONSE_ERROR
@ USBTMC_ERROR_GET_RESRC_NOT_FOUND
@ USBTMC_ERROR_WRITE_INVALID_TRANSFER_COUNT
@ USBTMC_ERROR_READSTB_INTERRUPT_RESPONSE_ERROR
@ USBTMC_ERROR_READSTB_CONTROL_RESPONSE_ERROR
@ USBTMC_ERROR_READ_INVALID_HEADER
@ USBTMC_ERROR_CLEAR_RESPONSE_ERROR
@ USBTMC_ERROR_READ_WRONG_MSG_SIZE
@ USBTMC_ERROR_CLEAR_BULKIN_RESPONSE_ERROR
@ USBTMC_ERROR_FIND_RESRC_BAD_FILTER
@ USBTMC_ERROR_DEVICE_NOT_OPEN
@ USBTMC_ERROR_SRQ_NOT_ENABLED
@ USBTMC_ERROR_INSTRUMENT_LOCKED
@ USBTMC_ERROR_FIND_RESRC_NO_USBTMC_USB488
static const U8 USBTMC_BM_REQUEST_TYPE_IN_CLS_EP
static const I32 USBTMC_BULK_HEADER_SIZE
#define WL16(p, x)
static const U32 USBTMC_CHECK_CLEAR_STATUS_INTERVAL
static const U16 USBTMC_INITIATE_ABORT_BULKOUT_RESP_LENGTH
@ READ_STATUS_BYTE
@ INITIATE_CLEAR
@ INITIATE_ABORT_BULK_OUT
@ CHECK_ABORT_BULK_IN_STATUS
@ CHECK_CLEAR_STATUS
@ CHECK_ABORT_BULK_OUT_STATUS
@ INITIATE_ABORT_BULK_IN
Exception to be thrown.
Definition Exception.h:17
virtual const char * what() const noexcept
Return string describing what happened.
Definition Exception.h:34
CRecursiveMutex m_Lock
Lock onto the class interface.
tResourceName m_Rsrc
Resource name of the instrument.
U32 m_Timeout
Timeout for operations.
CIEEE488ResourceManager & m_rRrsrcMan
Reference to the associated resource manager.
CIEEE488Instrument(CIEEE488ResourceManager &rRM, tResourceName Rsrc)
Constructor.
static const I32 IEEE488_DEFAULT_TIMEOUT
Default timeout (ms)
I32 m_Status
Status of last operation.
CMutex m_Lock
Lock onto the resource manager.
I32 m_Status
Status of last operation.
List of VISA resource names.
void resize(size_t size)
Resize the buffer.
MTL_INSTRUMENT_BUFFER_TYPE * data() noexcept
Return a pointer to the data.
void reserve(size_t capacity)
Allocate at least a given amount of space.
void clear()
Clear by setting the buffer size to zero.
size_t capacity() const
Return the buffer capacity (allocated size).
size_t size() const
Return the buffer size.
CUSBTMCInstrument(CUSBTMCResourceManager &rRM, tResourceName Rsrc)
Constructor.
virtual bool Timeout(void)
Last operation timed out.
virtual bool Read(CSCPIBuffer &rBuf, bool Append=false)
Read from a USBTMC instrument: SCPI buffer class variant.
virtual bool DiscardEvents(void)
Discard service requests.
virtual bool IsOpen(void)
Check whether a session to this instrument is open.
virtual bool LockedExclusive(void)
Check whether session is locked exclusively.
virtual void Close(void)
Close this VXI-11 instrument.
virtual ~CUSBTMCInstrument(void)
Destructor.
virtual bool WaitOnEvent(U32 Timeout)
Wait for a service request.
virtual bool LockExclusive(U32 Timeout)
Obtain an exclusive lock for this session.
virtual bool Unlock(void)
Unlock the session.
virtual bool DisableEvent(void)
Disable service requests.
virtual bool AssertTrigger(void)
Assert a trigger.
virtual bool Clear(void)
Clear the instrument.
virtual bool ReadSTB(U16 &rSTB)
Read status byte.
virtual bool Write(const char *Str)
Write to a USBTMC instrument: C string variant.
virtual std::string StatusDescription(I32 Status)
Return description of status word.
virtual bool EnableEvent(void)
Enable service requests.
virtual bool Open(void)
Open this USBTMC instrument.
USBTMC Resource Manager class.
virtual bool Timeout(void)
Last operation timed out.
virtual std::string StatusDescription(I32 Status)
Return description of status word.
virtual ~CUSBTMCResourceManager(void)
Destructor.
virtual bool FindResources(CResourceList &rList, std::string Filter="?*")
Find USBTMC resources.
virtual bool Initialize(void)
Initialize the Resource Manager.
std::timed_mutex Mutex
std::string tResourceName
IEEE488 resource name.
@ Exception
Error condition has occured during an operation.
std::mutex CMutex
Mutex.