element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Test & Tools
  • Technologies
  • More
Test & Tools
Blog SCPI on a Linux Board - Part 1: Proof of Concept
  • Blog
  • Forum
  • Documents
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Test & Tools to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 27 May 2018 5:12 PM Date Created
  • Views 3310 views
  • Likes 6 likes
  • Comments 1 comment
  • debian
  • BeagleBone
  • labview
  • scpi
  • beaglebone green
  • BeagleBone Black
  • raspberry_pi_3
  • linux
Related
Recommended

SCPI on a Linux Board - Part 1: Proof of Concept

Jan Cumps
Jan Cumps
27 May 2018

I'm building a SCPI shell for Linux.

I have the basis working over TCP/IP on a Raspberry Pi and a BeagleBone.

 

image

In this post I'll show the basics: the Pi or BB listens to SCPI commands and sends replies.

I'll include the LabVIEW test bed that I used to get this working.

 

 

In this series, I'm focusing on the specifics for TCP/IP communication with a SCPI service. I will not make an instrument but this project can serve as the basis of a SCPI programmable Linux device.

 

The SCPI Server

 

A program on the Linux board will run and will perform two things:

  • Listen to SCPI commands on a TCP/IP port
  • Send SCPI replies

image

 

I've written the program in C. It uses common, fairly stable Linux libraries and uses them in shared object mode, so there's no hard dependencies on Linux version.

Because of that, it also cross-compiles and debugs straight away from the Arm DS-5 Community Edition IDE.

The program registers itself as the listener for a socket (passed as a command line parameter, then waits until traffic arrives.

 

When traffic arrives, it sends that directly to the SCPI library for parsing. This is very similar to what I had implemented for USB SCPI devices before.

When the SCPI library decides to send results, it'll use the same socket to talk back.

 

This is a partial implementation of the usual SCPI TCP/IP functionality, enough to fulfill the typical command / reply scenario.

The full implementation allows negotiation between server and client to open a pipe for continuous data exchange.

 

attribution

TCP/IP Socket code is adapted from BinaryTides Server and client example with C sockets on Linux by Silver Moon.

The SCPI library is the one I mostly use in projects here on element14, Jan Breuer's really excellent SCPI lib.

 

The main function is very straightforward. Init our SCPI library and prepare the program to act as a server side Socket listener.

 

int main(int argc, char *argv[]) {
  int c, read_size, portno;
  struct sockaddr_in server, client;
  char client_message[2000];


  signal(SIGINT, sig_handler);


  SCPI_Init(&scpi_context, scpi_commands, &scpi_interface, scpi_units_def,
  SCPI_IDN1, SCPI_IDN2, SCPI_IDN3, SCPI_IDN4, scpi_input_buffer,
      SCPI_INPUT_BUFFER_LENGTH, scpi_error_queue_data,
      SCPI_ERROR_QUEUE_SIZE);


  if (argc < 2) {
    fprintf(stderr, "ERROR, no port provided\n");
    exit(1);
  }
  portno = atoi(argv[1]);


  //Create socket
  socket_desc = socket(AF_INET, SOCK_STREAM, 0);
  if (socket_desc == -1) {
    printf("Could not create socket");
  }
  puts("Socket created");


  //Prepare the sockaddr_in structure
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = INADDR_ANY;
  server.sin_port = htons(portno);


  //Bind
  if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) {
    //print the error message
    perror("bind failed. Error");
    return 1;
  }
  puts("bind done");

 

Some of the functions called here, like signal() and SCPI_xxx(),  I'll discuss later on in this post.

But for now, you can follow the main flow. When this code has executed, our SCPI library is initialised and the server is ready to start the listen and reply cycle.

 

while (1) {


    //Listen
    listen(socket_desc, 3);


    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);


    //accept connection from an incoming client
    client_sock = accept(socket_desc, (struct sockaddr *) &client,
        (socklen_t*) &c);
    if (client_sock < 0) {
      perror("accept failed");
      return 1;
    }
    puts("Connection accepted");


    //Receive a message from client
    while ((read_size = recv(client_sock, client_message, 2000, 0)) > 0) {
      SCPI_Input(&scpi_context, client_message, strlen(client_message));
    }


    if (read_size == 0) {
      puts("Client disconnected");
      fflush(stdout);
    } else if (read_size == -1) {
      perror("recv failed");
    }
    close(client_sock);
  }

 

I'm open for advise on this code. It works but I took a very naive approach of trying until I got a working device. I'm not an expert on this matter.

 

You'll see that the main loop never writes to the socket. That's because the SCPI library uses a callback function. You have to write that function yourself.

Here's the one I wrote for the SCPI TCP/IP server:

 

size_t SCPI_Write(scpi_t * context, const char * data, size_t len) {
  (void) context;
  int n = write(client_sock, data, len);
  if (n < 0)
    error("ERROR writing to socket");
  return n;
}

 

I've also provided a handler to clean up resources when Linux ends the program.

 

void sig_handler(int signo) {
  if (signo == SIGINT) {
    shutdown(socket_desc, SHUT_RDWR);
  }
}

 

Todo: make this a deamon that can be started at the bootup of the Linux device.

I think my C code is almost ready for that. I'll have to write the instructions to register it.

When using it for a real instrument, I suggest to only put the SCPI handling in this process and run your instrument in another one.

You can use POSIX messaging or the Socket API to let the two processes work together.

 

LabVIEW Test Bed

 

The code isn't production ready yet, but good enough as a test bed. It sends the *IDN? command to the Linux device and validates the return value.

 

image

 

The IP address and port are fixed here but that's not the end state.

One thing to look at is the Read block.

 

image

 

I've added an error handling block to discard TCP/IP timeouts. I have this issue that when the reply is less than the byte count passed to the read block, it tims out.

I've tried to check the number of bytes waiting for read, and to implement the termination attribute for the VISA connection, but both constructs are flagged as unsupported at runtime.

So I've decided to overrule the timeout error.

If this gives an issue (it doesn't in the current test bed because there are further checks that validate the data), I can improve this construct.

 

The great thing is that it works.

 

related blog
SCPI on a Linux Board - Letter of Intent

SCPI on a Linux Board - Part 1: Proof of Concept

SCPI on a Linux Board - Part 2a: PiFace Digital C programming

SCPI on a Linux Board - Part 2b: PiFace Digital C++ programming
SCPI on a Linux Board - Part 3: TCP/IP Socket C++ programming
SCPI on a Linux Board - Part 4: TCP/IP SCPI and Instrument Service
SCPI on a Linux Board - Part 4b: TCP/IP SCPI and Instrument Service 100% Working
SCPI on a Linux Board - Part 4c: TCP/IP SCPI and Instrument Service - Run as a Daemon
SCPI on a Linux Board - Part 5a: LabVIEW Driver for LAB Switch: Open, Close and Switch functions
Attachments:
linux_scpi_socket.zip
scpi_driver.zip
  • Sign in to reply

Top Comments

  • genebren
    genebren over 7 years ago +1
    Another very interesting project!
  • genebren
    genebren over 7 years ago

    Another very interesting project!

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube