Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions scopehal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions scopehal/RigolOscilloscope.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ class RigolOscilloscope : public virtual SCPIOscilloscope
}},
{"Rigol DHO1000", {
{ SCPITransportType::TRANSPORT_LAN, "<ip_address>:5555" },
{ SCPITransportType::TRANSPORT_LXI, "<ip_address>" },
{ SCPITransportType::TRANSPORT_USBTMC, "/dev/usbtmc<x>" },
}},
{"Rigol DHO4000", {
Expand Down
44 changes: 44 additions & 0 deletions scopehal/SCPILxiTransport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@

#ifdef HAS_LXI

#ifdef HAS_VISA
#include <visa.h>
#else
extern "C"
{
#include <lxi.h>
}
#endif

#include "scopehal.h"

Expand All @@ -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;
Expand All @@ -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);

Expand All @@ -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.
Expand All @@ -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
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -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<char*>(&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<void(float)> progress)
Expand Down Expand Up @@ -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<char*>(reinterpret_cast<const char*>(buf)), len, m_timeout);
#endif
}

size_t SCPILxiTransport::ReadRawData(size_t len, unsigned char* buf, std::function<void(float)> /*progress*/)
Expand All @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions scopehal/SCPILxiTransport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down