Coding Your Own Networked Test Equipment

Mark Harris
|  Created: January 18, 2024  |  Updated: February 9, 2024
Coding Your Own Networked Test Equipment


If you have ever spent time manually testing batches of components, you’ll know just how laborious and time-consuming the whole process is. Each test follows the same basic steps repeated for each item you are testing. You’ll also understand the power of using test equipment that you can program to perform these steps for you, so it’s simply the case of setting everything up and plugging everything together so you can press a button to perform a test. You can save even more time by automating the configuration of all your test equipment with one click of a computer mouse.

However, what if you want to create bespoke test equipment to add to your automated test suite? This step-by-step guide will show you how to write code that allows you to configure your networked test equipment from the comfort of your computer.

Networked automation eliminates the need to set up each piece of test equipment separately and saves time if you need to repeat the same tests in the future. The bonus is that restoring settings after any power cut or accidental equipment power off is quick and straightforward.

Introduction to SCPI

If you are unfamiliar with networking test equipment, you’ll need to know about the Standard Commands for Programmable Instruments (SCPI). Back in the day, Hewlett-Packard came up with the concept of a standard interface bus that would allow any computer with the correct interface to connect to any piece of test equipment. This HPIB standard became known as the General Purpose Interface Bus (GPIB) with its own IEEE 488 standard designation. This standardization allowed each piece of networked test equipment to respond to commands from the computer to perform functions such as output a signal or perform a measurement.

SCPI expanded the principle of standardized networking of test equipment by adding an additional layer for the IEEE-488 standard to regulate the computer commands the test equipment could understand. This approach now means that an oscilloscope made by HP will respond to the same commands as an oscilloscope made by Keysight. Before the standardization of commands, often different models produced by the same manufacturer would react to different commands. This standardization means that the test equipment control program on a computer will work with any makes and models of lab equipment, so changing a networked bench power supply, for example, to a better model will not require changes to the control program.

This standardization also means that any code written for this step-by-step guide will work in any other lab if you have the same networked test equipment types linked to a suitable computer.

Introduction to SCPI

SPCI commands are in the form of simple ASCII strings that are reasonably intuitive to read and understand. For example, sending the command “*RST” to an item of test equipment will reset it; sending the command “*WAI” will instruct it to wait.

SPCI commands can instruct the test equipment to perform an action or request information depending on its format. For example, the command “TIM:ACQT 20ms” will change an oscilloscope’s acquisition time to 20ms, while the command “TIM:ACQT?” will cause it to return its current acquisition time.

Important points to consider are that commands are not case sensitive and support abbreviated forms, so, for example, “TRIG SOUR CH1” and “Trigger source Channel1” are both valid alternatives of the same command. You can also concatenate commands, so for example, “TRIG SOUR CH1”, “TRIG LEVEL1 10” and “TRIG POL INV” can be written as “TRIG:SOUR CH1;LEVEL1 10;POL INV” as all commands apply to the same TRIG. These commands set the source channel, its level in volts, and the polarity. This example sets the channel 1 level to 10V with inverted polarity. You don’t have to specify its trigger 1 as this is assumed, but you could use “TRIG1:” to avoid ambiguity.

The Coding Project

This article’s accompanying video shows how to create your own networked test equipment that uses SCPI commands. This builds on a previous video showing how to communicate with test equipment for automation.

This exercise aims to enable custom test hardware to seamlessly fit into any existing test software that can handle SCPI commands, such as those using the LAN eXtensions for Instrumentation (LXI) or the Virtual Instrument Software Architecture (VISA). The ultimate goal is to develop a comprehensive, integrated test device by incorporating a microcontroller into the automated testing hardware.

Coding Your Own Networked Test Equipment

The Infineon XMC4700 Relax Kit development board, made for industrial applications, is at the heart of the project. The board includes a microcontroller with static and dynamic memory, clocks, power supplies, standard interfaces, and basic controls. It also includes an onboard ethernet connection with a media access control (MAC) address for networking.

A key benefit of this setup is the availability of the Digital Application Virtual Engineer (DAVE) integrated development environment that Infineon provides. DAVE is a C-based software development and code generation tool for microcontroller applications. It allows simplification of the coding process, conveniently handling most of the setup tasks so you can focus on implementing SCPI commands.

The test code we’ll create will read a button’s position and control an LED’s state. This simplistic test will offer an easy-to-understand example and provide a great starting point for further exploration of the power and benefits of automated testing.

Step-by-Step Coding Guide

Project Setup:

Coding Your Own Networked Test Equipment A Step-by-Step Guide

When using the DAVE tool for a new project, the first step is creating a new project file using the “File -> New -> DAVE Project” command sequence. This action will bring up a new window where you can select the “DAVE CE Project” option and give it an appropriate name.

Coding Your Own Networked Test Equipment A Step-by-Step Guide

You will then need to choose your target hardware; in this case, the XMC4700 Relax Kit.

Unless your project is going to be resource-constrained, it’s always good practice to use the full-featured newlib standard library rather than the nano-size option.

Coding Your Own Networked Test Equipment A Step-by-Step Guide

The next step is to set up the peripherals for the project using the “DAVE -> Add New APP” command.

Coding Your Own Networked Test Equipment A Step-by-Step Guide

The first configuration to set up is the network connection, and you do this with the “Ethernet -> ETH_LWIP” command, which adds a lightweight internet protocol (IP) stack to the project to handle this interface.

Coding Your Own Networked Test Equipment A Step-by-Step Guide

You also need to add the input/output (IO) interfaces for the test equipment, the button, and the LED indicator in this example. Both are discrete components, so you must add two “DIGITAL_IO apps” under the System command option, one for each element.


It’s good practice to rename the IO apps to identify their functions in their names to make life easier and prevent accidentally accessing the wrong app. This error can be challenging to spot when trying to debug a test program that’s behaving unexpectedly.


You must also configure the IP stack for the Ethernet connection by right-clicking on the “ETH_LWIP App” and clicking “Configure APP Instance”. You will find that the XMC4700 Relax Kit is already pre-configured, which saves time. You will need to change the static IP address on the IP settings page to match the subnet of the computer you’re using for your automated testing. Also, the user datagram protocol (UDP) is not required in this example so you can deactivate this in the protocol settings tab.


Finally, you need to provide the mapping between the APP pin settings and the microcontroller hardware using the manual pin allocation option for each component. To configure the discrete button, you right-click on the button and select the “Manual Pin Allocator” command.


You can then choose the appropriate pin number for the button on the Relax Kit from the dropdown menu, which conveniently provides labels to make this straightforward. Configuring the LED and the Ethernet connection both follow the same process. You will find that the pin allocator function simplifies this process by only allowing you to select pins with the functionality needed. The tool automatically provides all the XMC4700 Relax Kit labels to make this straightforward.

These steps complete the setup for your automated test project, and you’re now ready to write the testing code.

Project App Coding


You can generate the code for the Apps by simply clicking on the “Generate Code” button on the DAVE toolbar and then sit back and wait for the operation to complete.

Before coding in anger, a recommended step is to transfer the console from the microcontroller to the computer, providing easy `printf` access. This will allow you to format and print data to make writing and debugging code quicker and easier. You can do this by enabling “GDB Semi-Hosting” in the configuration settings. You can do this by navigating to the “Project Properties”, proceeding to “C/C++ Build”, and then selecting “Settings”.


Under “ARM-GCC, C Linker, Miscellaneous”, you will need to add “–specs=rdimon.specs” to the “Other” flags. This step incorporates the semi-hosting configuration for the linker.


You can then go to the “ARM-GCC C Compiler, Preprocessor” section and add a newly defined symbol of “XMC_DEBUG_ENABLE”. This setting ensures the redirect of the console in the debug build configuration.


You will need under project settings to uncheck the checkbox that provides “default newlib system calls” under the “ARM-GCC C Linker, General” settings. If you leave this checked, you’ll find that it interrupts the monitor handle initialization and causes the build to fail.

Next, you need to initialize monitoring, which you can do by adding “extern void initialise_monitor_handles(void);” to the beginning of your code. This function needs to be called after the DAVE_Init(); call.

Note that the spelling of “initialise” is the British English variant since the ARM base is in Cambridge, England. Using the US spelling will throw an error that can be difficult to resolve if you don’t spot the subtle spelling difference. 

Project Networking Coding

The first step in getting the Ethernet network working is to enable the Lightweight IP stack to check for new messages regularly. You can do this by adding a call to the function “sys_check_timeouts();” within your infinite while loop that runs after initialization is complete.

This function will need debugging to allow it to run on the microcontroller. You can do this by creating a new debug configuration. The recommendation is to turn off the “Set breakpoint at: main” option to allow the code to run as soon as the microcontroller starts. Selecting the debug option will load your new code into the microcontroller.


You can confirm that the code is running by bringing up a Windows console on your computer and pinging the IP address of the development board, which in this example, is the XMC4700 Relax Kit. The development board should respond to each ping, confirming that the board is operating and the network connection is working.

The Lightweight IP stack code will automatically handle the Internet Control Message Protocol (ICMP) functions. Still, you must create code to handle incoming Transmission Control Protocol (TCP) connections and data. You can do this using standard Lightweight IP stack code statements that are not microcontroller specific.

Now that you’ve completed the network connection configuration, you can set the protocol control block to listen on port 5025, which the SCPI code uses for communications. You should configure the Lightweight IP stack to delegate all new connections to a function called client_accept which you will need to extend to handle new clients. All data received will need redirection to a separate function processing that will also output a debug message to indicate receipt of a new connection.

Implementing a client_recv method will copy the received data into a buffer for processing. This function should also check for connections with no data, which indicates that the remote host has closed the connection. For this condition, the code can perform clean-up actions to remove any unwanted artifacts left by the closed connection.

Compiling the code will generate a functional build if there are no coding errors to debug.

Project IO Coding

The next step is the configuration of the “Digital IO Apps” to perform their required operations.


Right-click on each App and select the “Configure App Instance” option. The default setting for IO components is a tristate input, perfect for the button. However, for the LED, you will need to change the settings to an “Input/Output” with a strong drive and soft edge. This strong drive configuration ensures the board will produce enough drive current to illuminate the LED. The soft edge configuration refers to the pin’s edge transition speed. A soft edge eases any transitory effects on the power distribution network and reduces the risk of an adverse impact on electromagnetic compliance. Using this option for discrete output is good practice unless you need a signal with nanosecond edge rates.

Regenerating the updated code will add these new changes to the functional build. It is important to remember to always regenerate code after making any changes to a DAVE App.

Project SCPI Coding

With the configuration and initialization functions complete, the project coding can finally move in to implement the SCPI commands for testing. There is no need to implement the SCPI commands from scratch; an exceptional SCPI-Parser library by Jan Breuer is available on GitHub as the starting point.

You can take advantage of this resource by extracting the libscpi folder into your project’s Libraries folder. Then extract the scpi-def folders from “examples -> common” into your project folder. This step imports the SCPI-Parser library and provides a good starting point for implementing your project.

You will need to delete the test folder and makefile in the libscpi library within the DAVE’s integrated development environment, as these will be incompatible with the ARM-GCC library in use.


Then navigate back to the project properties window under “Build, Settings, Compiler, Directories” and add a reference to the libscpi includes folder.

You will also need to open the scpi-def.c file and add an include statement for “dave.h” to link your IO functions to the scpi-def file.

As a side note, this file includes a fantastic demo implementation of a Digital Multimeter and functions for automated testing. Unfortunately, these functions are incompatible with the ARM compiler used for this example, and so need to be removed. However, if you need to implement your own functions in the future, you can refer back to the original files for reference.

When editing the file, delete all the DMM and test functions in the command configuration block but retain the code for the TST command and all the following statements, along with the standard SCPI commands the library will handle.

You can define the identification information for the test setup in the “scpi-def.h” file, so using the SCPI *IDN command will return useful information in response to any identification request.

You can set up the SCPI commands in the project’s “main.c” file. You will need to add the SCPI context to the main function using the user_context property to pass a reference to the Lightweight IP protocol control block allowing initialization of the SCPI library. Then you need to add your functions to enable libscpi to communicate over the network connection. In this example, the following functions need to be defined:

  • The “SCPI_Write” function allows libscpi to send data over the network connection.

  • The “SCPI_Flush” function notifies the Lightweight IP stack to send any data in the buffer immediately.

  • The “SCPI_Error” function provides a means to handle SCPI errors. For this basic example, you can bypass this with a simple call to the printf function.

  • The “SCPI_Control” function is an optional feature that allows you to write to the control channel on TCP port 5026, which you will not require for this example.

  • The “SCPI_Reset function” is called in response to receiving a reset command, reverting all test instruments to their default settings. There is no connected test equipment for this basic example so you can bypass this with a simple call to the printf function.


Finally, the user_context needs to be set for the new client connection when making a connection to the Lightweight IP stack. This will allow data to pass to the SCPI library from the buffer via the client_recv function to “SCPI_Input” to be processed. You’ll need to note that this implementation will not handle multiple connections simultaneously but represents good practice network configuration.

Compiling the updated code and uploading it to the microcontroller should result in a test system that not only continues to respond to pings from a Windows Console but should also respond to SCPI commands.

Project SCPI Code Testing

This example project used a Rohde & Schwarz VISA Tester application for testing SCPI commands.


After connecting the application to the test equipment, the first test is to issue an identity (IDN?\n) request. This is a recommended first step, and the command is entirely handled by the SCPI library, ensuring that the communications are operational and you set up the library correctly. This means that resolving any issues involving tests requiring a response from a peripheral device or test equipment can assume that the communications and the library are not suspects in the debugging process.

Testing the peripherals requires adding new patterns to the `scpi_commands` array to implement the required functions. Calls to the “printf” function can be included for debugging the functionality, providing a simple method of verifying the execution of the code.


In the example, the code reads the button’s state using the “scpi_result_t IO_Btn“ function in the DAVE App previously set up for the button handler with the state sent using the “SCPI_ResultBool” response. The returned value is inverted as this button is an active low component.


The LED handler function parses the received button state parameter and sets the appropriate LED state. If no parameters exist, then no action is taken for this example. This step uses the “scpi_result_t IO_Led” function to perform its function.

With the microcontroller programmed, you can test the code using the Console tab in the DAVE tool. This will demonstrate receipt of the connection and operation of the identity request command.


You can check the button’s state by sending an SCPI query and test the functionality by observing that the returned state changes when you press the button.

You can test the LED functionality simply by sending on and off commands, observing the light’s state, and monitoring the console’s status.

With both button and LED working correctly, you have the basis of a fully functional network-connected instrument. Connection of a test automation platform or writing your test code will enable you to remotely check the state of the button and control the LED.


The article shows how using the DAVE integrated test environment with a development board will allow you to create and connect your own networked test equipment to integrate with your bench equipment and automate lab testing.

This step-by-step guide is for an elementary proof-of-concept demonstration, but following the steps and getting a working test system will equip you with everything you need to create your own test instruments.

We will use the principles we explored in this project to create a practical item of test equipment in the near future, so stay tuned for further developments.

About Author

About Author

Mark Harris is an engineer's engineer, with over 16 years of diverse experience within the electronics industry, varying from aerospace and defense contracts to small product startups, hobbies and everything in between. Before moving to the United Kingdom, Mark was employed by one of the largest research organizations in Canada; every day brought a different project or challenge involving electronics, mechanics, and software. He also publishes the most extensive open source database library of components for Altium Designer called the Celestial Database Library. Mark has an affinity for open-source hardware and software and the innovative problem-solving required for the day-to-day challenges such projects offer. Electronics are passion; watching a product go from an idea to reality and start interacting with the world is a never-ending source of enjoyment. 

You can contact Mark directly at:

Related Technical Documentation

Back to Home
Thank you, you are now subscribed to updates.