https://github.com/j123b567/scpi-parser

Dependents:   scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master

Committer:
dudmuck
Date:
Thu Apr 09 22:42:15 2015 +0000
Revision:
0:aad43948c45c
Child:
1:b497f235115a
SCPI library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:aad43948c45c 1 /*-
dudmuck 0:aad43948c45c 2 * Copyright (c) 2012-2013 Jan Breuer,
dudmuck 0:aad43948c45c 3 *
dudmuck 0:aad43948c45c 4 * All Rights Reserved
dudmuck 0:aad43948c45c 5 *
dudmuck 0:aad43948c45c 6 * Redistribution and use in source and binary forms, with or without
dudmuck 0:aad43948c45c 7 * modification, are permitted provided that the following conditions are
dudmuck 0:aad43948c45c 8 * met:
dudmuck 0:aad43948c45c 9 * 1. Redistributions of source code must retain the above copyright notice,
dudmuck 0:aad43948c45c 10 * this list of conditions and the following disclaimer.
dudmuck 0:aad43948c45c 11 * 2. Redistributions in binary form must reproduce the above copyright
dudmuck 0:aad43948c45c 12 * notice, this list of conditions and the following disclaimer in the
dudmuck 0:aad43948c45c 13 * documentation and/or other materials provided with the distribution.
dudmuck 0:aad43948c45c 14 *
dudmuck 0:aad43948c45c 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
dudmuck 0:aad43948c45c 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
dudmuck 0:aad43948c45c 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
dudmuck 0:aad43948c45c 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
dudmuck 0:aad43948c45c 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
dudmuck 0:aad43948c45c 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
dudmuck 0:aad43948c45c 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
dudmuck 0:aad43948c45c 22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
dudmuck 0:aad43948c45c 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
dudmuck 0:aad43948c45c 24 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
dudmuck 0:aad43948c45c 25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dudmuck 0:aad43948c45c 26 */
dudmuck 0:aad43948c45c 27
dudmuck 0:aad43948c45c 28 /**
dudmuck 0:aad43948c45c 29 * @file scpi_parser.c
dudmuck 0:aad43948c45c 30 * @date Thu Nov 15 10:58:45 UTC 2012
dudmuck 0:aad43948c45c 31 *
dudmuck 0:aad43948c45c 32 * @brief SCPI parser implementation
dudmuck 0:aad43948c45c 33 *
dudmuck 0:aad43948c45c 34 *
dudmuck 0:aad43948c45c 35 */
dudmuck 0:aad43948c45c 36
dudmuck 0:aad43948c45c 37 #include <ctype.h>
dudmuck 0:aad43948c45c 38 #include <string.h>
dudmuck 0:aad43948c45c 39
dudmuck 0:aad43948c45c 40 #include "scpi/config.h"
dudmuck 0:aad43948c45c 41 #include "scpi/parser.h"
dudmuck 0:aad43948c45c 42 #include "scpi/utils_private.h"
dudmuck 0:aad43948c45c 43 #include "scpi/error.h"
dudmuck 0:aad43948c45c 44 #include "scpi/constants.h"
dudmuck 0:aad43948c45c 45
dudmuck 0:aad43948c45c 46
dudmuck 0:aad43948c45c 47 static size_t cmdTerminatorPos(const char * cmd, size_t len);
dudmuck 0:aad43948c45c 48 static size_t cmdlineSeparatorPos(const char * cmd, size_t len);
dudmuck 0:aad43948c45c 49 static const char * cmdlineSeparator(const char * cmd, size_t len);
dudmuck 0:aad43948c45c 50 static const char * cmdlineTerminator(const char * cmd, size_t len);
dudmuck 0:aad43948c45c 51 static size_t skipCmdLine(const char * cmd, size_t len);
dudmuck 0:aad43948c45c 52
dudmuck 0:aad43948c45c 53 static void paramSkipBytes(scpi_t * context, size_t num);
dudmuck 0:aad43948c45c 54 static void paramSkipWhitespace(scpi_t * context);
dudmuck 0:aad43948c45c 55 static scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory);
dudmuck 0:aad43948c45c 56
dudmuck 0:aad43948c45c 57 /*
dudmuck 0:aad43948c45c 58 int _strnicmp(const char* s1, const char* s2, size_t len) {
dudmuck 0:aad43948c45c 59 int result = 0;
dudmuck 0:aad43948c45c 60 int i;
dudmuck 0:aad43948c45c 61
dudmuck 0:aad43948c45c 62 for (i = 0; i < len && s1[i] && s2[i]; i++) {
dudmuck 0:aad43948c45c 63 char c1 = tolower(s1[i]);
dudmuck 0:aad43948c45c 64 char c2 = tolower(s2[i]);
dudmuck 0:aad43948c45c 65 if (c1 != c2) {
dudmuck 0:aad43948c45c 66 result = (int) c1 - (int) c2;
dudmuck 0:aad43948c45c 67 break;
dudmuck 0:aad43948c45c 68 }
dudmuck 0:aad43948c45c 69 }
dudmuck 0:aad43948c45c 70
dudmuck 0:aad43948c45c 71 return result;
dudmuck 0:aad43948c45c 72 }
dudmuck 0:aad43948c45c 73 */
dudmuck 0:aad43948c45c 74
dudmuck 0:aad43948c45c 75 /**
dudmuck 0:aad43948c45c 76 * Find command termination character
dudmuck 0:aad43948c45c 77 * @param cmd - input command
dudmuck 0:aad43948c45c 78 * @param len - max search length
dudmuck 0:aad43948c45c 79 * @return position of terminator or len
dudmuck 0:aad43948c45c 80 */
dudmuck 0:aad43948c45c 81 size_t cmdTerminatorPos(const char * cmd, size_t len) {
dudmuck 0:aad43948c45c 82 const char * terminator = strnpbrk(cmd, len, "; \r\n\t");
dudmuck 0:aad43948c45c 83 if (terminator == NULL) {
dudmuck 0:aad43948c45c 84 return len;
dudmuck 0:aad43948c45c 85 } else {
dudmuck 0:aad43948c45c 86 return terminator - cmd;
dudmuck 0:aad43948c45c 87 }
dudmuck 0:aad43948c45c 88 }
dudmuck 0:aad43948c45c 89
dudmuck 0:aad43948c45c 90 /**
dudmuck 0:aad43948c45c 91 * Find command line separator
dudmuck 0:aad43948c45c 92 * @param cmd - input command
dudmuck 0:aad43948c45c 93 * @param len - max search length
dudmuck 0:aad43948c45c 94 * @return pointer to line separator or NULL
dudmuck 0:aad43948c45c 95 */
dudmuck 0:aad43948c45c 96 const char * cmdlineSeparator(const char * cmd, size_t len) {
dudmuck 0:aad43948c45c 97 return strnpbrk(cmd, len, ";\r\n");
dudmuck 0:aad43948c45c 98 }
dudmuck 0:aad43948c45c 99
dudmuck 0:aad43948c45c 100 /**
dudmuck 0:aad43948c45c 101 * Find command line terminator
dudmuck 0:aad43948c45c 102 * @param cmd - input command
dudmuck 0:aad43948c45c 103 * @param len - max search length
dudmuck 0:aad43948c45c 104 * @return pointer to command line terminator or NULL
dudmuck 0:aad43948c45c 105 */
dudmuck 0:aad43948c45c 106 const char * cmdlineTerminator(const char * cmd, size_t len) {
dudmuck 0:aad43948c45c 107 return strnpbrk(cmd, len, "\r\n");
dudmuck 0:aad43948c45c 108 }
dudmuck 0:aad43948c45c 109
dudmuck 0:aad43948c45c 110 /**
dudmuck 0:aad43948c45c 111 * Find command line separator position
dudmuck 0:aad43948c45c 112 * @param cmd - input command
dudmuck 0:aad43948c45c 113 * @param len - max search length
dudmuck 0:aad43948c45c 114 * @return position of line separator or len
dudmuck 0:aad43948c45c 115 */
dudmuck 0:aad43948c45c 116 size_t cmdlineSeparatorPos(const char * cmd, size_t len) {
dudmuck 0:aad43948c45c 117 const char * separator = cmdlineSeparator(cmd, len);
dudmuck 0:aad43948c45c 118 if (separator == NULL) {
dudmuck 0:aad43948c45c 119 return len;
dudmuck 0:aad43948c45c 120 } else {
dudmuck 0:aad43948c45c 121 return separator - cmd;
dudmuck 0:aad43948c45c 122 }
dudmuck 0:aad43948c45c 123 }
dudmuck 0:aad43948c45c 124
dudmuck 0:aad43948c45c 125 /**
dudmuck 0:aad43948c45c 126 * Find next part of command
dudmuck 0:aad43948c45c 127 * @param cmd - input command
dudmuck 0:aad43948c45c 128 * @param len - max search length
dudmuck 0:aad43948c45c 129 * @return number of characters to be skipped
dudmuck 0:aad43948c45c 130 */
dudmuck 0:aad43948c45c 131 size_t skipCmdLine(const char * cmd, size_t len) {
dudmuck 0:aad43948c45c 132 const char * separator = cmdlineSeparator(cmd, len);
dudmuck 0:aad43948c45c 133 if (separator == NULL) {
dudmuck 0:aad43948c45c 134 return len;
dudmuck 0:aad43948c45c 135 } else {
dudmuck 0:aad43948c45c 136 return separator + 1 - cmd;
dudmuck 0:aad43948c45c 137 }
dudmuck 0:aad43948c45c 138 }
dudmuck 0:aad43948c45c 139
dudmuck 0:aad43948c45c 140 /**
dudmuck 0:aad43948c45c 141 * Write data to SCPI output
dudmuck 0:aad43948c45c 142 * @param context
dudmuck 0:aad43948c45c 143 * @param data
dudmuck 0:aad43948c45c 144 * @param len - lenght of data to be written
dudmuck 0:aad43948c45c 145 * @return number of bytes written
dudmuck 0:aad43948c45c 146 */
dudmuck 0:aad43948c45c 147 static size_t writeData(scpi_t * context, const char * data, size_t len) {
dudmuck 0:aad43948c45c 148 return context->interface->write(context, data, len);
dudmuck 0:aad43948c45c 149 }
dudmuck 0:aad43948c45c 150
dudmuck 0:aad43948c45c 151 /**
dudmuck 0:aad43948c45c 152 * Flush data to SCPI output
dudmuck 0:aad43948c45c 153 * @param context
dudmuck 0:aad43948c45c 154 * @return
dudmuck 0:aad43948c45c 155 */
dudmuck 0:aad43948c45c 156 static int flushData(scpi_t * context) {
dudmuck 0:aad43948c45c 157 if (context && context->interface && context->interface->flush) {
dudmuck 0:aad43948c45c 158 return context->interface->flush(context);
dudmuck 0:aad43948c45c 159 } else {
dudmuck 0:aad43948c45c 160 return SCPI_RES_OK;
dudmuck 0:aad43948c45c 161 }
dudmuck 0:aad43948c45c 162 }
dudmuck 0:aad43948c45c 163
dudmuck 0:aad43948c45c 164 /**
dudmuck 0:aad43948c45c 165 * Write result delimiter to output
dudmuck 0:aad43948c45c 166 * @param context
dudmuck 0:aad43948c45c 167 * @return number of bytes written
dudmuck 0:aad43948c45c 168 */
dudmuck 0:aad43948c45c 169 static size_t writeDelimiter(scpi_t * context) {
dudmuck 0:aad43948c45c 170 if (context->output_count > 0) {
dudmuck 0:aad43948c45c 171 return writeData(context, ", ", 2);
dudmuck 0:aad43948c45c 172 } else {
dudmuck 0:aad43948c45c 173 return 0;
dudmuck 0:aad43948c45c 174 }
dudmuck 0:aad43948c45c 175 }
dudmuck 0:aad43948c45c 176
dudmuck 0:aad43948c45c 177 /**
dudmuck 0:aad43948c45c 178 * Conditionaly write "New Line"
dudmuck 0:aad43948c45c 179 * @param context
dudmuck 0:aad43948c45c 180 * @return number of characters written
dudmuck 0:aad43948c45c 181 */
dudmuck 0:aad43948c45c 182 static size_t writeNewLine(scpi_t * context) {
dudmuck 0:aad43948c45c 183 if (context->output_count > 0) {
dudmuck 0:aad43948c45c 184 size_t len;
dudmuck 0:aad43948c45c 185 len = writeData(context, "\r\n", 2);
dudmuck 0:aad43948c45c 186 flushData(context);
dudmuck 0:aad43948c45c 187 return len;
dudmuck 0:aad43948c45c 188 } else {
dudmuck 0:aad43948c45c 189 return 0;
dudmuck 0:aad43948c45c 190 }
dudmuck 0:aad43948c45c 191 }
dudmuck 0:aad43948c45c 192
dudmuck 0:aad43948c45c 193 /**
dudmuck 0:aad43948c45c 194 * Process command
dudmuck 0:aad43948c45c 195 * @param context
dudmuck 0:aad43948c45c 196 */
dudmuck 0:aad43948c45c 197 static void processCommand(scpi_t * context) {
dudmuck 0:aad43948c45c 198 const scpi_command_t * cmd = context->paramlist.cmd;
dudmuck 0:aad43948c45c 199
dudmuck 0:aad43948c45c 200 context->cmd_error = FALSE;
dudmuck 0:aad43948c45c 201 context->output_count = 0;
dudmuck 0:aad43948c45c 202 context->input_count = 0;
dudmuck 0:aad43948c45c 203
dudmuck 0:aad43948c45c 204 SCPI_DEBUG_COMMAND(context);
dudmuck 0:aad43948c45c 205 /* if callback exists - call command callback */
dudmuck 0:aad43948c45c 206 if (cmd->callback != NULL) {
dudmuck 0:aad43948c45c 207 if ((cmd->callback(context) != SCPI_RES_OK) && !context->cmd_error) {
dudmuck 0:aad43948c45c 208 SCPI_ErrorPush(context, SCPI_ERROR_EXECUTION_ERROR);
dudmuck 0:aad43948c45c 209 }
dudmuck 0:aad43948c45c 210 }
dudmuck 0:aad43948c45c 211
dudmuck 0:aad43948c45c 212 /* conditionaly write new line */
dudmuck 0:aad43948c45c 213 writeNewLine(context);
dudmuck 0:aad43948c45c 214
dudmuck 0:aad43948c45c 215 /* skip all whitespaces */
dudmuck 0:aad43948c45c 216 paramSkipWhitespace(context);
dudmuck 0:aad43948c45c 217
dudmuck 0:aad43948c45c 218 /* set error if command callback did not read all parameters */
dudmuck 0:aad43948c45c 219 if (context->paramlist.length != 0 && !context->cmd_error) {
dudmuck 0:aad43948c45c 220 SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED);
dudmuck 0:aad43948c45c 221 }
dudmuck 0:aad43948c45c 222 }
dudmuck 0:aad43948c45c 223
dudmuck 0:aad43948c45c 224 /**
dudmuck 0:aad43948c45c 225 * Cycle all patterns and search matching pattern. Execute command callback.
dudmuck 0:aad43948c45c 226 * @param context
dudmuck 0:aad43948c45c 227 * @result TRUE if context->paramlist is filled with correct values
dudmuck 0:aad43948c45c 228 */
dudmuck 0:aad43948c45c 229 static scpi_bool_t findCommand(scpi_t * context, const char * cmdline_ptr, size_t cmdline_len, size_t cmd_len) {
dudmuck 0:aad43948c45c 230 int32_t i;
dudmuck 0:aad43948c45c 231 const scpi_command_t * cmd;
dudmuck 0:aad43948c45c 232
dudmuck 0:aad43948c45c 233 for (i = 0; context->cmdlist[i].pattern != NULL; i++) {
dudmuck 0:aad43948c45c 234 cmd = &context->cmdlist[i];
dudmuck 0:aad43948c45c 235 if (matchCommand(cmd->pattern, cmdline_ptr, cmd_len)) {
dudmuck 0:aad43948c45c 236 context->paramlist.cmd = cmd;
dudmuck 0:aad43948c45c 237 context->paramlist.parameters = cmdline_ptr + cmd_len;
dudmuck 0:aad43948c45c 238 context->paramlist.length = cmdline_len - cmd_len;
dudmuck 0:aad43948c45c 239 context->paramlist.cmd_raw.data = cmdline_ptr;
dudmuck 0:aad43948c45c 240 context->paramlist.cmd_raw.length = cmd_len;
dudmuck 0:aad43948c45c 241 context->paramlist.cmd_raw.position = 0;
dudmuck 0:aad43948c45c 242 return TRUE;
dudmuck 0:aad43948c45c 243 }
dudmuck 0:aad43948c45c 244 }
dudmuck 0:aad43948c45c 245 return FALSE;
dudmuck 0:aad43948c45c 246 }
dudmuck 0:aad43948c45c 247
dudmuck 0:aad43948c45c 248 /**
dudmuck 0:aad43948c45c 249 * Parse one command line
dudmuck 0:aad43948c45c 250 * @param context
dudmuck 0:aad43948c45c 251 * @param data - complete command line
dudmuck 0:aad43948c45c 252 * @param len - command line length
dudmuck 0:aad43948c45c 253 * @return 1 if the last evaluated command was found
dudmuck 0:aad43948c45c 254 */
dudmuck 0:aad43948c45c 255 int SCPI_Parse(scpi_t * context, char * data, size_t len) {
dudmuck 0:aad43948c45c 256 int result = 0;
dudmuck 0:aad43948c45c 257 const char * cmdline_end = data + len;
dudmuck 0:aad43948c45c 258 char * cmdline_ptr = data;
dudmuck 0:aad43948c45c 259 size_t cmd_len;
dudmuck 0:aad43948c45c 260 size_t cmdline_len;
dudmuck 0:aad43948c45c 261 char * cmdline_ptr_prev = NULL;
dudmuck 0:aad43948c45c 262 size_t cmd_len_prev = 0;
dudmuck 0:aad43948c45c 263
dudmuck 0:aad43948c45c 264 if (context == NULL) {
dudmuck 0:aad43948c45c 265 return -1;
dudmuck 0:aad43948c45c 266 }
dudmuck 0:aad43948c45c 267
dudmuck 0:aad43948c45c 268 while (cmdline_ptr < cmdline_end) {
dudmuck 0:aad43948c45c 269 result = 0;
dudmuck 0:aad43948c45c 270 cmd_len = cmdTerminatorPos(cmdline_ptr, cmdline_end - cmdline_ptr);
dudmuck 0:aad43948c45c 271 if (cmd_len > 0) {
dudmuck 0:aad43948c45c 272 composeCompoundCommand(cmdline_ptr_prev, cmd_len_prev,
dudmuck 0:aad43948c45c 273 &cmdline_ptr, &cmd_len);
dudmuck 0:aad43948c45c 274 cmdline_len = cmdlineSeparatorPos(cmdline_ptr, cmdline_end - cmdline_ptr);
dudmuck 0:aad43948c45c 275 if(findCommand(context, cmdline_ptr, cmdline_len, cmd_len)) {
dudmuck 0:aad43948c45c 276 processCommand(context);
dudmuck 0:aad43948c45c 277 result = 1;
dudmuck 0:aad43948c45c 278 cmdline_ptr_prev = cmdline_ptr;
dudmuck 0:aad43948c45c 279 cmd_len_prev = cmd_len;
dudmuck 0:aad43948c45c 280 } else {
dudmuck 0:aad43948c45c 281 SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER);
dudmuck 0:aad43948c45c 282 }
dudmuck 0:aad43948c45c 283 }
dudmuck 0:aad43948c45c 284 cmdline_ptr += skipCmdLine(cmdline_ptr, cmdline_end - cmdline_ptr);
dudmuck 0:aad43948c45c 285 cmdline_ptr += skipWhitespace(cmdline_ptr, cmdline_end - cmdline_ptr);
dudmuck 0:aad43948c45c 286 }
dudmuck 0:aad43948c45c 287 return result;
dudmuck 0:aad43948c45c 288 }
dudmuck 0:aad43948c45c 289
dudmuck 0:aad43948c45c 290 /**
dudmuck 0:aad43948c45c 291 * Initialize SCPI context structure
dudmuck 0:aad43948c45c 292 * @param context
dudmuck 0:aad43948c45c 293 * @param command_list
dudmuck 0:aad43948c45c 294 * @param buffer
dudmuck 0:aad43948c45c 295 * @param interface
dudmuck 0:aad43948c45c 296 */
dudmuck 0:aad43948c45c 297 void SCPI_Init(scpi_t * context) {
dudmuck 0:aad43948c45c 298 if (context->idn[0] == NULL) {
dudmuck 0:aad43948c45c 299 context->idn[0] = SCPI_DEFAULT_1_MANUFACTURE;
dudmuck 0:aad43948c45c 300 }
dudmuck 0:aad43948c45c 301 if (context->idn[1] == NULL) {
dudmuck 0:aad43948c45c 302 context->idn[1] = SCPI_DEFAULT_2_MODEL;
dudmuck 0:aad43948c45c 303 }
dudmuck 0:aad43948c45c 304 if (context->idn[2] == NULL) {
dudmuck 0:aad43948c45c 305 context->idn[2] = SCPI_DEFAULT_3;
dudmuck 0:aad43948c45c 306 }
dudmuck 0:aad43948c45c 307 if (context->idn[3] == NULL) {
dudmuck 0:aad43948c45c 308 context->idn[3] = SCPI_DEFAULT_4_REVISION;
dudmuck 0:aad43948c45c 309 }
dudmuck 0:aad43948c45c 310
dudmuck 0:aad43948c45c 311 context->buffer.position = 0;
dudmuck 0:aad43948c45c 312 SCPI_ErrorInit(context);
dudmuck 0:aad43948c45c 313 }
dudmuck 0:aad43948c45c 314
dudmuck 0:aad43948c45c 315 /**
dudmuck 0:aad43948c45c 316 * Interface to the application. Adds data to system buffer and try to search
dudmuck 0:aad43948c45c 317 * command line termination. If the termination is found or if len=0, command
dudmuck 0:aad43948c45c 318 * parser is called.
dudmuck 0:aad43948c45c 319 *
dudmuck 0:aad43948c45c 320 * @param context
dudmuck 0:aad43948c45c 321 * @param data - data to process
dudmuck 0:aad43948c45c 322 * @param len - length of data
dudmuck 0:aad43948c45c 323 * @return
dudmuck 0:aad43948c45c 324 */
dudmuck 0:aad43948c45c 325 int SCPI_Input(scpi_t * context, const char * data, size_t len) {
dudmuck 0:aad43948c45c 326 int result = 0;
dudmuck 0:aad43948c45c 327 const char * cmd_term;
dudmuck 0:aad43948c45c 328 if (len == 0) {
dudmuck 0:aad43948c45c 329 context->buffer.data[context->buffer.position] = 0;
dudmuck 0:aad43948c45c 330 result = SCPI_Parse(context, context->buffer.data, context->buffer.position);
dudmuck 0:aad43948c45c 331 context->buffer.position = 0;
dudmuck 0:aad43948c45c 332 } else {
dudmuck 0:aad43948c45c 333 size_t buffer_free;
dudmuck 0:aad43948c45c 334 int ws;
dudmuck 0:aad43948c45c 335 buffer_free = context->buffer.length - context->buffer.position;
dudmuck 0:aad43948c45c 336 if (len > (buffer_free - 1)) {
dudmuck 0:aad43948c45c 337 return -1;
dudmuck 0:aad43948c45c 338 }
dudmuck 0:aad43948c45c 339 memcpy(&context->buffer.data[context->buffer.position], data, len);
dudmuck 0:aad43948c45c 340 context->buffer.position += len;
dudmuck 0:aad43948c45c 341 context->buffer.data[context->buffer.position] = 0;
dudmuck 0:aad43948c45c 342
dudmuck 0:aad43948c45c 343 ws = skipWhitespace(context->buffer.data, context->buffer.position);
dudmuck 0:aad43948c45c 344 cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws);
dudmuck 0:aad43948c45c 345 while (cmd_term != NULL) {
dudmuck 0:aad43948c45c 346 int curr_len = cmd_term - context->buffer.data;
dudmuck 0:aad43948c45c 347 result = SCPI_Parse(context, context->buffer.data + ws, curr_len - ws);
dudmuck 0:aad43948c45c 348 memmove(context->buffer.data, cmd_term, context->buffer.position - curr_len);
dudmuck 0:aad43948c45c 349 context->buffer.position -= curr_len;
dudmuck 0:aad43948c45c 350
dudmuck 0:aad43948c45c 351 ws = skipWhitespace(context->buffer.data, context->buffer.position);
dudmuck 0:aad43948c45c 352 cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws);
dudmuck 0:aad43948c45c 353 }
dudmuck 0:aad43948c45c 354 }
dudmuck 0:aad43948c45c 355
dudmuck 0:aad43948c45c 356 return result;
dudmuck 0:aad43948c45c 357 }
dudmuck 0:aad43948c45c 358
dudmuck 0:aad43948c45c 359 /* writing results */
dudmuck 0:aad43948c45c 360
dudmuck 0:aad43948c45c 361 /**
dudmuck 0:aad43948c45c 362 * Write raw string result to the output
dudmuck 0:aad43948c45c 363 * @param context
dudmuck 0:aad43948c45c 364 * @param data
dudmuck 0:aad43948c45c 365 * @return
dudmuck 0:aad43948c45c 366 */
dudmuck 0:aad43948c45c 367 size_t SCPI_ResultString(scpi_t * context, const char * data) {
dudmuck 0:aad43948c45c 368 size_t len = strlen(data);
dudmuck 0:aad43948c45c 369 size_t result = 0;
dudmuck 0:aad43948c45c 370 result += writeDelimiter(context);
dudmuck 0:aad43948c45c 371 result += writeData(context, data, len);
dudmuck 0:aad43948c45c 372 context->output_count++;
dudmuck 0:aad43948c45c 373 return result;
dudmuck 0:aad43948c45c 374 }
dudmuck 0:aad43948c45c 375
dudmuck 0:aad43948c45c 376 /**
dudmuck 0:aad43948c45c 377 * Write integer value to the result
dudmuck 0:aad43948c45c 378 * @param context
dudmuck 0:aad43948c45c 379 * @param val
dudmuck 0:aad43948c45c 380 * @return
dudmuck 0:aad43948c45c 381 */
dudmuck 0:aad43948c45c 382 size_t SCPI_ResultInt(scpi_t * context, int32_t val) {
dudmuck 0:aad43948c45c 383 char buffer[12];
dudmuck 0:aad43948c45c 384 size_t result = 0;
dudmuck 0:aad43948c45c 385 size_t len = longToStr(val, buffer, sizeof (buffer));
dudmuck 0:aad43948c45c 386 result += writeDelimiter(context);
dudmuck 0:aad43948c45c 387 result += writeData(context, buffer, len);
dudmuck 0:aad43948c45c 388 context->output_count++;
dudmuck 0:aad43948c45c 389 return result;
dudmuck 0:aad43948c45c 390 }
dudmuck 0:aad43948c45c 391
dudmuck 0:aad43948c45c 392 /**
dudmuck 0:aad43948c45c 393 * Write boolean value to the result
dudmuck 0:aad43948c45c 394 * @param context
dudmuck 0:aad43948c45c 395 * @param val
dudmuck 0:aad43948c45c 396 * @return
dudmuck 0:aad43948c45c 397 */
dudmuck 0:aad43948c45c 398 size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) {
dudmuck 0:aad43948c45c 399 return SCPI_ResultInt(context, val ? 1 : 0);
dudmuck 0:aad43948c45c 400 }
dudmuck 0:aad43948c45c 401
dudmuck 0:aad43948c45c 402 /**
dudmuck 0:aad43948c45c 403 * Write double walue to the result
dudmuck 0:aad43948c45c 404 * @param context
dudmuck 0:aad43948c45c 405 * @param val
dudmuck 0:aad43948c45c 406 * @return
dudmuck 0:aad43948c45c 407 */
dudmuck 0:aad43948c45c 408 size_t SCPI_ResultDouble(scpi_t * context, double val) {
dudmuck 0:aad43948c45c 409 char buffer[32];
dudmuck 0:aad43948c45c 410 size_t result = 0;
dudmuck 0:aad43948c45c 411 size_t len = doubleToStr(val, buffer, sizeof (buffer));
dudmuck 0:aad43948c45c 412 result += writeDelimiter(context);
dudmuck 0:aad43948c45c 413 result += writeData(context, buffer, len);
dudmuck 0:aad43948c45c 414 context->output_count++;
dudmuck 0:aad43948c45c 415 return result;
dudmuck 0:aad43948c45c 416
dudmuck 0:aad43948c45c 417 }
dudmuck 0:aad43948c45c 418
dudmuck 0:aad43948c45c 419 /**
dudmuck 0:aad43948c45c 420 * Write string withn " to the result
dudmuck 0:aad43948c45c 421 * @param context
dudmuck 0:aad43948c45c 422 * @param data
dudmuck 0:aad43948c45c 423 * @return
dudmuck 0:aad43948c45c 424 */
dudmuck 0:aad43948c45c 425 size_t SCPI_ResultText(scpi_t * context, const char * data) {
dudmuck 0:aad43948c45c 426 size_t result = 0;
dudmuck 0:aad43948c45c 427 result += writeDelimiter(context);
dudmuck 0:aad43948c45c 428 result += writeData(context, "\"", 1);
dudmuck 0:aad43948c45c 429 result += writeData(context, data, strlen(data));
dudmuck 0:aad43948c45c 430 result += writeData(context, "\"", 1);
dudmuck 0:aad43948c45c 431 context->output_count++;
dudmuck 0:aad43948c45c 432 return result;
dudmuck 0:aad43948c45c 433 }
dudmuck 0:aad43948c45c 434
dudmuck 0:aad43948c45c 435 /* parsing parameters */
dudmuck 0:aad43948c45c 436
dudmuck 0:aad43948c45c 437 /**
dudmuck 0:aad43948c45c 438 * Skip num bytes from the begginig of parameters
dudmuck 0:aad43948c45c 439 * @param context
dudmuck 0:aad43948c45c 440 * @param num
dudmuck 0:aad43948c45c 441 */
dudmuck 0:aad43948c45c 442 void paramSkipBytes(scpi_t * context, size_t num) {
dudmuck 0:aad43948c45c 443 if (context->paramlist.length < num) {
dudmuck 0:aad43948c45c 444 num = context->paramlist.length;
dudmuck 0:aad43948c45c 445 }
dudmuck 0:aad43948c45c 446 context->paramlist.parameters += num;
dudmuck 0:aad43948c45c 447 context->paramlist.length -= num;
dudmuck 0:aad43948c45c 448 }
dudmuck 0:aad43948c45c 449
dudmuck 0:aad43948c45c 450 /**
dudmuck 0:aad43948c45c 451 * Skip white spaces from the beggining of parameters
dudmuck 0:aad43948c45c 452 * @param context
dudmuck 0:aad43948c45c 453 */
dudmuck 0:aad43948c45c 454 void paramSkipWhitespace(scpi_t * context) {
dudmuck 0:aad43948c45c 455 size_t ws = skipWhitespace(context->paramlist.parameters, context->paramlist.length);
dudmuck 0:aad43948c45c 456 paramSkipBytes(context, ws);
dudmuck 0:aad43948c45c 457 }
dudmuck 0:aad43948c45c 458
dudmuck 0:aad43948c45c 459 /**
dudmuck 0:aad43948c45c 460 * Find next parameter
dudmuck 0:aad43948c45c 461 * @param context
dudmuck 0:aad43948c45c 462 * @param mandatory
dudmuck 0:aad43948c45c 463 * @return
dudmuck 0:aad43948c45c 464 */
dudmuck 0:aad43948c45c 465 scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 466 paramSkipWhitespace(context);
dudmuck 0:aad43948c45c 467 if (context->paramlist.length == 0) {
dudmuck 0:aad43948c45c 468 if (mandatory) {
dudmuck 0:aad43948c45c 469 SCPI_ErrorPush(context, SCPI_ERROR_MISSING_PARAMETER);
dudmuck 0:aad43948c45c 470 }
dudmuck 0:aad43948c45c 471 return FALSE;
dudmuck 0:aad43948c45c 472 }
dudmuck 0:aad43948c45c 473 if (context->input_count != 0) {
dudmuck 0:aad43948c45c 474 if (context->paramlist.parameters[0] == ',') {
dudmuck 0:aad43948c45c 475 paramSkipBytes(context, 1);
dudmuck 0:aad43948c45c 476 paramSkipWhitespace(context);
dudmuck 0:aad43948c45c 477 } else {
dudmuck 0:aad43948c45c 478 SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR);
dudmuck 0:aad43948c45c 479 return FALSE;
dudmuck 0:aad43948c45c 480 }
dudmuck 0:aad43948c45c 481 }
dudmuck 0:aad43948c45c 482 context->input_count++;
dudmuck 0:aad43948c45c 483 return TRUE;
dudmuck 0:aad43948c45c 484 }
dudmuck 0:aad43948c45c 485
dudmuck 0:aad43948c45c 486 /**
dudmuck 0:aad43948c45c 487 * Parse integer parameter
dudmuck 0:aad43948c45c 488 * @param context
dudmuck 0:aad43948c45c 489 * @param value
dudmuck 0:aad43948c45c 490 * @param mandatory
dudmuck 0:aad43948c45c 491 * @return
dudmuck 0:aad43948c45c 492 */
dudmuck 0:aad43948c45c 493 scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 494 const char * param;
dudmuck 0:aad43948c45c 495 size_t param_len;
dudmuck 0:aad43948c45c 496 size_t num_len;
dudmuck 0:aad43948c45c 497
dudmuck 0:aad43948c45c 498 if (!value) {
dudmuck 0:aad43948c45c 499 return FALSE;
dudmuck 0:aad43948c45c 500 }
dudmuck 0:aad43948c45c 501
dudmuck 0:aad43948c45c 502 if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
dudmuck 0:aad43948c45c 503 return FALSE;
dudmuck 0:aad43948c45c 504 }
dudmuck 0:aad43948c45c 505
dudmuck 0:aad43948c45c 506 num_len = strToLong(param, value);
dudmuck 0:aad43948c45c 507
dudmuck 0:aad43948c45c 508 if (num_len != param_len) {
dudmuck 0:aad43948c45c 509 SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
dudmuck 0:aad43948c45c 510 return FALSE;
dudmuck 0:aad43948c45c 511 }
dudmuck 0:aad43948c45c 512
dudmuck 0:aad43948c45c 513 return TRUE;
dudmuck 0:aad43948c45c 514 }
dudmuck 0:aad43948c45c 515
dudmuck 0:aad43948c45c 516 /**
dudmuck 0:aad43948c45c 517 * Parse double parameter
dudmuck 0:aad43948c45c 518 * @param context
dudmuck 0:aad43948c45c 519 * @param value
dudmuck 0:aad43948c45c 520 * @param mandatory
dudmuck 0:aad43948c45c 521 * @return
dudmuck 0:aad43948c45c 522 */
dudmuck 0:aad43948c45c 523 scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 524 const char * param;
dudmuck 0:aad43948c45c 525 size_t param_len;
dudmuck 0:aad43948c45c 526 size_t num_len;
dudmuck 0:aad43948c45c 527
dudmuck 0:aad43948c45c 528 if (!value) {
dudmuck 0:aad43948c45c 529 return FALSE;
dudmuck 0:aad43948c45c 530 }
dudmuck 0:aad43948c45c 531
dudmuck 0:aad43948c45c 532 if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
dudmuck 0:aad43948c45c 533 return FALSE;
dudmuck 0:aad43948c45c 534 }
dudmuck 0:aad43948c45c 535
dudmuck 0:aad43948c45c 536 num_len = strToDouble(param, value);
dudmuck 0:aad43948c45c 537
dudmuck 0:aad43948c45c 538 if (num_len != param_len) {
dudmuck 0:aad43948c45c 539 SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
dudmuck 0:aad43948c45c 540 return FALSE;
dudmuck 0:aad43948c45c 541 }
dudmuck 0:aad43948c45c 542
dudmuck 0:aad43948c45c 543 return TRUE;
dudmuck 0:aad43948c45c 544 }
dudmuck 0:aad43948c45c 545
dudmuck 0:aad43948c45c 546 /**
dudmuck 0:aad43948c45c 547 * Parse string parameter
dudmuck 0:aad43948c45c 548 * @param context
dudmuck 0:aad43948c45c 549 * @param value Pointer to string buffer where pointer to non-null terminated string will be returned
dudmuck 0:aad43948c45c 550 * @param len Length of returned non-null terminated string
dudmuck 0:aad43948c45c 551 * @param mandatory
dudmuck 0:aad43948c45c 552 * @return
dudmuck 0:aad43948c45c 553 */
dudmuck 0:aad43948c45c 554 scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 555 size_t length;
dudmuck 0:aad43948c45c 556
dudmuck 0:aad43948c45c 557 if (!value || !len) {
dudmuck 0:aad43948c45c 558 return FALSE;
dudmuck 0:aad43948c45c 559 }
dudmuck 0:aad43948c45c 560
dudmuck 0:aad43948c45c 561 if (!paramNext(context, mandatory)) {
dudmuck 0:aad43948c45c 562 return FALSE;
dudmuck 0:aad43948c45c 563 }
dudmuck 0:aad43948c45c 564
dudmuck 0:aad43948c45c 565 if (locateStr(context->paramlist.parameters, context->paramlist.length, value, &length)) {
dudmuck 0:aad43948c45c 566 paramSkipBytes(context, length);
dudmuck 0:aad43948c45c 567 paramSkipWhitespace(context);
dudmuck 0:aad43948c45c 568 if (len) {
dudmuck 0:aad43948c45c 569 *len = length;
dudmuck 0:aad43948c45c 570 }
dudmuck 0:aad43948c45c 571 return TRUE;
dudmuck 0:aad43948c45c 572 }
dudmuck 0:aad43948c45c 573
dudmuck 0:aad43948c45c 574 return FALSE;
dudmuck 0:aad43948c45c 575 }
dudmuck 0:aad43948c45c 576
dudmuck 0:aad43948c45c 577 /**
dudmuck 0:aad43948c45c 578 * Parse text parameter (can be inside "")
dudmuck 0:aad43948c45c 579 * @param context
dudmuck 0:aad43948c45c 580 * @param value Pointer to string buffer where pointer to non-null terminated string will be returned
dudmuck 0:aad43948c45c 581 * @param len Length of returned non-null terminated string
dudmuck 0:aad43948c45c 582 * @param mandatory
dudmuck 0:aad43948c45c 583 * @return
dudmuck 0:aad43948c45c 584 */
dudmuck 0:aad43948c45c 585 scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 586 size_t length;
dudmuck 0:aad43948c45c 587
dudmuck 0:aad43948c45c 588 if (!value || !len) {
dudmuck 0:aad43948c45c 589 return FALSE;
dudmuck 0:aad43948c45c 590 }
dudmuck 0:aad43948c45c 591
dudmuck 0:aad43948c45c 592 if (!paramNext(context, mandatory)) {
dudmuck 0:aad43948c45c 593 return FALSE;
dudmuck 0:aad43948c45c 594 }
dudmuck 0:aad43948c45c 595
dudmuck 0:aad43948c45c 596 if (locateText(context->paramlist.parameters, context->paramlist.length, value, &length)) {
dudmuck 0:aad43948c45c 597 paramSkipBytes(context, length);
dudmuck 0:aad43948c45c 598 if (len) {
dudmuck 0:aad43948c45c 599 *len = length;
dudmuck 0:aad43948c45c 600 }
dudmuck 0:aad43948c45c 601 return TRUE;
dudmuck 0:aad43948c45c 602 }
dudmuck 0:aad43948c45c 603
dudmuck 0:aad43948c45c 604 return FALSE;
dudmuck 0:aad43948c45c 605 }
dudmuck 0:aad43948c45c 606
dudmuck 0:aad43948c45c 607 /**
dudmuck 0:aad43948c45c 608 * Parse boolean parameter as described in the spec SCPI-99 7.3 Boolean Program Data
dudmuck 0:aad43948c45c 609 * @param context
dudmuck 0:aad43948c45c 610 * @param value
dudmuck 0:aad43948c45c 611 * @param mandatory
dudmuck 0:aad43948c45c 612 * @return
dudmuck 0:aad43948c45c 613 */
dudmuck 0:aad43948c45c 614 scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 615 const char * param;
dudmuck 0:aad43948c45c 616 size_t param_len;
dudmuck 0:aad43948c45c 617 size_t num_len;
dudmuck 0:aad43948c45c 618 int32_t i;
dudmuck 0:aad43948c45c 619
dudmuck 0:aad43948c45c 620 if (!value) {
dudmuck 0:aad43948c45c 621 return FALSE;
dudmuck 0:aad43948c45c 622 }
dudmuck 0:aad43948c45c 623
dudmuck 0:aad43948c45c 624 if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
dudmuck 0:aad43948c45c 625 return FALSE;
dudmuck 0:aad43948c45c 626 }
dudmuck 0:aad43948c45c 627
dudmuck 0:aad43948c45c 628 if (matchPattern("ON", 2, param, param_len)) {
dudmuck 0:aad43948c45c 629 *value = TRUE;
dudmuck 0:aad43948c45c 630 } else if (matchPattern("OFF", 3, param, param_len)) {
dudmuck 0:aad43948c45c 631 *value = FALSE;
dudmuck 0:aad43948c45c 632 } else {
dudmuck 0:aad43948c45c 633 num_len = strToLong(param, &i);
dudmuck 0:aad43948c45c 634
dudmuck 0:aad43948c45c 635 if (num_len != param_len) {
dudmuck 0:aad43948c45c 636 SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
dudmuck 0:aad43948c45c 637 return FALSE;
dudmuck 0:aad43948c45c 638 }
dudmuck 0:aad43948c45c 639
dudmuck 0:aad43948c45c 640 *value = i ? TRUE : FALSE;
dudmuck 0:aad43948c45c 641 }
dudmuck 0:aad43948c45c 642
dudmuck 0:aad43948c45c 643 return TRUE;
dudmuck 0:aad43948c45c 644 }
dudmuck 0:aad43948c45c 645
dudmuck 0:aad43948c45c 646 /**
dudmuck 0:aad43948c45c 647 * Parse choice parameter
dudmuck 0:aad43948c45c 648 * @param context
dudmuck 0:aad43948c45c 649 * @param options
dudmuck 0:aad43948c45c 650 * @param value
dudmuck 0:aad43948c45c 651 * @param mandatory
dudmuck 0:aad43948c45c 652 * @return
dudmuck 0:aad43948c45c 653 */
dudmuck 0:aad43948c45c 654 scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory) {
dudmuck 0:aad43948c45c 655 const char * param;
dudmuck 0:aad43948c45c 656 size_t param_len;
dudmuck 0:aad43948c45c 657 size_t res;
dudmuck 0:aad43948c45c 658
dudmuck 0:aad43948c45c 659 if (!options || !value) {
dudmuck 0:aad43948c45c 660 return FALSE;
dudmuck 0:aad43948c45c 661 }
dudmuck 0:aad43948c45c 662
dudmuck 0:aad43948c45c 663 if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
dudmuck 0:aad43948c45c 664 return FALSE;
dudmuck 0:aad43948c45c 665 }
dudmuck 0:aad43948c45c 666
dudmuck 0:aad43948c45c 667 for (res = 0; options[res]; ++res) {
dudmuck 0:aad43948c45c 668 if (matchPattern(options[res], strlen(options[res]), param, param_len)) {
dudmuck 0:aad43948c45c 669 *value = res;
dudmuck 0:aad43948c45c 670 return TRUE;
dudmuck 0:aad43948c45c 671 }
dudmuck 0:aad43948c45c 672 }
dudmuck 0:aad43948c45c 673
dudmuck 0:aad43948c45c 674 SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
dudmuck 0:aad43948c45c 675 return FALSE;
dudmuck 0:aad43948c45c 676 }
dudmuck 0:aad43948c45c 677
dudmuck 0:aad43948c45c 678 scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd) {
dudmuck 0:aad43948c45c 679 if (! context->paramlist.cmd) {
dudmuck 0:aad43948c45c 680 return FALSE;
dudmuck 0:aad43948c45c 681 }
dudmuck 0:aad43948c45c 682
dudmuck 0:aad43948c45c 683 const char * pattern = context->paramlist.cmd->pattern;
dudmuck 0:aad43948c45c 684 return matchCommand (pattern, cmd, strlen (cmd));
dudmuck 0:aad43948c45c 685 }