Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 40da7cdfbe60
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f790a73e598d
Choose a head ref
  • 2 commits
  • 5 files changed
  • 2 contributors

Commits on Jun 3, 2020

  1. Support for USBTMC.

    tomverbeure committed Jun 3, 2020
    Copy the full SHA
    03118d7 View commit details
  2. Merge pull request #134 from tomverbeure/usbtmc

    Support for USBTMC
    azonenberg authored Jun 3, 2020
    Copy the full SHA
    f790a73 View commit details
Showing with 296 additions and 0 deletions.
  1. +1 −0 scopehal/CMakeLists.txt
  2. +216 −0 scopehal/SCPITMCTransport.cpp
  3. +77 −0 scopehal/SCPITMCTransport.h
  4. +1 −0 scopehal/scopehal.cpp
  5. +1 −0 scopehal/scopehal.h
1 change: 1 addition & 0 deletions scopehal/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ set(SCOPEHAL_SOURCES
SCPISocketTransport.cpp
VICPSocketTransport.cpp
SCPILxiTransport.cpp
SCPITMCTransport.cpp
SCPIDevice.cpp

Instrument.cpp
216 changes: 216 additions & 0 deletions scopehal/SCPITMCTransport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Implementation of SCPITMCTransport
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

#include "scopehal.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

SCPITMCTransport::SCPITMCTransport(string args)
{
// TODO: add configuration options:
// - set the maximum request size of usbtmc read requests (currently 2032)
// - set timeout value (when using kernel that has usbtmc v2 version)
// - set size of staging buffer (or get rid of it entirely?)
m_devicePath = args;

// FIXME: currently not used
m_timeout = 1000;

LogDebug("Connecting to SCPI oscilloscope over USBTMC through %s\n", m_devicePath.c_str());

m_handle = open(m_devicePath.c_str(), O_RDWR);
if (m_handle <= 0)
{
LogError("Couldn't open %s\n", m_devicePath.c_str());
return;
}

// Right now, I'm using an internal staging buffer because this code has been copied from the lxi transport driver.
// It's not strictly needed...
m_staging_buf_size = 150000000;
m_staging_buf = new unsigned char[m_staging_buf_size];
if (m_staging_buf == NULL)
return;
m_data_in_staging_buf = 0;
m_data_offset = 0;
m_data_depleted = false;
}

SCPITMCTransport::~SCPITMCTransport()
{
if (IsConnected())
close(m_handle);

delete[] m_staging_buf;
}

bool SCPITMCTransport::IsConnected()
{
return (m_handle > 0);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual transport code

string SCPITMCTransport::GetTransportName()
{
return "usbtmc";
}

string SCPITMCTransport::GetConnectionString()
{
return m_devicePath;
}

bool SCPITMCTransport::SendCommand(string cmd)
{
if (!IsConnected())
return false;

LogTrace("Sending %s\n", cmd.c_str());

int result = write(m_handle, cmd.c_str(), cmd.length());

m_data_in_staging_buf = 0;
m_data_offset = 0;
m_data_depleted = false;

return (result == (int)cmd.length());
}

string SCPITMCTransport::ReadReply()
{
string ret;

if (!m_staging_buf || !IsConnected())
return ret;

//FIXME: there *has* to be a more efficient way to do this...
char tmp = ' ';
while(true)
{
if (m_data_depleted)
break;
ReadRawData(1, (unsigned char *)&tmp);
if( (tmp == '\n') || (tmp == ';') )
break;
else
ret += tmp;
}
LogTrace("Got %s\n", ret.c_str());
return ret;
}

void SCPITMCTransport::SendRawData(size_t len, const unsigned char* buf)
{
// XXX: Should this reset m_data_depleted just like SendCommmand?
write(m_handle, (const char *)buf, len);
}

void SCPITMCTransport::ReadRawData(size_t len, unsigned char* buf)
{
// Data in the staging buffer is assumed to always be a consequence of a SendCommand request.
// Since we fetch all the reply data in one go, once all this data has been fetched, we mark
// the staging buffer as depleted and don't issue a new read until a new SendCommand
// is issued.

if (!m_staging_buf || !IsConnected())
return;

if (!m_data_depleted)
{
if (m_data_in_staging_buf == 0)
{

#if 0
// This is what we'd use if we could be sure that the installed Linux kernel had
// usbtmc driver v2.
m_data_in_staging_buf = read(m_handle, (char *)m_staging_buf, m_staging_buf_size);
#else
// Split up one potentially large read into a bunch of smaller ones.
// The performance impact of this is pretty small.
const int max_bytes_per_req = 2032;
int i = 0;
int bytes_fetched, bytes_requested;

do
{
bytes_requested = (max_bytes_per_req < len) ? max_bytes_per_req : len;
bytes_fetched = read(m_handle, (char *)m_staging_buf + i, m_staging_buf_size);
i += bytes_fetched;
} while(bytes_fetched == bytes_requested);

m_data_in_staging_buf = i;
#endif

if (m_data_in_staging_buf <= 0)
m_data_in_staging_buf = 0;
m_data_offset = 0;
}

unsigned int data_left = m_data_in_staging_buf - m_data_offset;
if (data_left > 0)
{
int nr_bytes = len > data_left ? data_left : len;

memcpy(buf, m_staging_buf + m_data_offset, nr_bytes);

m_data_offset += nr_bytes;
}

if (m_data_offset == m_data_in_staging_buf)
m_data_depleted = true;
}
else
{
// When this happens, the SCPIDevice is fetching more data from device than what
// could be expected from the SendCommand that was issued.
LogDebug("ReadRawData: data depleted.\n");
}
}

bool SCPITMCTransport::IsCommandBatchingSupported()
{
return false;
}
77 changes: 77 additions & 0 deletions scopehal/SCPITMCTransport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Declaration of SCPITMCTransport
*/

#ifndef SCPITMCTransport_h
#define SCPITMCTransport_h

/**
@brief Abstraction of a transport layer for moving SCPI data between endpoints
*/
class SCPITMCTransport : public SCPITransport
{
public:
SCPITMCTransport(std::string args);
virtual ~SCPITMCTransport();

virtual std::string GetConnectionString();
static std::string GetTransportName();

virtual bool SendCommand(std::string cmd);
virtual std::string ReadReply();
virtual void ReadRawData(size_t len, unsigned char* buf);
virtual void SendRawData(size_t len, const unsigned char* buf);

virtual bool IsCommandBatchingSupported();
virtual bool IsConnected();

TRANSPORT_INITPROC(SCPITMCTransport)

std::string GetDevicePath()
{ return m_devicePath; }

protected:
std::string m_devicePath;

int m_handle;
int m_timeout;

int m_staging_buf_size;
unsigned char *m_staging_buf;
int m_data_in_staging_buf;
int m_data_offset;
bool m_data_depleted;
};

#endif
1 change: 1 addition & 0 deletions scopehal/scopehal.cpp
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@ void TransportStaticInit()

AddTransportClass(SCPISocketTransport);
AddTransportClass(SCPILxiTransport);
AddTransportClass(SCPITMCTransport);
AddTransportClass(VICPSocketTransport);
}

1 change: 1 addition & 0 deletions scopehal/scopehal.h
Original file line number Diff line number Diff line change
@@ -61,6 +61,7 @@ extern "C"
#include "SCPITransport.h"
#include "SCPISocketTransport.h"
#include "SCPILxiTransport.h"
#include "SCPITMCTransport.h"
#include "VICPSocketTransport.h"
#include "SCPIDevice.h"