scpi-parser, adopted from github

Dependents:   scpi_parser_test

Committer:
iesensor
Date:
Fri Nov 14 01:07:59 2014 +0000
Revision:
0:d8aca47812e0
tested on K64F

Who changed what in which revision?

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