![]() | Enter Your Project for a chance to win a grand prize for the most innovative use of Arduino or a $200 shopping cart! The Birthday Special: Arduino Projects for Arduino Day! | Project14 Home |
| Monthly Themes | ||
| Monthly Theme Poll |
To celebrate Project 14's birthday, I'm going to make a programmable switch with an Arduino UNO. This post describes the firmware and SCPI api. |
SCPI Commands
The instrument supports the following commands:
| Command | Description | Example |
|---|---|---|
| *IDN? | instrument identity | *IDN? element14,Arduino SCPI Switch,1,0 |
| *RST | reset instrument. Set all switches off | *RST |
| *CLS | same as *RST | *CLS |
| :DIGITAL:SWITCH# ON|OFF | turn a switch on or off. 1 based | :DIGI:SWIT1 ON |
| :DIGITAL:SWITCH#? | get a switch' status. 1 based | :DIGITAL:SWITCH1? OFF |
Firmware
Here's a link to the GIST: https://gist.github.com/jancumps/9573730e7bac392efcdbfa24e722bf4d#file-scpiswitch-ino
I don' know what's wrong with element14's code highlighter these days, but it fails to show #includes with angle brackets.
The first two lines are:
#include <scpiparser.h>
#include <Arduino.h>
#include
#include
#define NUMBEROFCHANNELS 2
struct scpi_parser_context ctx;
scpi_error_t identify(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t reset(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t get_digital_1(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t get_digital_2(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t set_digital_1(struct scpi_parser_context* context, struct scpi_token* command);
scpi_error_t set_digital_2(struct scpi_parser_context* context, struct scpi_token* command);
bool bDigital [NUMBEROFCHANNELS] = {};
int iPins [NUMBEROFCHANNELS] = {2,3};
void setup() {
struct scpi_command* digital;
int i = 0;
Serial.begin(38400);
for (i = 0; i < NUMBEROFCHANNELS; i++) {
pinMode(iPins[i], OUTPUT);
digitalWrite(iPins[i], LOW);
}
/* First, initialise the parser. */
scpi_init(&ctx);
/*
* After initialising the parser, we set up the command tree. Ours is
*
* *IDN? -> identify
* *RST -> reset
* :DIGI
* :SWIT1 -> channel 1
* :SWIT2 -> channel 2
*/
scpi_register_command(ctx.command_tree, SCPI_CL_SAMELEVEL, "*IDN?", 5, "*IDN?", 5, identify);
scpi_register_command(ctx.command_tree, SCPI_CL_SAMELEVEL, "*RST", 4, "*RST", 4, reset);
scpi_register_command(ctx.command_tree, SCPI_CL_SAMELEVEL, "*CLS", 4, "*CLS", 4, reset);
digital = scpi_register_command(ctx.command_tree, SCPI_CL_CHILD, "DIGITAL", 7, "DIGI", 4, NULL);
scpi_register_command(digital, SCPI_CL_CHILD, "SWITCH1?", 8, "SWIT1?", 6, get_digital_1);
scpi_register_command(digital, SCPI_CL_CHILD, "SWITCH2?", 8, "SWIT2?", 6, get_digital_2);
scpi_register_command(digital, SCPI_CL_CHILD, "SWITCH1", 7, "SWIT1", 5, set_digital_1);
scpi_register_command(digital, SCPI_CL_CHILD, "SWITCH2", 7, "SWIT2", 5, set_digital_2);
}
void loop() {
char line_buffer[256];
unsigned char read_length;
while(1) {
/* Read in a line and execute it. */
read_length = Serial.readBytesUntil('\n', line_buffer, 256);
if(read_length >0)
if(line_buffer[read_length-1]=='\r') // thank you jon clift
read_length = read_length - 1; if(read_length > 0) {
scpi_execute_command(&ctx, line_buffer, read_length);
}
}
}
/*
* Respond to *IDN?
*/
scpi_error_t identify(struct scpi_parser_context* context, struct scpi_token* command) {
scpi_free_tokens(command);
Serial.println("Project14,Arduino SCPI Switch,1,0");
return SCPI_SUCCESS;
}
/*
* Respond to *RST and *CLS
*/
scpi_error_t reset(struct scpi_parser_context* context, struct scpi_token* command) {
scpi_free_tokens(command);
int i = 0;
for (i = 0; i < NUMBEROFCHANNELS; i++) {
digitalWrite(iPins[i], LOW);
bDigital[i] = 0;
}
return SCPI_SUCCESS;
}
scpi_error_t get_digital(int channel, struct scpi_parser_context* context, struct scpi_token* command) {
if (bDigital[channel] ) {
Serial.println("ON");
} else {
Serial.println("OFF");
}
scpi_free_tokens(command);
return SCPI_SUCCESS;
}
/**
* get digital 1 status
*/
scpi_error_t get_digital_1(struct scpi_parser_context* context, struct scpi_token* command) {
return get_digital(0, context, command);
}
/**
* get digital 2 status
*/
scpi_error_t get_digital_2(struct scpi_parser_context* context, struct scpi_token* command) {
return get_digital(1, context, command);
}
scpi_error_t set_digital(int channel, struct scpi_parser_context* context, struct scpi_token* command) {
struct scpi_token* args;
bool bSuccess = false;
bool bSwitch = false;
args = command;
while(args != NULL && args->type == 0) {
args = args->next;
}
if (args->length == 1) {
if (args->value[0] == '0') {
bSuccess = true;
}
if (args->value[0] == '1') {
bSuccess = true;
bSwitch = true;
}
}
if (args->length == 2) {
if ((args->value[0] == 'O') || (args->value[0] == 'o')) {
if ((args->value[1] == 'N') || (args->value[1] == 'n')) {
bSuccess = true;
bSwitch = true;
}
}
}
if (args->length == 3) {
if ((args->value[0] == 'O') || (args->value[0] == 'o')) {
if ((args->value[1] == 'F') || (args->value[1] == 'f')) {
if ((args->value[2] == 'F') || (args->value[2] == 'f')) {
bSuccess = true;
}
}
}
}
scpi_free_tokens(command);
// Serial.print("Success: ");
// Serial.print(bSuccess ? "y" : "n");
// Serial.print(" channel: ");
// Serial.print(channel);
// Serial.print(" pin ");
// Serial.print(iPins[channel]);
// Serial.print(" switch ");
// Serial.print(bSwitch ? "on" : "off");
// Serial.print("\n");
if (bSuccess) {
digitalWrite(iPins[channel], bSwitch? HIGH : LOW);
bDigital[channel] = bSwitch;
}
return bSuccess ? SCPI_SUCCESS : SCPI_COMMAND_NOT_FOUND;
}
scpi_error_t set_digital_1(struct scpi_parser_context* context, struct scpi_token* command) {
return set_digital(0, context, command);
}
scpi_error_t set_digital_2(struct scpi_parser_context* context, struct scpi_token* command) {
return set_digital(1, context, command);
}
It isn't difficult to trace the SCPI commands back to the firmware functions. Not a lot is happening here.
Please check the code. If there's a construct that you have questions about, post a comment and I'll elaborate.
If you haven't got the SCPI library installed yet, check the previous post: Arduino in Test Instrumentation - Part 1: SCPI Lib.



Top Comments