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