scpi commands via c# application

Applications, development tools, FPGA, C, WEB
Post Reply
aschuetz
Posts: 34
Joined: Tue Nov 24, 2015 11:26 am

scpi commands via c# application

Post by aschuetz » Fri Sep 15, 2017 2:26 pm

Dear all,

in the past I used Python and SCPI to receive data from and control the Red Pitaya. Now I want to receive data from a C# application and I'm thinking about how to do it. When I was searching on Google I always found "VISA" https://en.wikipedia.org/wiki/Virtual_I ... chitecture which seems to be connected somehow to SCPI. I'm confused now!

As far as I understood, SCPI is a standard how to define commands. Since I used Python and SCPI I think the command will be the same with C#. But I don't know how to communicate with the device. Is it correct that VISA is the way how to get connected to a device like the Red Pitaya? What I want to do is to send the commands from my C# application via the network to my Red Pitaya to receive the data.

It would be nice if someone could help me to understand it correctly.

Thanks,
Alex

tknopp
Posts: 26
Joined: Thu Feb 09, 2017 1:13 pm

Re: scpi commands via c# application

Post by tknopp » Fri Sep 15, 2017 10:18 pm

scpi is just a set of commands that are transferred using a tcp socket. So you just have to establish a tcp connection with the red pitaya. Have a look at the Matlab examples that also use a raw tcp socket.

aschuetz
Posts: 34
Joined: Tue Nov 24, 2015 11:26 am

Re: scpi commands via c# application

Post by aschuetz » Tue Sep 19, 2017 12:20 pm

tknopp wrote:scpi is just a set of commands that are transferred using a tcp socket. So you just have to establish a tcp connection with the red pitaya. Have a look at the Matlab examples that also use a raw tcp socket.
Thanks for this idea! For me working with sockets is not easy. I tried to do it from the scratch but it was not really successful. If the scpi deamon is running on the RP it will be the server and my program will the client:

Code: Select all

const int port = 5000;
const string redpitaya = "172.31.153.79";
static TcpClient client = new TcpClient(redpitaya, port);
static NetworkStream nwStream = client.GetStream();
This is my function to send a command which seems to work (I don't know how to proof it but there is no exception that I can't reach the server.

Code: Select all

static void sendCommand(string command)
        {
            byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(command);
            Console.WriteLine("Sending : " + command);
            nwStream.Write(bytesToSend, 0, bytesToSend.Length);     
        }
But I don't know how to receive an answer. I tried the following:

Code: Select all

static void readAnswer()
        {
            nwStream.ReadTimeout = 100;
            try
            {
                client.ReceiveBufferSize = 16384;
                byte[] bytes = new byte[16384];
                nwStream.Read(bytes, 0, 16384);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex);
            }            
        }
I'm not really sure if the buffer needs this size or not. Because in the case I want to receive data from the RP or to receive the information about the triggerlevel is different.

Finally, I have some doubts about this part from the Matlab code:

Code: Select all

%% Wait for trigger
 while 1
    trig_rsp=query(tcpipObj,'ACQ:TRIG:STAT?')
    if strcmp('TD',trig_rsp(1:2))
    break
    end
end
This seems to be really important to receive data. Does it mean it is necessary to wait until the buffer is filled before I can receive data? Actually, I don't know if the sending is working or not. Furthermore, I don't know how to receive the data. :roll:

JohnnyMalaria
Posts: 28
Joined: Fri Apr 28, 2017 12:43 am

Re: scpi commands via c# application

Post by JohnnyMalaria » Tue Sep 19, 2017 8:22 pm

Does it mean it is necessary to wait until the buffer is filled before I can receive data?
No, you can monitor the position of the current write data pointer while the buffer is filling. I needed to acquire ~8sec data but I couldn't wait until the end. I wrote the following Python code that allowed me to retrieve 1sec chunks, process the data and then wait for the next 1sec chunk. It's rather long but the information is there. Even though it is Python, it still uses the same SCPI commands. If you look elsewhere in the forum, I posted a question about the final chunk not getting read but I have had no reply.

In the end, though, I gave up on the RP for my acquisition needs. I found it just far too much work to achieve the most basic functionality.

Code: Select all

# -*- coding: utf-8 -*-
"""
Created on Mon Aug  7 15:33:22 2017

@author: john

CONTINUOUS CAPTURE
"""

import redpitaya_scpi as scpi
import matplotlib.pyplot as plot
import time

def sendScpi(hostobj, text, echo = True):
    if echo:
        print(hostobj.host + ' [TX]: ' + text.upper())
    hostobj.tx_txt(text.upper())
    
def recvScpi(hostobj, echo = False):
    text = hostobj.rx_txt()
    if echo:
        print(hostobj.host + ' [RX]: ' + text)
    return text

def sendRecvScpi(hostobj, text, echo = True):
    sendScpi(hostobj, text, echo)
    return recvScpi(hostobj, echo)
    
def createScpiObject(hostip):
    scpi_retry = True
    while scpi_retry:
        scpi_retry = False
        try:
            scpiobj =  scpi.scpi(hostip)
            sendScpi(scpiobj, '*RST')
            sendRecvScpi(scpiobj, '*IDN?')
        except:
            print('scpi.scpi(' + hostip +') exception')
            scpi_retry = True
            
    return scpiobj

def configureGenerator(hostobj, channel, shape, amp, freq, phase = 0):
    source = 'SOUR' + str(channel)
    output = 'OUTPUT' + str(channel)
    sendScpi(hostobj, 'GEN:RST')
    sendScpi(hostobj, source + ':FUNC ' + shape)
    sendScpi(hostobj, source + ':VOLT ' + str(amp))
    sendScpi(hostobj, source + ':PHASE ' + str(phase))
    sendScpi(hostobj, source + ':FREQ:FIX ' + str(freq))
    sendScpi(hostobj, output + ':STATE ON')
    sendScpi(hostobj, source + ':TRIG EXT_PE')

def configureAcquire(hostobj, decim = 65536, level = 100, delay = 8192):
    sendScpi(hostobj, 'ACQ:STOP', False)
    sendScpi(hostobj, 'ACQ:DATA:UNITS RAW')
    sendScpi(hostobj, 'ACQ:DATA:FORMAT ASCII')
    sendScpi(hostobj, 'ACQ:DEC ' + str(decim), False)
    sendScpi(hostobj, 'ACQ:TRIG:LEVEL ' + str(level), False)
    sendScpi(hostobj, 'ACQ:TRIG:DLY ' + str(delay), False)
    sendScpi(hostobj, 'ACQ:START', False)

def acquireData(hostobj, decim, chunksize, chunkcount, channel = 3):
    echo = False
    count = 0
    timescale = decim / 125e6
    tpos = []
    currentchunkstart = 0
    currentchunkpos = 0
    currentchunkend = currentchunkstart + chunksize - 1
    if channel & 1:
        buff1 = []
    if channel & 2:
        buff2 = []
    while 1:
        response = sendRecvScpi(hostobj, 'ACQ:TRIG:STAT?', False)
        if response != 'TD':
            if tpos == []:
                tpos = int(sendRecvScpi(hostobj, 'ACQ:TPOS?', False))
                
            wpos = int(sendRecvScpi(hostobj, 'ACQ:WPOS?', False))
            if wpos < tpos:
                wpos = wpos + 16384
                
            currentchunkpos = wpos - tpos
            if currentchunkpos >= currentchunkend:
                print('CHUNK - ' + str(count + 1)) # + ', ' + str(tpos) + ', ' + str(currentchunkstart) + ', ' + str(currentchunkend) + ', ' + str(chunksize))
                if channel & 1:
                    buff1.append(getDataChunk(hostobj, 1, tpos, currentchunkstart, chunksize) + ',')
                if channel & 2:
                    buff2.append(getDataChunk(hostobj, 2, tpos, currentchunkstart, chunksize) + ',')
    
                currentchunkstart = currentchunkend + 1
                currentchunkend = currentchunkstart + chunksize - 1
                count = count + 1
                if count == chunkcount:
                    if channel == 1:       
                        return [buff1[:-1]]
                    if channel == 2:       
                        return [buff2[:-1]]
                    if channel == 3:       
                        return [buff1[:-1], buff2[:-1]]
                    
        else: # TD
            if channel == 1:       
                return [buff1[:-1]]
            if channel == 2:       
                return [buff2[:-1]]
            if channel == 3:       
                return [buff1[:-1], buff2[:-1]]
            
#        print(round(((int(wpos) - int(tpos)) * timescale), 1))

def getDataChunk(hostobj, channel, tpos, offset, size):
    start = (tpos + offset) & 16383
#    if start > 16384:
#        start = start - 16384
       
    maxsize = size
    
    if start + size > 16383:
        maxsize = 16383 - start
        
    scpistring = 'ACQ:SOUR' + str(channel) + ':DATA:STA:N? ' + str(start) + ',' + str(maxsize)
    sendScpi(hostobj, scpistring, False)
    buff = recvScpi(hostobj, False)
    buff = buff[1:-1]
    if maxsize != size:
        maxsize = size - maxsize
        scpistring = 'ACQ:SOUR' + str(channel) + ':DATA:STA:N? ' + str(0) + ',' + str(maxsize)
        sendScpi(hostobj, scpistring, False)
        buff = buff + ',' + recvScpi(hostobj, False)[1:-1]
        
    return buff

def showData(buff):
    buffstr = ''.join(str(e) for e in buff)
    buffstr2 = buffstr.strip('{}[]\n\r\'"').replace("  ", "").split(',')
    print(buffstr2)
    plot.plot(list(map(float, buffstr2)))
    
def main():
    channel = 2
    chunksize = 2048
    chunkcount = 16384 / chunksize
    decim = 65536
    rp = createScpiObject('192.168.2.100')
    sendScpi(rp, 'DIG:PIN:DIR OUT, DIO2_P')
    sendScpi(rp, 'DIG:PIN DIO2_P, 0')
    configureGenerator(rp, 1, 'sine', 0.01, 0.25, 0)
    configureAcquire(rp, decim, delay = 8192)
    sendScpi(rp, 'ACQ:TRIG EXT_PE', False)
    sendScpi(rp, 'DIG:PIN DIO2_P, 1')
    sendScpi(rp, 'DIG:PIN DIO2_P, 0')
#    time.sleep(0.05)
    start = time.time()
    if channel == 1:       
        buff1 = acquireData(rp, decim, chunksize, chunkcount, 1)
    if channel == 2:       
        buff2 = acquireData(rp, decim, chunksize, chunkcount, 2)
    if channel == 3:       
        [buff1, buff2] = acquireData(rp, decim, chunksize, chunkcount, 3)
    print ('Total acquisition time: ', round(time.time() - start, 2), 's')

    print ('Downloading full channel 2 data...')
    rp.tx_txt('ACQ:SOUR2:DATA?')
    buff_string = rp.rx_txt()
    buff_string = buff_string.strip('{}[]\n\r\'"').replace("  ", "").split(',')
    buff3 = list(map(float, buff_string))
    plot.plot(buff3)
    plot.xlim(0, 16383)
    plot.show()
    
#    showData(buff1) #+','+buff3)
    showData(buff2) #+','+buff4)
    plot.xlim(0, 16383)
    plot.show()
    
    
if __name__ == "__main__":
    main()

aschuetz
Posts: 34
Joined: Tue Nov 24, 2015 11:26 am

Re: scpi commands via c# application

Post by aschuetz » Wed Dec 20, 2017 10:08 am

Hi all,

I wrote a "scpi" class for the Red Pitaya to send commands and receive answers via tcp/ip. I used the Matlab code as suggested to write everything in C#. Currently, I'm working on the style of the code. I think I'll share the project later if someone is interested.

Thanks,
Alex

Ilkka
Posts: 7
Joined: Fri Nov 27, 2015 9:20 pm

Re: scpi commands via c# application

Post by Ilkka » Fri Jan 05, 2018 9:49 pm

Hi Alex,

yes.. please share your C# code with others. I made some trials 1-2 years ago by using C#.

BR,
Ilkka

Post Reply
jadalnie klasyczne ekskluzywne meble wypoczynkowe do salonu ekskluzywne meble tapicerowane ekskluzywne meble do sypialni ekskluzywne meble włoskie

Who is online

Users browsing this forum: No registered users and 21 guests