diff --git a/scopehal/CMakeLists.txt b/scopehal/CMakeLists.txt index d7790cda..7326df30 100644 --- a/scopehal/CMakeLists.txt +++ b/scopehal/CMakeLists.txt @@ -4,6 +4,33 @@ # Libraries specific to scopehal library not provided by root CMakeLists +if(WIN32) + # Native Windows LXI/VXI-11 support via VISA + set(VISA_SEARCH_ROOTS "C:/Program Files/IVI Foundation/VISA") + + if(DEFINED ENV{VXIPNPPATH64}) + file(TO_CMAKE_PATH "$ENV{VXIPNPPATH64}" VISA_ENV_ROOT) + list(PREPEND VISA_SEARCH_ROOTS "${VISA_ENV_ROOT}") + endif() + + find_path(VISA_INCLUDE_DIR + NAMES visa.h + PATHS ${VISA_SEARCH_ROOTS} + PATH_SUFFIXES Win64/Include) + + find_library(VISA_LIBRARY + NAMES visa64 + PATHS ${VISA_SEARCH_ROOTS} + PATH_SUFFIXES Win64/Lib_x64/msc) + + if(VISA_INCLUDE_DIR AND VISA_LIBRARY) + message("-- Found VISA: ${VISA_LIBRARY}") + set(VISA_FOUND TRUE) + else() + message("-- VISA not found, LXI/VXI-11 instrument support will not be available.") + endif() +endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") pkg_check_modules(LXI liblxi QUIET IMPORTED_TARGET) #WORKAROUND LXI on Debian Bullseye lacks a pkgconfig file @@ -287,6 +314,16 @@ if(LXI_FOUND) ) target_compile_definitions(scopehal PUBLIC HAS_LXI) endif() +if(VISA_FOUND) + target_link_libraries(scopehal + ${VISA_LIBRARY} + ) + target_include_directories(scopehal PRIVATE + ${VISA_INCLUDE_DIR} + ) + target_compile_definitions(scopehal PUBLIC HAS_LXI HAS_VISA) +endif() + target_include_directories(scopehal PRIVATE diff --git a/scopehal/RigolOscilloscope.h b/scopehal/RigolOscilloscope.h index da7046b1..ed2c4544 100644 --- a/scopehal/RigolOscilloscope.h +++ b/scopehal/RigolOscilloscope.h @@ -163,6 +163,7 @@ class RigolOscilloscope : public virtual SCPIOscilloscope }}, {"Rigol DHO1000", { { SCPITransportType::TRANSPORT_LAN, ":5555" }, + { SCPITransportType::TRANSPORT_LXI, "" }, { SCPITransportType::TRANSPORT_USBTMC, "/dev/usbtmc" }, }}, {"Rigol DHO4000", { diff --git a/scopehal/SCPILxiTransport.cpp b/scopehal/SCPILxiTransport.cpp index 8b93140e..dae3f81c 100644 --- a/scopehal/SCPILxiTransport.cpp +++ b/scopehal/SCPILxiTransport.cpp @@ -36,10 +36,14 @@ #ifdef HAS_LXI +#ifdef HAS_VISA +#include +#else extern "C" { #include } +#endif #include "scopehal.h" @@ -52,11 +56,14 @@ bool SCPILxiTransport::m_lxi_initialized = false; SCPILxiTransport::SCPILxiTransport(const string& args) { + m_staging_buf = nullptr; +#ifndef HAS_VISA if (!m_lxi_initialized) { lxi_init(); m_lxi_initialized = true; } +#endif char hostname[128]; unsigned int port = 0; @@ -76,6 +83,14 @@ SCPILxiTransport::SCPILxiTransport(const string& args) LogDebug("Connecting to SCPI device over VXI-11 at %s:%d\n", m_hostname.c_str(), m_port); +#ifdef HAS_VISA + m_resourceManager = VI_NULL; m_device = VI_NULL; + ViStatus status = viOpenDefaultRM(&m_resourceManager); + if(status < VI_SUCCESS) { LogError("Could not open VISA resource manager\n"); return; } + string resource = "TCPIP0::" + m_hostname + "::inst0::INSTR"; + status = viOpen(m_resourceManager, (ViRsrc)resource.c_str(), VI_NULL, 5000, &m_device); + if(status < VI_SUCCESS) { LogError("Could not open VXI-11 device through VISA\n"); viClose(m_resourceManager); m_resourceManager = VI_NULL; return; } +#else string instname = "inst0"; m_device = lxi_connect(&m_hostname[0], m_port, &instname[0], m_timeout, VXI11); @@ -84,6 +99,7 @@ SCPILxiTransport::SCPILxiTransport(const string& args) LogError("Couldn't connect to VXI-11 device\n"); return; } +#endif // When you issue a lxi_receive request, you need to specify the size of the receiving buffer. // However, when the data received is larger than this buffer, liblxi simply discards this data. @@ -104,12 +120,20 @@ SCPILxiTransport::SCPILxiTransport(const string& args) SCPILxiTransport::~SCPILxiTransport() { +#ifdef HAS_VISA + if (m_device != VI_NULL) viClose(m_device); + if (m_resourceManager != VI_NULL) viClose(m_resourceManager); +#endif delete[] m_staging_buf; } bool SCPILxiTransport::IsConnected() { +#ifdef HAS_VISA + return (m_device != VI_NULL); +#else return (m_device != LXI_ERROR); +#endif } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -131,15 +155,24 @@ bool SCPILxiTransport::SendCommand(const string& cmd) { LogTrace("Sending %s\n", cmd.c_str()); +#ifdef HAS_VISA + ViUInt32 written = 0; + ViStatus status = viWrite(m_device, (ViBuf)cmd.data(), (ViUInt32)cmd.length(), &written); +#else //Need the cast when using liblxi versions prior to 63ea109 because they don't have "const" on the argument. //It doesn't actually change the inputs, so safe to cast. int result = lxi_send(m_device, const_cast(&cmd[0]), cmd.length(), m_timeout); +#endif m_data_in_staging_buf = 0; m_data_offset = 0; m_data_depleted = false; +#ifdef HAS_VISA + return (status >= VI_SUCCESS) && (written == cmd.length()); +#else return (result != LXI_ERROR); +#endif } string SCPILxiTransport::ReadReply(bool endOnSemicolon, [[maybe_unused]] function progress) @@ -169,9 +202,14 @@ void SCPILxiTransport::SendRawData(size_t len, const unsigned char* buf) { // XXX: Should this reset m_data_depleted just like SendCommmand? +#ifdef HAS_VISA + ViUInt32 written = 0; + viWrite(m_device, (ViBuf)buf, (ViUInt32)len, &written); +#else //Need the cast when using liblxi versions prior to 63ea109 because they don't have "const" on the argument. //It doesn't actually change the inputs, so safe to cast. lxi_send(m_device, const_cast(reinterpret_cast(buf)), len, m_timeout); +#endif } size_t SCPILxiTransport::ReadRawData(size_t len, unsigned char* buf, std::function /*progress*/) @@ -188,9 +226,15 @@ size_t SCPILxiTransport::ReadRawData(size_t len, unsigned char* buf, std::functi { if (m_data_in_staging_buf == 0) { +#ifdef HAS_VISA + ViUInt32 received = 0; + ViStatus status = viRead(m_device, (ViBuf)m_staging_buf, (ViUInt32)m_staging_buf_size, &received); + m_data_in_staging_buf = (status >= VI_SUCCESS) ? received : 0; +#else m_data_in_staging_buf = lxi_receive(m_device, (char *)m_staging_buf, m_staging_buf_size, m_timeout); if (m_data_in_staging_buf == LXI_ERROR) m_data_in_staging_buf = 0; +#endif m_data_offset = 0; } diff --git a/scopehal/SCPILxiTransport.h b/scopehal/SCPILxiTransport.h index 5a5bdc97..9533143c 100644 --- a/scopehal/SCPILxiTransport.h +++ b/scopehal/SCPILxiTransport.h @@ -77,7 +77,12 @@ class SCPILxiTransport : public SCPITransport std::string m_hostname; unsigned short m_port; +#ifdef HAS_VISA + unsigned long m_resourceManager; + unsigned long m_device; +#else int m_device; +#endif int m_timeout; int m_staging_buf_size;