String escape sequences

master
Ondřej Hruška 9 years ago
parent 749262e574
commit 8e60e0d94a
  1. 111
      main.c
  2. 134
      scpi_parser.c
  3. 7
      scpi_parser.h

111
main.c

@ -3,13 +3,47 @@
#include <stdlib.h>
#include "scpi_parser.h"
void cmd_aIDNq_cb(const SCPI_argval_t *args);
void cmd_APPL_SIN_cb(const SCPI_argval_t *args);
void cmd_APPL_TRI_cb(const SCPI_argval_t *args);
void cmd_FREQ_cb(const SCPI_argval_t *args);
void cmd_DISP_TEXT_cb(const SCPI_argval_t *args);
void cmd_DATA_BLOB_cb(const SCPI_argval_t *args);
void cmd_DATA_BLOB_data(const uint8_t *bytes);
void cmd_aIDNq_cb(const SCPI_argval_t *args)
{
printf("cb *IDN?\n");
}
void cmd_APPL_SIN_cb(const SCPI_argval_t *args)
{
printf("cb APPLy:SINe\n");
}
void cmd_APPL_TRI_cb(const SCPI_argval_t *args)
{
printf("cb APPLy:TRIangle\n");
}
void cmd_FREQ_cb(const SCPI_argval_t *args)
{
printf("cb FREQuency %d\n", args[0].INT);
}
void cmd_DISP_TEXT_cb(const SCPI_argval_t *args)
{
printf("cb DISPlay:TEXT %s, %d\n", args[0].STRING, args[1].BOOL);
}
void cmd_DATA_BLOB_cb(const SCPI_argval_t *args)
{
printf("cb DATA:BLOB %f, <%d>\n", args[0].FLOAT, args[1].BLOB_LEN);
}
void cmd_DATA_BLOB_data(const uint8_t *bytes)
{
printf("blob item: %s\n", bytes);
}
void cmd_STQENq_cb(const SCPI_argval_t *args)
{
@ -76,73 +110,16 @@ const SCPI_command_t scpi_cmd_lang[] = {
};
void cmd_aIDNq_cb(const SCPI_argval_t *args)
{
printf("cb *IDN?\n");
}
void cmd_APPL_SIN_cb(const SCPI_argval_t *args)
{
printf("cb APPLy:SINe\n");
}
void cmd_APPL_TRI_cb(const SCPI_argval_t *args)
{
printf("cb APPLy:TRIangle\n");
}
void cmd_FREQ_cb(const SCPI_argval_t *args)
{
printf("cb FREQuency %d\n", args[0].INT);
}
void cmd_DISP_TEXT_cb(const SCPI_argval_t *args)
{
printf("cb DISPlay:TEXT %s, %d\n", args[0].STRING, args[1].BOOL);
}
void cmd_DATA_BLOB_cb(const SCPI_argval_t *args)
{
printf("cb DATA:BLOB %f, <%d>\n", args[0].FLOAT, args[1].BLOB_LEN);
}
void cmd_DATA_BLOB_data(const uint8_t *bytes)
{
printf("blob item: %s\n", bytes);
}
int main()
{
// const char *inp = "*IDN?\n";
// const char *inp = "FREQ 50\n";
//const char *inp = "DISPlay:TEXT 'banana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n";
const char *inp = "DISPlay:TEXT 'ban\\\\'ana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n";
//const char *inp = "DATA:BLOB 13.456, #216AbcdEfghIjklMnop\nFREQ 50\r\n";
const char *inp = "STAT:QUE:ENAB?;ENAB 0;ENAB?;:*IDN?\n";
// const char *inp = "DATA:BLOB 13.456, #216AbcdEfghIjklMnop\nFREQ 50\r\n";
// const char *inp = "STAT:QUE:ENAB?;ENAB \t 1;ENAB?;:*IDN?\n";
for (int i = 0; i < strlen(inp); i++) {
scpi_handle_byte(inp[i]);
}
// printf("%d\n", char_equals_ci('a','A'));
// printf("%d\n", char_equals_ci('z','z'));
// printf("%d\n", char_equals_ci('z','Z'));
// printf("%d\n", char_equals_ci('M','M'));
// printf("%d\n", char_equals_ci('M','q'));
// printf("%d\n", char_equals_ci('*','*'));
// printf("%d\n", char_equals_ci('a',' '));
// printf("%d\n", level_str_matches("A","A"));
// printf("%d\n", level_str_matches("AbCdE","ABCDE"));
// printf("%d\n", level_str_matches("*IDN?","*IDN?"));
// printf("%d\n", level_str_matches("*IDN?","*IDN"));
// printf("%d\n", level_str_matches("MEAS","MEASure"));
//printf("%d\n", level_str_matches("*FBAZ?","*FxyzBAZ?"));
}

@ -7,18 +7,16 @@
#include <stdlib.h>
typedef enum {
PARS_COMMAND,
PARS_COMMAND = 0,
// collect generic arg, terminated with comma or newline. Leading and trailing whitespace ignored.
PARS_ARG,
PARS_ARG_STR_APOS, // collect arg - string with single quotes
PARS_ARG_STR_QUOT, // collect arg - string with double quotes
PARS_ARG_BLOB_PREAMBLE,
PARS_ARG, // generic argument (bool, float...)
PARS_ARG_STRING, // collect arg - string (special treatment for quotes)
PARS_ARG_BLOB_PREAMBLE, // #nDDD
PARS_ARG_BLOB_DISCARD, // discard blob - same as BLOB_BODY, but no callback or buffering
PARS_ARG_BLOB_BODY, // blob body, callback for each group
// command with no args terminated by whitespace, discard whitespace until newline and then run callback.
// error on non-whitespace
PARS_TRAILING_WHITE,
PARS_TRAILING_WHITE_NOCB, // no callback.
PARS_DISCARD_LINE, // used after detecting error
PARS_TRAILING_WHITE, // command ready to run, waiting for end, only whitespace allowed
PARS_TRAILING_WHITE_NOCB, // discard whitespace until end of line, don't run callback on success
PARS_DISCARD_LINE, // used after detecting error - drop all chars until \n
} parser_state_t;
#define MAX_CHARBUF_LEN 256
@ -37,6 +35,9 @@ static struct {
int32_t blob_cnt; // preamble counter, if 0, was just #, must read count. Used also for blob body.
int32_t blob_len; // total blob length to read
char string_quote; // symbol used to quote string
bool string_escape; // last char was backslash, next quote is literal
// recognized complete command level strings (FUNCtion) - exact copy from command struct
char cur_levels[MAX_LEVEL_COUNT][MAX_CMD_LEN];
uint8_t cur_level_i; // next free level slot index
@ -47,18 +48,8 @@ static struct {
SCPI_argval_t args[MAX_PARAM_COUNT];
uint8_t arg_i; // next free argument slot index
} pst = {
// defaults
.err_queue_i = 0,
.state = PARS_COMMAND,
.charbuf_i = 0,
.cur_level_i = 0,
.cmdbuf_kept = false,
.matched_cmd = NULL,
.blob_cnt = 0,
.blob_len = 0,
.arg_i = 0
};
} pst; // initialized by all zeros
static void pars_cmd_colon(void); // colon starting a command sub-segment
@ -107,8 +98,7 @@ static void pars_reset_cmd(void)
pst.cmdbuf_kept = false;
pst.matched_cmd = NULL;
pst.arg_i = 0;
pst.blob_cnt = 0;
pst.blob_len = 0;
pst.string_escape = false;
}
@ -117,18 +107,16 @@ static void pars_reset_cmd_keeplevel(void)
{
pst.state = PARS_COMMAND;
pst.charbuf_i = 0;
// rewind to last colon
// rewind to last colon
if (pst.cur_level_i > 0) {
pst.cur_level_i--; // keep prev levels
}
pst.cmdbuf_kept = true;
pst.matched_cmd = NULL;
pst.arg_i = 0;
pst.blob_cnt = 0;
pst.blob_len = 0;
pst.string_escape = false;
}
@ -185,6 +173,12 @@ static void pars_run_callback(void)
}
void scpi_discard_blob(void)
{
pst.state = PARS_ARG_BLOB_DISCARD;
}
void scpi_handle_byte(const uint8_t b)
{
// TODO handle blob here
@ -277,29 +271,26 @@ void scpi_handle_byte(const uint8_t b)
}
break;
// TODO escape sequence in string
case PARS_ARG_STRING:
// string
case PARS_ARG_STR_APOS:
if (c == '\'') {
if (c == pst.string_quote && !pst.string_escape) {
// end of string
pst.state = PARS_ARG; // next will be newline or comma (or ignored spaces)
} else if (c == '\n') {
printf("ERROR string literal not terminated.\n");//TODO error
pst.state = PARS_DISCARD_LINE;
} else {
charbuf_append(c);
}
break;
case PARS_ARG_STR_QUOT:
if (c == '"') {
// end of string
pst.state = PARS_ARG; // next will be newline or comma (or ignored spaces)
} else if (c == '\n') {
printf("ERROR string literal not terminated.\n");//TODO error
pst.state = PARS_DISCARD_LINE;
} else {
charbuf_append(c);
if (pst.string_escape) {
charbuf_append(c);
pst.string_escape = false;
} else {
if (c == '\\') {
pst.string_escape = true;
} else {
charbuf_append(c);
}
}
}
break;
@ -309,6 +300,8 @@ void scpi_handle_byte(const uint8_t b)
break;
case PARS_ARG_BLOB_BODY:
// binary blob body with callback on buffer full
charbuf_append(c);
pst.blob_cnt++;
@ -324,6 +317,17 @@ void scpi_handle_byte(const uint8_t b)
pst.state = PARS_TRAILING_WHITE_NOCB; // discard trailing whitespace until newline
}
break;
case PARS_ARG_BLOB_DISCARD:
// binary blob, discard incoming data
pst.blob_cnt++;
if (pst.blob_cnt == pst.blob_len) {
pst.state = PARS_DISCARD_LINE;
}
break;
}
}
@ -557,27 +561,6 @@ static bool try_match_cmd(const SCPI_command_t *cmd, bool partial)
static void pars_arg_char(char c)
{
switch (pst.matched_cmd->params[pst.arg_i]) {
case SCPI_DT_STRING:
if (c == '\'') {
pst.state = PARS_ARG_STR_APOS;
} else if (c == '"') {
pst.state = PARS_ARG_STR_QUOT;
} else {
printf("ERROR unexpected char '%c', should be ' or \"\n", c);//TODO error
pst.state = PARS_DISCARD_LINE;
}
break;
case SCPI_DT_BLOB:
if (c == '#') {
pst.state = PARS_ARG_BLOB_PREAMBLE;
pst.blob_cnt = 0;
} else {
printf("ERROR unexpected char '%c', binary block should start with #\n", c);//TODO error
pst.state = PARS_DISCARD_LINE;
}
break;
case SCPI_DT_FLOAT:
if (!IS_FLOAT_CHAR(c)) {
printf("ERROR unexpected char '%c' in float.\n", c);//TODO error
@ -596,6 +579,27 @@ static void pars_arg_char(char c)
}
break;
case SCPI_DT_STRING:
if (c == '\'' || c == '"') {
pst.state = PARS_ARG_STRING;
pst.string_quote = c;
pst.string_escape = false;
} else {
printf("ERROR invalid string quote, or chars after string.\n");//TODO error
pst.state = PARS_DISCARD_LINE;
}
break;
case SCPI_DT_BLOB:
if (c == '#') {
pst.state = PARS_ARG_BLOB_PREAMBLE;
pst.blob_cnt = 0;
} else {
printf("ERROR unexpected char '%c', binary block should start with #\n", c);//TODO error
pst.state = PARS_DISCARD_LINE;
}
break;
default:
charbuf_append(c);
break;

@ -57,5 +57,12 @@ typedef struct {
// Zero terminated command struct array
extern const SCPI_command_t scpi_cmd_lang[];
// --------------- functions --------------------
/**
* SCPI parser entry point.
* All incoming bytes should be sent to this function.
*/
void scpi_handle_byte(const uint8_t b);

Loading…
Cancel
Save