├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── examples └── test-interactive │ ├── scpi-def.cpp │ ├── scpi-def.h │ └── test-interactive.ino ├── library.properties └── src ├── SCPI_Parser.h ├── scpi ├── cc.h ├── config.h ├── constants.h ├── error.h ├── expression.h ├── ieee488.h ├── minimal.h ├── parser.h ├── types.h ├── units.h └── utils.h └── src ├── error.c ├── expression.c ├── fifo.c ├── fifo_private.h ├── ieee488.c ├── lexer.c ├── lexer_private.h ├── minimal.c ├── parser.c ├── parser_private.h ├── scpi.g ├── units.c ├── utils.c └── utils_private.h /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | jobs: 3 | lint: 4 | runs-on: ubuntu-latest 5 | steps: 6 | - uses: actions/checkout@v3 7 | - uses: arduino/arduino-lint-action@v1.0.2 8 | with: 9 | library-manager: submit 10 | project-type: library 11 | compliance: strict 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2023, Scott Feister 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SCPI Parser Arduino Library 2 | The [SCPI Parser](https://github.com/j123b567/scpi-parser) library (by Jan Breuer) attempts to be SCPI-99 compliant and is aimed at advanced programmers or instrumentation engineers. This GitHub page contains a port of that library to the Arduino IDE. 3 | 4 | SCPI Parser is not suitable for beginners to Arduino. For a lighter-weight solution in your Arduino projects, consider the [Vrekrer SCPI Parser library](https://github.com/Vrekrer/Vrekrer_scpi_parser). It is much simpler and easier to incorporate into your Arduino code. 5 | 6 | ## About 7 | The SCPI Parser C/C++ library is written by **Jan Breuer** and is contributed to by a variety of community members. 8 | 9 | I re-packaged it as an Arduino library so we could use this powerful library easily with Teensy 4.1 boards, which use the Arduino IDE, to develop embedded devices that communicate over SCPI. Arduino Library port of SCPI Parser is maintained by Scott Feister. I will try to keep it up-to-date with the primary SCPI Parser library. Open issues here *only* with issues of SCPI Parser in the Arduino IDE (not for general issues with SCPI Parser). 10 | 11 | ## Documentation 12 | Visit the [Official SCPI Parser Documentation](https://www.jaybee.cz/scpi-parser/) or the [Official SCPI Parser GitHub](https://github.com/j123b567/scpi-parser) for documentation on SCPI Parser (C/C++). The documentation on *this* page only contains developer information about the port of SCPI Parser to an Arduino Library. 13 | 14 | ## Installation 15 | This library is meant to be installed through the Arduino library manager. You can also download this repository as a zip file. 16 | 17 | ## Limitations 18 | This port to Arduino IDE is not tested on any boards except for the Teensy 4.1. It does not work on the Arduino Uno, Arduino Nano, etc. 19 | 20 | ## References I used while porting this library to Arduino 21 | 22 | 1. [Arduino Libraries](https://docs.arduino.cc/hacking/software/Libraries) 23 | 1. [Building a Library for Arduino](https://docs.arduino.cc/learn/contributions/arduino-creating-library-guide) 24 | 1. [Library Specification](https://arduino.github.io/arduino-cli/0.31/library-specification/) 25 | 26 | ## Steps I took to port this library to Arduino 27 | Created a new folder. 28 | 29 | Inside that folder, created library.keywords file and filled it with content. 30 | ``` 31 | name=SCPI-Parser 32 | version=2.2.0 33 | author=Jan Breuer 34 | maintainer=Scott Feister 35 | sentence=Port of SCPI Parser library (C/C++) to Arduino. Aims to provide parsing ability of SCPI commands on instrument side. 36 | paragraph=SCPI parser library is based on these standards: SCPI-99, IEEE 488.2-2004. This Arduino port was made by downloading SCPI Parser's most recent GitHub version as of March 4, 2023, so that recent C++ fixes were included. SCPI Parser (C/C++) git version was 4e87990. This is therefore not actually version 2.2.0, but slightly ahead of that version. 37 | category=Device Control 38 | url=https://www.jaybee.cz/scpi-parser/ 39 | includes=scpi.h 40 | architectures=* 41 | ``` 42 | 43 | Create a folder called "SCPI-Parser". 44 | 45 | Create a new folder named "src". This will store all source code and headers. (See Library Specification reference for Arduino, above). 46 | 47 | 1. From the SCPI Parser GitHub page, copy over the "root/libscpi/src" folder in its entirety. This becomes "/src/src" in the Arduino Library. 48 | 1. From the SCPI Parser GitHub page, copy over the "root/libscpi/inc/scpi" folder in its entirety. This becomes "/src/scpi" in the Arduino Library. 49 | 1. Within the Arduino Library, move the file "/src/scpi/scpi.h" up one level so it becomes "/src/scpi.h". 50 | 1. Rename "scpi.h" to "SCPI_Parser.h", to match Arduino best practices of matching header files to library name. 51 | 52 | ## Included Example 53 | This Arduino library contains just one example. This example is a direct port of the "test-interactive" example from the "examples" folder of the original source code of SCPI Parser. 54 | 55 | The following files were adapted from the original source code of SCPI Parser while porting this example: 56 | * root/examples/common-cxx/scpi-def.cpp 57 | * root/examples/common-cxx/scpi-def.h 58 | * root/examples/test-interactive-cxx/main.cpp 59 | 60 | In particular, for scpi-def.cpp and scpi-def.h, I just replaced `#include "scpi/scpi.h"` with `#include `. 61 | 62 | The "test-interactive/main.cpp" required much more heavy modfication, and became "test-interactive.ino". You can interact with this test device through the Serial monitor of the Arduino IDE. 63 | 64 | -------------------------------------------------------------------------------- /examples/test-interactive/scpi-def.cpp: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | This code is an adaptation of the "common-cxx" example folder from [scpi-parser]. 29 | 30 | GitHub page for [scpi-parser]: https://github.com/j123b567/scpi-parser 31 | Git checkout was on March 4, 2023. Revision 4e87990. 32 | 33 | The following files were modified for Arduino: 34 | [scpi-parser]/examples/common-cxx/scpi-def.cpp 35 | [scpi-parser]/examples/common-cxx/scpi-def.h 36 | 37 | The original [scpi-parser] code is an open project by Jan Breuer. 38 | Modified for Arduino by Scott Feister on March 4, 2023. 39 | BSD license is above for the [scpi-parser] project. 40 | 41 | */ 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include "scpi-def.h" 48 | 49 | static scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) { 50 | scpi_number_t param1, param2; 51 | char bf[15]; 52 | fprintf(stderr, "meas:volt:dc\r\n"); /* debug command name */ 53 | 54 | /* read first parameter if present */ 55 | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m1, FALSE)) { 56 | /* do something, if parameter not present */ 57 | } 58 | 59 | /* read second paraeter if present */ 60 | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m2, FALSE)) { 61 | /* do something, if parameter not present */ 62 | } 63 | 64 | 65 | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m1, bf, 15); 66 | fprintf(stderr, "\tP1=%s\r\n", bf); 67 | 68 | 69 | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m2, bf, 15); 70 | fprintf(stderr, "\tP2=%s\r\n", bf); 71 | 72 | SCPI_ResultDouble(context, 0); 73 | 74 | return SCPI_RES_OK; 75 | } 76 | 77 | static scpi_result_t DMM_MeasureVoltageAcQ(scpi_t * context) { 78 | scpi_number_t param1, param2; 79 | char bf[15]; 80 | fprintf(stderr, "meas:volt:ac\r\n"); /* debug command name */ 81 | 82 | /* read first parameter if present */ 83 | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m1, FALSE)) { 84 | /* do something, if parameter not present */ 85 | } 86 | 87 | /* read second paraeter if present */ 88 | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m2, FALSE)) { 89 | /* do something, if parameter not present */ 90 | } 91 | 92 | 93 | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m1, bf, 15); 94 | fprintf(stderr, "\tP1=%s\r\n", bf); 95 | 96 | 97 | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m2, bf, 15); 98 | fprintf(stderr, "\tP2=%s\r\n", bf); 99 | 100 | SCPI_ResultDouble(context, 0); 101 | 102 | return SCPI_RES_OK; 103 | } 104 | 105 | static scpi_result_t DMM_ConfigureVoltageDc(scpi_t * context) { 106 | double param1, param2; 107 | fprintf(stderr, "conf:volt:dc\r\n"); /* debug command name */ 108 | 109 | /* read first parameter if present */ 110 | if (!SCPI_ParamDouble(context, ¶m1, TRUE)) { 111 | return SCPI_RES_ERR; 112 | } 113 | 114 | /* read second paraeter if present */ 115 | if (!SCPI_ParamDouble(context, ¶m2, FALSE)) { 116 | /* do something, if parameter not present */ 117 | } 118 | 119 | fprintf(stderr, "\tP1=%lf\r\n", param1); 120 | fprintf(stderr, "\tP2=%lf\r\n", param2); 121 | 122 | return SCPI_RES_OK; 123 | } 124 | 125 | static scpi_result_t TEST_Bool(scpi_t * context) { 126 | scpi_bool_t param1; 127 | fprintf(stderr, "TEST:BOOL\r\n"); /* debug command name */ 128 | 129 | /* read first parameter if present */ 130 | if (!SCPI_ParamBool(context, ¶m1, TRUE)) { 131 | return SCPI_RES_ERR; 132 | } 133 | 134 | fprintf(stderr, "\tP1=%d\r\n", param1); 135 | 136 | return SCPI_RES_OK; 137 | } 138 | 139 | scpi_choice_def_t trigger_source[] = { 140 | {"BUS", 5}, 141 | {"IMMediate", 6}, 142 | {"EXTernal", 7}, 143 | SCPI_CHOICE_LIST_END /* termination of option list */ 144 | }; 145 | 146 | static scpi_result_t TEST_ChoiceQ(scpi_t * context) { 147 | 148 | int32_t param; 149 | const char * name; 150 | 151 | if (!SCPI_ParamChoice(context, trigger_source, ¶m, TRUE)) { 152 | return SCPI_RES_ERR; 153 | } 154 | 155 | SCPI_ChoiceToName(trigger_source, param, &name); 156 | fprintf(stderr, "\tP1=%s (%ld)\r\n", name, (long int) param); 157 | 158 | SCPI_ResultInt32(context, param); 159 | 160 | return SCPI_RES_OK; 161 | } 162 | 163 | static scpi_result_t TEST_Numbers(scpi_t * context) { 164 | int32_t numbers[2]; 165 | 166 | SCPI_CommandNumbers(context, numbers, 2, 1); 167 | 168 | fprintf(stderr, "TEST numbers %d %d\r\n", numbers[0], numbers[1]); 169 | 170 | return SCPI_RES_OK; 171 | } 172 | 173 | static scpi_result_t TEST_Text(scpi_t * context) { 174 | char buffer[100]; 175 | size_t copy_len; 176 | 177 | if (!SCPI_ParamCopyText(context, buffer, sizeof (buffer), ©_len, FALSE)) { 178 | buffer[0] = '\0'; 179 | } 180 | 181 | fprintf(stderr, "TEXT: ***%s***\r\n", buffer); 182 | 183 | return SCPI_RES_OK; 184 | } 185 | 186 | static scpi_result_t TEST_ArbQ(scpi_t * context) { 187 | const char * data; 188 | size_t len; 189 | 190 | if (SCPI_ParamArbitraryBlock(context, &data, &len, FALSE)) { 191 | SCPI_ResultArbitraryBlock(context, data, len); 192 | } 193 | 194 | return SCPI_RES_OK; 195 | } 196 | 197 | struct _scpi_channel_value_t { 198 | int32_t row; 199 | int32_t col; 200 | }; 201 | typedef struct _scpi_channel_value_t scpi_channel_value_t; 202 | 203 | /** 204 | * @brief 205 | * parses lists 206 | * channel numbers > 0. 207 | * no checks yet. 208 | * valid: (@1), (@3!1:1!3), ... 209 | * (@1!1:3!2) would be 1!1, 1!2, 2!1, 2!2, 3!1, 3!2. 210 | * (@3!1:1!3) would be 3!1, 3!2, 3!3, 2!1, 2!2, 2!3, ... 1!3. 211 | * 212 | * @param channel_list channel list, compare to SCPI99 Vol 1 Ch. 8.3.2 213 | */ 214 | static scpi_result_t TEST_Chanlst(scpi_t *context) { 215 | scpi_parameter_t channel_list_param; 216 | #define MAXROW 2 /* maximum number of rows */ 217 | #define MAXCOL 6 /* maximum number of columns */ 218 | #define MAXDIM 2 /* maximum number of dimensions */ 219 | scpi_channel_value_t array[MAXROW * MAXCOL]; /* array which holds values in order (2D) */ 220 | size_t chanlst_idx; /* index for channel list */ 221 | size_t arr_idx = 0; /* index for array */ 222 | size_t n, m = 1; /* counters for row (n) and columns (m) */ 223 | 224 | /* get channel list */ 225 | if (SCPI_Parameter(context, &channel_list_param, TRUE)) { 226 | scpi_expr_result_t res; 227 | scpi_bool_t is_range; 228 | int32_t values_from[MAXDIM]; 229 | int32_t values_to[MAXDIM]; 230 | size_t dimensions; 231 | 232 | bool for_stop_row = FALSE; /* true if iteration for rows has to stop */ 233 | bool for_stop_col = FALSE; /* true if iteration for columns has to stop */ 234 | int32_t dir_row = 1; /* direction of counter for rows, +/-1 */ 235 | int32_t dir_col = 1; /* direction of counter for columns, +/-1 */ 236 | 237 | /* the next statement is valid usage and it gets only real number of dimensions for the first item (index 0) */ 238 | if (!SCPI_ExprChannelListEntry(context, &channel_list_param, 0, &is_range, NULL, NULL, 0, &dimensions)) { 239 | chanlst_idx = 0; /* call first index */ 240 | arr_idx = 0; /* set arr_idx to 0 */ 241 | do { /* if valid, iterate over channel_list_param index while res == valid (do-while cause we have to do it once) */ 242 | res = SCPI_ExprChannelListEntry(context, &channel_list_param, chanlst_idx, &is_range, values_from, values_to, 4, &dimensions); 243 | if (is_range == FALSE) { /* still can have multiple dimensions */ 244 | if (dimensions == 1) { 245 | /* here we have our values 246 | * row == values_from[0] 247 | * col == 0 (fixed number) 248 | * call a function or something */ 249 | array[arr_idx].row = values_from[0]; 250 | array[arr_idx].col = 0; 251 | } else if (dimensions == 2) { 252 | /* here we have our values 253 | * row == values_fom[0] 254 | * col == values_from[1] 255 | * call a function or something */ 256 | array[arr_idx].row = values_from[0]; 257 | array[arr_idx].col = values_from[1]; 258 | } else { 259 | return SCPI_RES_ERR; 260 | } 261 | arr_idx++; /* inkrement array where we want to save our values to, not neccessary otherwise */ 262 | if (arr_idx >= MAXROW * MAXCOL) { 263 | return SCPI_RES_ERR; 264 | } 265 | } else if (is_range == TRUE) { 266 | if (values_from[0] > values_to[0]) { 267 | dir_row = -1; /* we have to decrement from values_from */ 268 | } else { /* if (values_from[0] < values_to[0]) */ 269 | dir_row = +1; /* default, we increment from values_from */ 270 | } 271 | 272 | /* iterating over rows, do it once -> set for_stop_row = false 273 | * needed if there is channel list index isn't at end yet */ 274 | for_stop_row = FALSE; 275 | for (n = values_from[0]; for_stop_row == FALSE; n += dir_row) { 276 | /* usual case for ranges, 2 dimensions */ 277 | if (dimensions == 2) { 278 | if (values_from[1] > values_to[1]) { 279 | dir_col = -1; 280 | } else if (values_from[1] < values_to[1]) { 281 | dir_col = +1; 282 | } 283 | /* iterating over columns, do it at least once -> set for_stop_col = false 284 | * needed if there is channel list index isn't at end yet */ 285 | for_stop_col = FALSE; 286 | for (m = values_from[1]; for_stop_col == FALSE; m += dir_col) { 287 | /* here we have our values 288 | * row == n 289 | * col == m 290 | * call a function or something */ 291 | array[arr_idx].row = n; 292 | array[arr_idx].col = m; 293 | arr_idx++; 294 | if (arr_idx >= MAXROW * MAXCOL) { 295 | return SCPI_RES_ERR; 296 | } 297 | if (m == (size_t)values_to[1]) { 298 | /* endpoint reached, stop column for-loop */ 299 | for_stop_col = TRUE; 300 | } 301 | } 302 | /* special case for range, example: (@2!1) */ 303 | } else if (dimensions == 1) { 304 | /* here we have values 305 | * row == n 306 | * col == 0 (fixed number) 307 | * call function or sth. */ 308 | array[arr_idx].row = n; 309 | array[arr_idx].col = 0; 310 | arr_idx++; 311 | if (arr_idx >= MAXROW * MAXCOL) { 312 | return SCPI_RES_ERR; 313 | } 314 | } 315 | if (n == (size_t)values_to[0]) { 316 | /* endpoint reached, stop row for-loop */ 317 | for_stop_row = TRUE; 318 | } 319 | } 320 | 321 | 322 | } else { 323 | return SCPI_RES_ERR; 324 | } 325 | /* increase index */ 326 | chanlst_idx++; 327 | } while (SCPI_EXPR_OK == SCPI_ExprChannelListEntry(context, &channel_list_param, chanlst_idx, &is_range, values_from, values_to, 4, &dimensions)); 328 | /* while checks, whether incremented index is valid */ 329 | } 330 | /* do something at the end if needed */ 331 | /* array[arr_idx].row = 0; */ 332 | /* array[arr_idx].col = 0; */ 333 | } 334 | 335 | { 336 | size_t i; 337 | fprintf(stderr, "TEST_Chanlst: "); 338 | for (i = 0; i< arr_idx; i++) { 339 | fprintf(stderr, "%d!%d, ", array[i].row, array[i].col); 340 | } 341 | fprintf(stderr, "\r\n"); 342 | } 343 | return SCPI_RES_OK; 344 | } 345 | 346 | /** 347 | * Reimplement IEEE488.2 *TST? 348 | * 349 | * Result should be 0 if everything is ok 350 | * Result should be 1 if something goes wrong 351 | * 352 | * Return SCPI_RES_OK 353 | */ 354 | static scpi_result_t My_CoreTstQ(scpi_t * context) { 355 | 356 | SCPI_ResultInt32(context, 0); 357 | 358 | return SCPI_RES_OK; 359 | } 360 | 361 | const scpi_command_t scpi_commands[] = { 362 | /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */ 363 | {"*CLS", SCPI_CoreCls, 0}, 364 | {"*ESE", SCPI_CoreEse, 0}, 365 | {"*ESE?", SCPI_CoreEseQ, 0}, 366 | {"*ESR?", SCPI_CoreEsrQ, 0}, 367 | {"*IDN?", SCPI_CoreIdnQ, 0}, 368 | {"*OPC", SCPI_CoreOpc, 0}, 369 | {"*OPC?", SCPI_CoreOpcQ, 0}, 370 | {"*RST", SCPI_CoreRst, 0}, 371 | {"*SRE", SCPI_CoreSre, 0}, 372 | {"*SRE?", SCPI_CoreSreQ, 0}, 373 | {"*STB?", SCPI_CoreStbQ, 0}, 374 | {"*TST?", My_CoreTstQ, 0}, 375 | {"*WAI", SCPI_CoreWai, 0}, 376 | 377 | /* Required SCPI commands (SCPI std V1999.0 4.2.1) */ 378 | {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, 0}, 379 | {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, 0}, 380 | {"SYSTem:VERSion?", SCPI_SystemVersionQ, 0}, 381 | 382 | //{"STATus:OPERation?", scpi_stub_callback, 0}, 383 | //{"STATus:OPERation:EVENt?", scpi_stub_callback, 0}, 384 | //{"STATus:OPERation:CONDition?", scpi_stub_callback, 0}, 385 | //{"STATus:OPERation:ENABle", scpi_stub_callback, 0}, 386 | //{"STATus:OPERation:ENABle?", scpi_stub_callback, 0}, 387 | 388 | {"STATus:QUEStionable[:EVENt]?", SCPI_StatusQuestionableEventQ, 0}, 389 | //{"STATus:QUEStionable:CONDition?", scpi_stub_callback, 0}, 390 | {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable, 0}, 391 | {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ, 0}, 392 | 393 | {"STATus:PRESet", SCPI_StatusPreset, 0}, 394 | 395 | /* DMM */ 396 | {"MEASure:VOLTage:DC?", DMM_MeasureVoltageDcQ, 0}, 397 | {"CONFigure:VOLTage:DC", DMM_ConfigureVoltageDc, 0}, 398 | {"MEASure:VOLTage:DC:RATio?", SCPI_StubQ, 0}, 399 | {"MEASure:VOLTage:AC?", DMM_MeasureVoltageAcQ, 0}, 400 | {"MEASure:CURRent:DC?", SCPI_StubQ, 0}, 401 | {"MEASure:CURRent:AC?", SCPI_StubQ, 0}, 402 | {"MEASure:RESistance?", SCPI_StubQ, 0}, 403 | {"MEASure:FRESistance?", SCPI_StubQ, 0}, 404 | {"MEASure:FREQuency?", SCPI_StubQ, 0}, 405 | {"MEASure:PERiod?", SCPI_StubQ, 0}, 406 | 407 | {"SYSTem:COMMunication:TCPIP:CONTROL?", SCPI_SystemCommTcpipControlQ, 0}, 408 | 409 | {"TEST:BOOL", TEST_Bool, 0}, 410 | {"TEST:CHOice?", TEST_ChoiceQ, 0}, 411 | {"TEST#:NUMbers#", TEST_Numbers, 0}, 412 | {"TEST:TEXT", TEST_Text, 0}, 413 | {"TEST:ARBitrary?", TEST_ArbQ, 0}, 414 | {"TEST:CHANnellist", TEST_Chanlst, 0}, 415 | 416 | SCPI_CMD_LIST_END 417 | }; 418 | 419 | scpi_interface_t scpi_interface = { 420 | /*.error = */ SCPI_Error, 421 | /*.write = */ SCPI_Write, 422 | /*.control = */ SCPI_Control, 423 | /*.flush = */ SCPI_Flush, 424 | /*.reset = */ SCPI_Reset, 425 | }; 426 | 427 | char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH]; 428 | scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE]; 429 | 430 | scpi_t scpi_context; 431 | -------------------------------------------------------------------------------- /examples/test-interactive/scpi-def.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | This code is an adaptation of the "common-cxx" example folder from [scpi-parser]. 29 | 30 | GitHub page for [scpi-parser]: https://github.com/j123b567/scpi-parser 31 | Git checkout was on March 4, 2023. Revision 4e87990. 32 | 33 | The following files were modified for Arduino: 34 | [scpi-parser]/examples/common-cxx/scpi-def.cpp 35 | [scpi-parser]/examples/common-cxx/scpi-def.h 36 | 37 | The original [scpi-parser] code is an open project by Jan Breuer. 38 | Modified for Arduino by Scott Feister on March 4, 2023 39 | BSD license is above for the [scpi-parser] project. 40 | 41 | */ 42 | 43 | #ifndef __SCPI_DEF_H_ 44 | #define __SCPI_DEF_H_ 45 | 46 | 47 | #include 48 | 49 | #define SCPI_INPUT_BUFFER_LENGTH 256 50 | #define SCPI_ERROR_QUEUE_SIZE 17 51 | #define SCPI_IDN1 "MANUFACTURE" 52 | #define SCPI_IDN2 "INSTR2013" 53 | #define SCPI_IDN3 NULL 54 | #define SCPI_IDN4 "01-02" 55 | 56 | extern const scpi_command_t scpi_commands[]; 57 | extern scpi_interface_t scpi_interface; 58 | extern char scpi_input_buffer[]; 59 | extern scpi_error_t scpi_error_queue_data[]; 60 | extern scpi_t scpi_context; 61 | 62 | size_t SCPI_Write(scpi_t * context, const char * data, size_t len); 63 | int SCPI_Error(scpi_t * context, int_fast16_t err); 64 | scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val); 65 | scpi_result_t SCPI_Reset(scpi_t * context); 66 | scpi_result_t SCPI_Flush(scpi_t * context); 67 | 68 | 69 | scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context); 70 | 71 | #endif /* __SCPI_DEF_H_ */ 72 | -------------------------------------------------------------------------------- /examples/test-interactive/test-interactive.ino: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | SCPI interactive parser example 29 | 30 | This code is an adaptation of the "test-interactive" example from [scpi-parser]. 31 | 32 | GitHub page for [scpi-parser]: https://github.com/j123b567/scpi-parser 33 | Git checkout was on March 4, 2023. Revision 4e87990. 34 | 35 | The following files were modified for Arduino: 36 | [scpi-parser]/examples/common-cxx/scpi-def.cpp 37 | [scpi-parser]/examples/common-cxx/scpi-def.h 38 | [scpi-parser]/examples/test-interactive-cxx/main.cpp 39 | 40 | The original [scpi-parser] code is an open project by Jan Breuer. 41 | Modified for Arduino by Scott Feister on March 4, 2023 42 | BSD license is above for the [scpi-parser] project. 43 | 44 | */ 45 | 46 | #include 47 | #include "scpi-def.h" 48 | 49 | char incoming_byte = 0; // for incoming serial data 50 | 51 | size_t SCPI_Write(scpi_t * context, const char * data, size_t len) { 52 | (void) context; 53 | Serial.write(data, len); 54 | return len; 55 | } 56 | 57 | scpi_result_t SCPI_Flush(scpi_t * context) { 58 | (void) context; 59 | Serial.flush(); 60 | return SCPI_RES_OK; 61 | } 62 | 63 | int SCPI_Error(scpi_t * context, int_fast16_t err) { 64 | (void) context; 65 | Serial.print("**ERROR: "); 66 | Serial.print(err); 67 | Serial.print(", \""); 68 | Serial.print(SCPI_ErrorTranslate(err)); 69 | Serial.println("\""); 70 | return 0; 71 | } 72 | 73 | scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) { 74 | (void) context; 75 | 76 | if (SCPI_CTRL_SRQ == ctrl) { 77 | Serial.print("**SRQ: 0x"); 78 | Serial.print(val, HEX); 79 | Serial.print("("); 80 | Serial.print(val, DEC); 81 | Serial.println(")"); 82 | } else { 83 | Serial.print("**CTRL: "); 84 | Serial.print(val, HEX); 85 | Serial.print("("); 86 | Serial.print(val, DEC); 87 | Serial.println(")"); 88 | } 89 | return SCPI_RES_OK; 90 | } 91 | 92 | scpi_result_t SCPI_Reset(scpi_t * context) { 93 | (void) context; 94 | Serial.println("**Reset"); 95 | return SCPI_RES_OK; 96 | } 97 | 98 | scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context) { 99 | (void) context; 100 | return SCPI_RES_ERR; 101 | } 102 | 103 | void setup() { 104 | SCPI_Init(&scpi_context, 105 | scpi_commands, 106 | &scpi_interface, 107 | scpi_units_def, 108 | SCPI_IDN1, SCPI_IDN2, SCPI_IDN3, SCPI_IDN4, 109 | scpi_input_buffer, SCPI_INPUT_BUFFER_LENGTH, 110 | scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE); 111 | 112 | Serial.begin(9600); 113 | while (!Serial); // wait for serial to finish initializing 114 | Serial.println("SCPI Interactive demo"); 115 | } 116 | 117 | void loop() { 118 | // send data to SCPI parser only when you receive data: 119 | if (Serial.available() > 0) { 120 | incoming_byte = Serial.read(); 121 | SCPI_Input(&scpi_context, &incoming_byte, 1); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SCPI_Parser 2 | version=2.2.0 3 | author=Jan Breuer 4 | maintainer=Scott Feister 5 | sentence=Port of the C/C++ "SCPI Parser" library by Jan Breuer, suitable for advanced C/C++ programmers. For a much simpler solution in your Arduino projects, consider the Vrekrer SCPI Parser library. 6 | paragraph=SCPI Parser for advanced programmers or instrumentation engineers. Tested only on Teensy 4.1 board. Fails to compile for Arduino Uno/Nano due to missing strtoull() in stdlib.h. Port of the C/C++ SCPI Parser library by Jan Breuer. Aims to provide parsing ability of SCPI commands on instrument side. SCPI parser library is based on these standards: SCPI-99, IEEE 488.2-2004. This Arduino port was made by downloading SCPI Parser's most recent GitHub version as of March 4, 2023, so that recent C++ fixes were included. SCPI Parser (C/C++) git version was 4e87990. This is therefore not actually version 2.2.0, but slightly ahead of that version. 7 | category=Communication 8 | url=https://github.com/sfeister/scpi-parser-arduino 9 | includes=SCPI_Parser.h 10 | architectures=* 11 | -------------------------------------------------------------------------------- /src/SCPI_Parser.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI library include file 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_H 39 | #define SCPI_H 40 | 41 | #include "scpi/parser.h" 42 | #include "scpi/ieee488.h" 43 | #include "scpi/error.h" 44 | #include "scpi/constants.h" 45 | #include "scpi/minimal.h" 46 | #include "scpi/units.h" 47 | #include "scpi/utils.h" 48 | #include "scpi/expression.h" 49 | 50 | #endif /* SCPI_H */ 51 | 52 | -------------------------------------------------------------------------------- /src/scpi/cc.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file cc.h 31 | * 32 | * @brief compiler detection 33 | * 34 | * 35 | */ 36 | 37 | #ifndef __SCPI_CC_H_ 38 | #define __SCPI_CC_H_ 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | #if defined(__STDC__) 45 | # define C89 1 46 | # if defined(__STDC_VERSION__) 47 | # define C90 1 48 | # if (__STDC_VERSION__ >= 199409L) 49 | # define C94 1 50 | # endif 51 | # if (__STDC_VERSION__ >= 199901L) 52 | # define C99 1 53 | # endif 54 | # endif 55 | #endif 56 | 57 | #if defined(__cplusplus) 58 | # if (__cplusplus >= 199711) 59 | # define CXX98 1 60 | # endif 61 | #endif 62 | 63 | #if (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200809L) || \ 64 | (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 700) 65 | #define HAVE_STRNDUP 1 66 | #define HAVE_STRNLEN 1 67 | #endif 68 | 69 | #if (defined _BSD_SOURCE && _BSD_SOURCE) || \ 70 | (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 500) || \ 71 | (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \ 72 | (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) || \ 73 | C99 74 | #define HAVE_SNPRINTF 1 75 | #endif 76 | 77 | #if (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) 78 | #define HAVE_STRNCASECMP 1 79 | #endif 80 | 81 | #if (defined _BSD_SOURCE && _BSD_SOURCE) || \ 82 | (defined _SVID_SOURCE && _SVID_SOURCE) || \ 83 | (defined _XOPEN_SOURCE && _XOPEN_SOURCE) || \ 84 | (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \ 85 | (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) ||\ 86 | C99 87 | #define HAVE_ISNAN 1 88 | #endif 89 | 90 | #if (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600)|| \ 91 | (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \ 92 | (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) || \ 93 | C99 94 | #define HAVE_ISFINITE 1 95 | #define HAVE_SIGNBIT 1 96 | #endif 97 | 98 | #if (defined _XOPEN_SOURCE && XOPEN_SOURCE >= 600) || \ 99 | (defined _BSD_SOURCE && _BSD_SOURCE) || \ 100 | (defined _SVID_SOURCE && _SVID_SOURCE) || \ 101 | (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \ 102 | (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) 103 | #define HAVE_STRTOLL 1 104 | #endif 105 | 106 | #if (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600) || \ 107 | (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \ 108 | (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) || \ 109 | C99 110 | #define HAVE_STRTOF 1 111 | #endif 112 | 113 | #if (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || C99 || CXX98 114 | #define HAVE_STDBOOL 1 115 | #endif 116 | 117 | /* Compiler specific */ 118 | /* RealView/Keil ARM Compiler, e.g. Cortex-M CPUs */ 119 | #if defined(__CC_ARM) 120 | #define HAVE_STRNCASECMP 1 121 | #endif 122 | 123 | /* National Instruments (R) CVI x86/x64 PC platform */ 124 | #if defined(_CVI_) 125 | #define HAVE_STRNICMP 1 126 | #endif 127 | 128 | /* 8bit PIC - PIC16, etc */ 129 | #if defined(_MPC_) 130 | #define HAVE_STRNICMP 1 131 | #endif 132 | 133 | /* PIC24 */ 134 | #if defined(__C30__) 135 | #endif 136 | 137 | /* PIC32mx */ 138 | #if defined(__C32__) 139 | #define HAVE_FINITE 1 140 | #endif 141 | 142 | /* AVR libc */ 143 | #if defined(__AVR__) 144 | #include 145 | #define HAVE_DTOSTRE 1 146 | #undef HAVE_STRTOF 147 | #define HAVE_STRTOF 0 148 | #endif 149 | 150 | /* default values */ 151 | #ifndef HAVE_STRNLEN 152 | #define HAVE_STRNLEN 0 153 | #endif 154 | 155 | #ifndef HAVE_STRDUP 156 | #define HAVE_STRDUP 0 157 | #endif 158 | 159 | #ifndef HAVE_STRNDUP 160 | #define HAVE_STRNDUP 0 161 | #endif 162 | 163 | #ifndef HAVE_STRNICMP 164 | #define HAVE_STRNICMP 0 165 | #endif 166 | 167 | #ifndef HAVE_STDBOOL 168 | #define HAVE_STDBOOL 0 169 | #endif 170 | 171 | #ifndef HAVE_SNPRINTF 172 | #define HAVE_SNPRINTF 0 173 | #endif 174 | 175 | #ifndef HAVE_STRNCASECMP 176 | #define HAVE_STRNCASECMP 0 177 | #endif 178 | 179 | #ifndef HAVE_ISNAN 180 | #define HAVE_ISNAN 0 181 | #endif 182 | 183 | #ifndef HAVE_ISFINITE 184 | #define HAVE_ISFINITE 0 185 | #endif 186 | 187 | #ifndef HAVE_FINITE 188 | #define HAVE_FINITE 0 189 | #endif 190 | 191 | #ifndef HAVE_SIGNBIT 192 | #define HAVE_SIGNBIT 0 193 | #endif 194 | 195 | #ifndef HAVE_STRTOLL 196 | #define HAVE_STRTOLL 0 197 | #endif 198 | 199 | #ifndef HAVE_STRTOF 200 | #define HAVE_STRTOF 0 201 | #endif 202 | 203 | #ifndef HAVE_DTOSTRE 204 | #define HAVE_DTOSTRE 0 205 | #endif 206 | 207 | #ifdef __cplusplus 208 | } 209 | #endif 210 | 211 | #endif /* __SCPI_CC_H_ */ 212 | -------------------------------------------------------------------------------- /src/scpi/config.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file config.h 31 | * @date Wed Mar 20 12:21:26 UTC 2013 32 | * 33 | * @brief SCPI Configuration 34 | * 35 | * 36 | */ 37 | 38 | #ifndef __SCPI_CONFIG_H_ 39 | #define __SCPI_CONFIG_H_ 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #include "cc.h" 46 | 47 | #ifdef SCPI_USER_CONFIG 48 | #include "scpi_user_config.h" 49 | #endif 50 | 51 | /* set the termination character(s) */ 52 | #define LINE_ENDING_CR "\r" /* use a carriage return as termination charcter */ 53 | #define LINE_ENDING_LF "\n" /* use a line feed as termination charcter */ 54 | #define LINE_ENDING_CRLF "\r\n" /* use carriage return + line feed as termination charcters */ 55 | 56 | #ifndef SCPI_LINE_ENDING 57 | #define SCPI_LINE_ENDING LINE_ENDING_CRLF 58 | #endif 59 | 60 | #ifndef USE_CUSTOM_REGISTERS 61 | #define USE_CUSTOM_REGISTERS 0 62 | #endif 63 | 64 | /** 65 | * Detect, if it has limited resources or it is running on a full blown operating system. 66 | * All values can be overiden by scpi_user_config.h 67 | */ 68 | #define SYSTEM_BARE_METAL 0 69 | #define SYSTEM_FULL_BLOWN 1 70 | 71 | /* This should cover all windows compilers (msvc, mingw, cvi) and all Linux/OSX/BSD and other UNIX compatible systems (gcc, clang) */ 72 | #if defined(_WIN32) || defined(_WIN64) || defined(__unix) || defined(__unix__) || defined(__APPLE__) 73 | #define SYSTEM_TYPE SYSTEM_FULL_BLOWN 74 | #else 75 | #define SYSTEM_TYPE SYSTEM_BARE_METAL 76 | #endif 77 | 78 | /** 79 | * Enable full error list 80 | * 0 = Minimal set of errors 81 | * 1 = Full set of errors 82 | * 83 | * For small systems, full set of errors will occupy large ammount of data 84 | * It is enabled by default on full blown systems and disabled on limited bare metal systems 85 | */ 86 | #ifndef USE_FULL_ERROR_LIST 87 | #define USE_FULL_ERROR_LIST SYSTEM_TYPE 88 | #endif 89 | 90 | /** 91 | * Enable also LIST_OF_USER_ERRORS to be included 92 | * 0 = Use only library defined errors 93 | * 1 = Use also LIST_OF_USER_ERRORS 94 | */ 95 | #ifndef USE_USER_ERROR_LIST 96 | #define USE_USER_ERROR_LIST 0 97 | #endif 98 | 99 | #ifndef USE_DEVICE_DEPENDENT_ERROR_INFORMATION 100 | #define USE_DEVICE_DEPENDENT_ERROR_INFORMATION SYSTEM_TYPE 101 | #endif 102 | 103 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION 104 | #ifndef USE_MEMORY_ALLOCATION_FREE 105 | #define USE_MEMORY_ALLOCATION_FREE 1 106 | #endif 107 | #else 108 | #ifndef USE_MEMORY_ALLOCATION_FREE 109 | #define USE_MEMORY_ALLOCATION_FREE 0 110 | #endif 111 | #endif 112 | 113 | #ifndef USE_COMMAND_TAGS 114 | #define USE_COMMAND_TAGS 1 115 | #endif 116 | 117 | #ifndef USE_DEPRECATED_FUNCTIONS 118 | #define USE_DEPRECATED_FUNCTIONS 1 119 | #endif 120 | 121 | #ifndef USE_CUSTOM_DTOSTRE 122 | #define USE_CUSTOM_DTOSTRE 0 123 | #endif 124 | 125 | #ifndef USE_UNITS_IMPERIAL 126 | #define USE_UNITS_IMPERIAL 0 127 | #endif 128 | 129 | #ifndef USE_UNITS_ANGLE 130 | #define USE_UNITS_ANGLE SYSTEM_TYPE 131 | #endif 132 | 133 | #ifndef USE_UNITS_PARTICLES 134 | #define USE_UNITS_PARTICLES SYSTEM_TYPE 135 | #endif 136 | 137 | #ifndef USE_UNITS_DISTANCE 138 | #define USE_UNITS_DISTANCE SYSTEM_TYPE 139 | #endif 140 | 141 | #ifndef USE_UNITS_MAGNETIC 142 | #define USE_UNITS_MAGNETIC SYSTEM_TYPE 143 | #endif 144 | 145 | #ifndef USE_UNITS_LIGHT 146 | #define USE_UNITS_LIGHT SYSTEM_TYPE 147 | #endif 148 | 149 | #ifndef USE_UNITS_ENERGY_FORCE_MASS 150 | #define USE_UNITS_ENERGY_FORCE_MASS SYSTEM_TYPE 151 | #endif 152 | 153 | #ifndef USE_UNITS_TIME 154 | #define USE_UNITS_TIME SYSTEM_TYPE 155 | #endif 156 | 157 | #ifndef USE_UNITS_TEMPERATURE 158 | #define USE_UNITS_TEMPERATURE SYSTEM_TYPE 159 | #endif 160 | 161 | #ifndef USE_UNITS_RATIO 162 | #define USE_UNITS_RATIO SYSTEM_TYPE 163 | #endif 164 | 165 | #ifndef USE_UNITS_POWER 166 | #define USE_UNITS_POWER 1 167 | #endif 168 | 169 | #ifndef USE_UNITS_FREQUENCY 170 | #define USE_UNITS_FREQUENCY 1 171 | #endif 172 | 173 | #ifndef USE_UNITS_ELECTRIC 174 | #define USE_UNITS_ELECTRIC 1 175 | #endif 176 | 177 | #ifndef USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE 178 | #define USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE SYSTEM_TYPE 179 | #endif 180 | 181 | /* define local macros depending on existance of strnlen */ 182 | #if HAVE_STRNLEN 183 | #define SCPIDEFINE_strnlen(s, l) strnlen((s), (l)) 184 | #else 185 | #define SCPIDEFINE_strnlen(s, l) BSD_strnlen((s), (l)) 186 | #endif 187 | 188 | /* define local macros depending on existance of strncasecmp and strnicmp */ 189 | #if HAVE_STRNCASECMP 190 | #define SCPIDEFINE_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l)) 191 | #elif HAVE_STRNICMP 192 | #define SCPIDEFINE_strncasecmp(s1, s2, l) strnicmp((s1), (s2), (l)) 193 | #else 194 | #define SCPIDEFINE_strncasecmp(s1, s2, l) OUR_strncasecmp((s1), (s2), (l)) 195 | #endif 196 | 197 | #if HAVE_DTOSTRE 198 | #define SCPIDEFINE_floatToStr(v, s, l) dtostre((double)(v), (s), 6, DTOSTR_PLUS_SIGN | DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE) 199 | #elif USE_CUSTOM_DTOSTRE 200 | #define SCPIDEFINE_floatToStr(v, s, l) SCPI_dtostre((v), (s), (l), 6, 0) 201 | #elif HAVE_SNPRINTF 202 | #define SCPIDEFINE_floatToStr(v, s, l) snprintf((s), (l), "%g", (v)) 203 | #else 204 | #define SCPIDEFINE_floatToStr(v, s, l) SCPI_dtostre((v), (s), (l), 6, 0) 205 | #endif 206 | 207 | #if HAVE_DTOSTRE 208 | #define SCPIDEFINE_doubleToStr(v, s, l) dtostre((v), (s), 15, DTOSTR_PLUS_SIGN | DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE) 209 | #elif USE_CUSTOM_DTOSTRE 210 | #define SCPIDEFINE_doubleToStr(v, s, l) SCPI_dtostre((v), (s), (l), 15, 0) 211 | #elif HAVE_SNPRINTF 212 | #define SCPIDEFINE_doubleToStr(v, s, l) snprintf((s), (l), "%.15lg", (v)) 213 | #else 214 | #define SCPIDEFINE_doubleToStr(v, s, l) SCPI_dtostre((v), (s), (l), 15, 0) 215 | #endif 216 | 217 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION 218 | 219 | #if USE_MEMORY_ALLOCATION_FREE 220 | #include 221 | #include 222 | #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 2 223 | #if HAVE_STRNDUP 224 | #define SCPIDEFINE_strndup(h, s, l) strndup((s), (l)) 225 | #else 226 | #define SCPIDEFINE_strndup(h, s, l) OUR_strndup((s), (l)) 227 | #endif 228 | #define SCPIDEFINE_free(h, s, r) free((s)) 229 | #else 230 | #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 3 231 | #define SCPIDEFINE_strndup(h, s, l) scpiheap_strndup((h), (s), (l)) 232 | #define SCPIDEFINE_free(h, s, r) scpiheap_free((h), (s), (r)) 233 | #define SCPIDEFINE_get_parts(h, s, l1, s2, l2) scpiheap_get_parts((h), (s), (l1), (s2), (l2)) 234 | #endif 235 | #else 236 | #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 1 237 | #define SCPIDEFINE_strndup(h, s, l) NULL 238 | #define SCPIDEFINE_free(h, s, r) 239 | #endif 240 | 241 | #if HAVE_SIGNBIT 242 | #define SCPIDEFINE_signbit(n) signbit(n) 243 | #else 244 | #define SCPIDEFINE_signbit(n) ((n)<0) 245 | #endif 246 | 247 | #if HAVE_FINITE 248 | #define SCPIDEFINE_isfinite(n) finite(n) 249 | #elif HAVE_ISFINITE 250 | #define SCPIDEFINE_isfinite(n) isfinite(n) 251 | #else 252 | #define SCPIDEFINE_isfinite(n) (!SCPIDEFINE_isnan((n)) && ((n) < INFINITY) && ((n) > -INFINITY)) 253 | #endif 254 | 255 | #if HAVE_STRTOF 256 | #define SCPIDEFINE_strtof(n, p) strtof((n), (p)) 257 | #else 258 | #define SCPIDEFINE_strtof(n, p) strtod((n), (p)) 259 | #endif 260 | 261 | #if HAVE_STRTOLL 262 | #define SCPIDEFINE_strtoll(n, p, b) strtoll((n), (p), (b)) 263 | #define SCPIDEFINE_strtoull(n, p, b) strtoull((n), (p), (b)) 264 | #else 265 | #define SCPIDEFINE_strtoll(n, p, b) strtoll((n), (p), (b)) 266 | #define SCPIDEFINE_strtoull(n, p, b) strtoull((n), (p), (b)) 267 | extern long long int strtoll(const char *nptr, char **endptr, int base); 268 | extern unsigned long long int strtoull(const char *nptr, char **endptr, int base); 269 | /* TODO: implement OUR_strtoll and OUR_strtoull */ 270 | /* #warning "64bit string to int conversion not implemented" */ 271 | #endif 272 | 273 | #if HAVE_ISNAN 274 | #define SCPIDEFINE_isnan(n) isnan((n)) 275 | #else 276 | #define SCPIDEFINE_isnan(n) ((n) != (n)) 277 | #endif 278 | 279 | #ifndef NAN 280 | #define NAN (0.0 / 0.0) 281 | #endif 282 | 283 | #ifndef INFINITY 284 | #define INFINITY (1.0 / 0.0) 285 | #endif 286 | 287 | #ifdef __cplusplus 288 | } 289 | #endif 290 | 291 | #endif 292 | -------------------------------------------------------------------------------- /src/scpi/constants.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_constants.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI Device constants 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_CONSTANTS_H 39 | #define SCPI_CONSTANTS_H 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | /* 21.21 :VERSion? 46 | * YYYY.V 47 | * YYYY = SCPI year 48 | * V = SCPI revision 49 | */ 50 | #define SCPI_STD_VERSION_REVISION "1999.0" 51 | 52 | /* 21.8 :ERRor Subsystem 53 | * The maximum string length of plus is 255 characters. 54 | */ 55 | #define SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH 255 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif /* SCPI_CONSTANTS_H */ 62 | 63 | -------------------------------------------------------------------------------- /src/scpi/error.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_error.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief Error handling and storing routines 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_ERROR_H 39 | #define SCPI_ERROR_H 40 | 41 | #include "scpi/config.h" 42 | #include "scpi/types.h" 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size); 49 | void SCPI_ErrorClear(scpi_t * context); 50 | scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error); 51 | void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len); 52 | void SCPI_ErrorPush(scpi_t * context, int16_t err); 53 | int32_t SCPI_ErrorCount(scpi_t * context); 54 | const char * SCPI_ErrorTranslate(int16_t err); 55 | 56 | 57 | /* Using X-Macro technique to define everything once 58 | * http://en.wikipedia.org/wiki/X_Macro 59 | * 60 | * X macro is for minimal set of errors for library itself 61 | * XE macro is for full set of SCPI errors available to user application 62 | */ 63 | #define LIST_OF_ERRORS \ 64 | X(SCPI_ERROR_NO_ERROR, 0, "No error") \ 65 | XE(SCPI_ERROR_COMMAND, -100, "Command error") \ 66 | X(SCPI_ERROR_INVALID_CHARACTER, -101, "Invalid character") \ 67 | XE(SCPI_ERROR_SYNTAX, -102, "Syntax error") \ 68 | X(SCPI_ERROR_INVALID_SEPARATOR, -103, "Invalid separator") \ 69 | X(SCPI_ERROR_DATA_TYPE_ERROR, -104, "Data type error") \ 70 | XE(SCPI_ERROR_GET_NOT_ALLOWED, -105, "GET not allowed") \ 71 | X(SCPI_ERROR_PARAMETER_NOT_ALLOWED, -108, "Parameter not allowed") \ 72 | X(SCPI_ERROR_MISSING_PARAMETER, -109, "Missing parameter") \ 73 | XE(SCPI_ERROR_COMMAND_HEADER, -110, "Command header error") \ 74 | XE(SCPI_ERROR_HEADER_SEPARATOR, -111, "Header separator error") \ 75 | XE(SCPI_ERROR_PRG_MNEMONIC_TOO_LONG, -112, "Program mnemonic too long") \ 76 | X(SCPI_ERROR_UNDEFINED_HEADER, -113, "Undefined header") \ 77 | XE(SCPI_ERROR_HEADER_SUFFIX_OUTOFRANGE, -114, "Header suffix out of range") \ 78 | XE(SCPI_ERROR_UNEXP_NUM_OF_PARAMETER, -115, "Unexpected number of parameters") \ 79 | XE(SCPI_ERROR_NUMERIC_DATA_ERROR, -120, "Numeric data error") \ 80 | XE(SCPI_ERROR_INVAL_CHAR_IN_NUMBER, -121, "Invalid character in number") \ 81 | XE(SCPI_ERROR_EXPONENT_TOO_LONG, -123, "Exponent too large") \ 82 | XE(SCPI_ERROR_TOO_MANY_DIGITS, -124, "Too many digits") \ 83 | XE(SCPI_ERROR_NUMERIC_DATA_NOT_ALLOWED, -128, "Numeric data not allowed") \ 84 | XE(SCPI_ERROR_SUFFIX_ERROR, -130, "Suffix error") \ 85 | X(SCPI_ERROR_INVALID_SUFFIX, -131, "Invalid suffix") \ 86 | XE(SCPI_ERROR_SUFFIX_TOO_LONG, -134, "Suffix too long") \ 87 | X(SCPI_ERROR_SUFFIX_NOT_ALLOWED, -138, "Suffix not allowed") \ 88 | XE(SCPI_ERROR_CHARACTER_DATA_ERROR, -140, "Character data error") \ 89 | XE(SCPI_ERROR_INVAL_CHARACTER_DATA, -141, "Invalid character data") \ 90 | XE(SCPI_ERROR_CHARACTER_DATA_TOO_LONG, -144, "Character data too long") \ 91 | XE(SCPI_ERROR_CHARACTER_DATA_NOT_ALLOWED, -148, "Character data not allowed") \ 92 | XE(SCPI_ERROR_STRING_DATA_ERROR, -150, "String data error") \ 93 | X(SCPI_ERROR_INVALID_STRING_DATA, -151, "Invalid string data") \ 94 | XE(SCPI_ERROR_STRING_DATA_NOT_ALLOWED, -158, "String data not allowed") \ 95 | XE(SCPI_ERROR_BLOCK_DATA_ERROR, -160, "Block data error") \ 96 | XE(SCPI_ERROR_INVALID_BLOCK_DATA, -161, "Invalid block data") \ 97 | XE(SCPI_ERROR_BLOCK_DATA_NOT_ALLOWED, -168, "Block data not allowed") \ 98 | X(SCPI_ERROR_EXPRESSION_PARSING_ERROR, -170, "Expression error") \ 99 | XE(SCPI_ERROR_INVAL_EXPRESSION, -171, "Invalid expression") \ 100 | XE(SCPI_ERROR_EXPRESSION_DATA_NOT_ALLOWED, -178, "Expression data not allowed") \ 101 | XE(SCPI_ERROR_MACRO_DEFINITION_ERROR, -180, "Macro error") \ 102 | XE(SCPI_ERROR_INVAL_OUTSIDE_MACRO_DEF, -181, "Invalid outside macro definition") \ 103 | XE(SCPI_ERROR_INVAL_INSIDE_MACRO_DEF, -183, "Invalid inside macro definition") \ 104 | XE(SCPI_ERROR_MACRO_PARAMETER_ERROR, -184, "Macro parameter error") \ 105 | X(SCPI_ERROR_EXECUTION_ERROR, -200, "Execution error") \ 106 | XE(SCPI_ERROR_INVAL_WHILE_IN_LOCAL, -201, "Invalid while in local") \ 107 | XE(SCPI_ERROR_SETTINGS_LOST_DUE_TO_RTL, -202, "Settings lost due to rtl") \ 108 | XE(SCPI_ERROR_COMMAND_PROTECTED, -203, "Command protected") \ 109 | XE(SCPI_ERROR_TRIGGER_ERROR, -210, "Trigger error") \ 110 | XE(SCPI_ERROR_TRIGGER_IGNORED, -211, "Trigger ignored") \ 111 | XE(SCPI_ERROR_ARM_IGNORED, -212, "Arm ignored") \ 112 | XE(SCPI_ERROR_INIT_IGNORED, -213, "Init ignored") \ 113 | XE(SCPI_ERROR_TRIGGER_DEADLOCK, -214, "Trigger deadlock") \ 114 | XE(SCPI_ERROR_ARM_DEADLOCK, -215, "Arm deadlock") \ 115 | XE(SCPI_ERROR_PARAMETER_ERROR, -220, "Parameter error") \ 116 | XE(SCPI_ERROR_SETTINGS_CONFLICT, -221, "Settings conflict") \ 117 | XE(SCPI_ERROR_DATA_OUT_OF_RANGE, -222, "Data out of range") \ 118 | XE(SCPI_ERROR_TOO_MUCH_DATA, -223, "Too much data") \ 119 | X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE, -224, "Illegal parameter value") \ 120 | XE(SCPI_ERROR_OUT_OF_MEMORY_FOR_REQ_OP, -225, "Out of memory") \ 121 | XE(SCPI_ERROR_LISTS_NOT_SAME_LENGTH, -226, "Lists not same length") \ 122 | XE(SCPI_ERROR_DATA_CORRUPT, -230, "Data corrupt or stale") \ 123 | XE(SCPI_ERROR_DATA_QUESTIONABLE, -231, "Data questionable") \ 124 | XE(SCPI_ERROR_INVAL_VERSION, -233, "Invalid version") \ 125 | XE(SCPI_ERROR_HARDWARE_ERROR, -240, "Hardware error") \ 126 | XE(SCPI_ERROR_HARDWARE_MISSING, -241, "Hardware missing") \ 127 | XE(SCPI_ERROR_MASS_STORAGE_ERROR, -250, "Mass storage error") \ 128 | XE(SCPI_ERROR_MISSING_MASS_STORAGE, -251, "Missing mass storage") \ 129 | XE(SCPI_ERROR_MISSING_MASS_MEDIA, -252, "Missing media") \ 130 | XE(SCPI_ERROR_CORRUPT_MEDIA, -253, "Corrupt media") \ 131 | XE(SCPI_ERROR_MEDIA_FULL, -254, "Media full") \ 132 | XE(SCPI_ERROR_DIRECTORY_FULL, -255, "Directory full") \ 133 | XE(SCPI_ERROR_FILE_NAME_NOT_FOUND, -256, "File name not found") \ 134 | XE(SCPI_ERROR_FILE_NAME_ERROR, -257, "File name error") \ 135 | XE(SCPI_ERROR_MEDIA_PROTECTED, -258, "Media protected") \ 136 | XE(SCPI_ERROR_EXPRESSION_EXECUTING_ERROR, -260, "Expression error") \ 137 | XE(SCPI_ERROR_MATH_ERROR_IN_EXPRESSION, -261, "Math error in expression") \ 138 | XE(SCPI_ERROR_MACRO_UNDEF_EXEC_ERROR, -270, "Macro error") \ 139 | XE(SCPI_ERROR_MACRO_SYNTAX_ERROR, -271, "Macro syntax error") \ 140 | XE(SCPI_ERROR_MACRO_EXECUTION_ERROR, -272, "Macro execution error") \ 141 | XE(SCPI_ERROR_ILLEGAL_MACRO_LABEL, -273, "Illegal macro label") \ 142 | XE(SCPI_ERROR_IMPROPER_USED_MACRO_PARAM, -274, "Macro parameter error") \ 143 | XE(SCPI_ERROR_MACRO_DEFINITION_TOO_LONG, -275, "Macro definition too long") \ 144 | XE(SCPI_ERROR_MACRO_RECURSION_ERROR, -276, "Macro recursion error") \ 145 | XE(SCPI_ERROR_MACRO_REDEF_NOT_ALLOWED, -277, "Macro redefinition not allowed") \ 146 | XE(SCPI_ERROR_MACRO_HEADER_NOT_FOUND, -278, "Macro header not found") \ 147 | XE(SCPI_ERROR_PROGRAM_ERROR, -280, "Program error") \ 148 | XE(SCPI_ERROR_CANNOT_CREATE_PROGRAM, -281, "Cannot create program") \ 149 | XE(SCPI_ERROR_ILLEGAL_PROGRAM_NAME, -282, "Illegal program name") \ 150 | XE(SCPI_ERROR_ILLEGAL_VARIABLE_NAME, -283, "Illegal variable name") \ 151 | XE(SCPI_ERROR_PROGRAM_CURRENTLY_RUNNING, -284, "Program currently running") \ 152 | XE(SCPI_ERROR_PROGRAM_SYNTAX_ERROR, -285, "Program syntax error") \ 153 | XE(SCPI_ERROR_PROGRAM_RUNTIME_ERROR, -286, "Program runtime error") \ 154 | XE(SCPI_ERROR_MEMORY_USE_ERROR, -290, "Memory use error") \ 155 | XE(SCPI_ERROR_OUT_OF_MEMORY, -291, "Out of memory") \ 156 | XE(SCPI_ERROR_REF_NAME_DOES_NOT_EXIST, -292, "Referenced name does not exist") \ 157 | XE(SCPI_ERROR_REF_NAME_ALREADY_EXISTS, -293, "Referenced name already exists") \ 158 | XE(SCPI_ERROR_INCOMPATIBLE_TYPE, -294, "Incompatible type") \ 159 | XE(SCPI_ERROR_DEVICE_ERROR, -300, "Device specific error") \ 160 | X(SCPI_ERROR_SYSTEM_ERROR, -310, "System error") \ 161 | XE(SCPI_ERROR_MEMORY_ERROR, -311, "Memory error") \ 162 | XE(SCPI_ERROR_PUD_MEMORY_LOST, -312, "PUD memory lost") \ 163 | XE(SCPI_ERROR_CALIBRATION_MEMORY_LOST, -313, "Calibration memory lost") \ 164 | XE(SCPI_ERROR_SAVE_RECALL_MEMORY_LOST, -314, "Save/recall memory lost") \ 165 | XE(SCPI_ERROR_CONFIGURATION_MEMORY_LOST, -315, "Configuration memory lost") \ 166 | XE(SCPI_ERROR_STORAGE_FAULT, -320, "Storage fault") \ 167 | XE(SCPI_ERROR_OUT_OF_DEVICE_MEMORY, -321, "Out of memory") \ 168 | XE(SCPI_ERROR_SELF_TEST_FAILED, -330, "Self-test failed") \ 169 | XE(SCPI_ERROR_CALIBRATION_FAILED, -340, "Calibration failed") \ 170 | X(SCPI_ERROR_QUEUE_OVERFLOW, -350, "Queue overflow") \ 171 | XE(SCPI_ERROR_COMMUNICATION_ERROR, -360, "Communication error") \ 172 | XE(SCPI_ERROR_PARITY_ERROR_IN_CMD_MSG, -361, "Parity error in program message") \ 173 | XE(SCPI_ERROR_FRAMING_ERROR_IN_CMD_MSG, -362, "Framing error in program message") \ 174 | X(SCPI_ERROR_INPUT_BUFFER_OVERRUN, -363, "Input buffer overrun") \ 175 | XE(SCPI_ERROR_TIME_OUT, -365, "Time out error") \ 176 | XE(SCPI_ERROR_QUERY_ERROR, -400, "Query error") \ 177 | XE(SCPI_ERROR_QUERY_INTERRUPTED, -410, "Query INTERRUPTED") \ 178 | XE(SCPI_ERROR_QUERY_UNTERMINATED, -420, "Query UNTERMINATED") \ 179 | XE(SCPI_ERROR_QUERY_DEADLOCKED, -430, "Query DEADLOCKED") \ 180 | XE(SCPI_ERROR_QUERY_UNTERM_INDEF_RESP, -440, "Query UNTERMINATED after indefinite response") \ 181 | XE(SCPI_ERROR_POWER_ON, -500, "Power on") \ 182 | XE(SCPI_ERROR_USER_REQUEST, -600, "User request") \ 183 | XE(SCPI_ERROR_REQUEST_CONTROL, -700, "Request control") \ 184 | XE(SCPI_ERROR_OPERATION_COMPLETE, -800, "Operation complete") \ 185 | 186 | 187 | enum { 188 | #define X(def, val, str) def = val, 189 | #if USE_FULL_ERROR_LIST 190 | #define XE X 191 | #else 192 | #define XE(def, val, str) 193 | #endif 194 | LIST_OF_ERRORS 195 | 196 | #if USE_USER_ERROR_LIST 197 | LIST_OF_USER_ERRORS 198 | #endif 199 | #undef X 200 | #undef XE 201 | }; 202 | 203 | #ifdef __cplusplus 204 | } 205 | #endif 206 | 207 | #endif /* SCPI_ERROR_H */ 208 | 209 | -------------------------------------------------------------------------------- /src/scpi/expression.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file expression.h 31 | * 32 | * @brief Expressions handling 33 | * 34 | * 35 | */ 36 | #ifndef SCPI_EXPRESSION_H 37 | #define SCPI_EXPRESSION_H 38 | 39 | #include "scpi/config.h" 40 | #include "scpi/types.h" 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | enum _scpi_expr_result_t { 47 | SCPI_EXPR_OK = 0, 48 | SCPI_EXPR_ERROR, 49 | SCPI_EXPR_NO_MORE, 50 | }; 51 | typedef enum _scpi_expr_result_t scpi_expr_result_t; 52 | 53 | scpi_expr_result_t SCPI_ExprNumericListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, scpi_parameter_t * valueFrom, scpi_parameter_t * valueTo); 54 | scpi_expr_result_t SCPI_ExprNumericListEntryInt(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valueFrom, int32_t * valueTo); 55 | scpi_expr_result_t SCPI_ExprNumericListEntryDouble(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, double * valueFrom, double * valueTo); 56 | scpi_expr_result_t SCPI_ExprChannelListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #endif /* SCPI_EXPRESSION_H */ 63 | -------------------------------------------------------------------------------- /src/scpi/ieee488.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_ieee488.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief Implementation of IEEE488.2 commands and state model 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_IEEE488_H 39 | #define SCPI_IEEE488_H 40 | 41 | #include "scpi/types.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | scpi_result_t SCPI_CoreCls(scpi_t * context); 48 | scpi_result_t SCPI_CoreEse(scpi_t * context); 49 | scpi_result_t SCPI_CoreEseQ(scpi_t * context); 50 | scpi_result_t SCPI_CoreEsrQ(scpi_t * context); 51 | scpi_result_t SCPI_CoreIdnQ(scpi_t * context); 52 | scpi_result_t SCPI_CoreOpc(scpi_t * context); 53 | scpi_result_t SCPI_CoreOpcQ(scpi_t * context); 54 | scpi_result_t SCPI_CoreRst(scpi_t * context); 55 | scpi_result_t SCPI_CoreSre(scpi_t * context); 56 | scpi_result_t SCPI_CoreSreQ(scpi_t * context); 57 | scpi_result_t SCPI_CoreStbQ(scpi_t * context); 58 | scpi_result_t SCPI_CoreTstQ(scpi_t * context); 59 | scpi_result_t SCPI_CoreWai(scpi_t * context); 60 | 61 | 62 | #define STB_R01 0x01 /* Not used */ 63 | #define STB_PRO 0x02 /* Protection Event Flag */ 64 | #define STB_QMA 0x04 /* Error/Event queue message available */ 65 | #define STB_QES 0x08 /* Questionable status */ 66 | #define STB_MAV 0x10 /* Message Available */ 67 | #define STB_ESR 0x20 /* Standard Event Status Register */ 68 | #define STB_SRQ 0x40 /* Service Request */ 69 | #define STB_OPS 0x80 /* Operation Status Flag */ 70 | 71 | 72 | #define ESR_OPC 0x01 /* Operation complete */ 73 | #define ESR_REQ 0x02 /* Request Control */ 74 | #define ESR_QER 0x04 /* Query Error */ 75 | #define ESR_DER 0x08 /* Device Dependent Error */ 76 | #define ESR_EER 0x10 /* Execution Error (e.g. range error) */ 77 | #define ESR_CER 0x20 /* Command error (e.g. syntax error) */ 78 | #define ESR_URQ 0x40 /* User Request */ 79 | #define ESR_PON 0x80 /* Power On */ 80 | 81 | 82 | scpi_reg_val_t SCPI_RegGet(scpi_t * context, scpi_reg_name_t name); 83 | void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val); 84 | void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits); 85 | void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits); 86 | 87 | void SCPI_EventClear(scpi_t * context); 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | 93 | #endif /* SCPI_IEEE488_H */ 94 | 95 | -------------------------------------------------------------------------------- /src/scpi/minimal.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_minimal.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI minimal implementation 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_MINIMAL_H 39 | #define SCPI_MINIMAL_H 40 | 41 | #include "scpi/types.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | scpi_result_t SCPI_Stub(scpi_t * context); 48 | scpi_result_t SCPI_StubQ(scpi_t * context); 49 | 50 | scpi_result_t SCPI_SystemVersionQ(scpi_t * context); 51 | scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context); 52 | scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context); 53 | scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context); 54 | scpi_result_t SCPI_StatusQuestionableConditionQ(scpi_t * context); 55 | scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context); 56 | scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context); 57 | scpi_result_t SCPI_StatusOperationConditionQ(scpi_t * context); 58 | scpi_result_t SCPI_StatusOperationEventQ(scpi_t * context); 59 | scpi_result_t SCPI_StatusOperationEnableQ(scpi_t * context); 60 | scpi_result_t SCPI_StatusOperationEnable(scpi_t * context); 61 | scpi_result_t SCPI_StatusPreset(scpi_t * context); 62 | 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #endif /* SCPI_MINIMAL_H */ 69 | 70 | -------------------------------------------------------------------------------- /src/scpi/parser.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_parser.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI parser implementation 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_PARSER_H 39 | #define SCPI_PARSER_H 40 | 41 | #include 42 | #include "scpi/types.h" 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | void SCPI_Init(scpi_t * context, 48 | const scpi_command_t * commands, 49 | scpi_interface_t * interface, 50 | const scpi_unit_def_t * units, 51 | const char * idn1, const char * idn2, const char * idn3, const char * idn4, 52 | char * input_buffer, size_t input_buffer_length, 53 | scpi_error_t * error_queue_data, int16_t error_queue_size); 54 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE 55 | void SCPI_InitHeap(scpi_t * context, char * error_info_heap, size_t error_info_heap_length); 56 | #endif 57 | 58 | scpi_bool_t SCPI_Input(scpi_t * context, const char * data, int len); 59 | scpi_bool_t SCPI_Parse(scpi_t * context, char * data, int len); 60 | 61 | size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len); 62 | #define SCPI_ResultMnemonic(context, data) SCPI_ResultCharacters((context), (data), strlen(data)) 63 | #define SCPI_ResultUInt8Base(c, v, b) SCPI_ResultUInt32Base((c), (v), (uint8_t)(b)) 64 | #define SCPI_ResultUInt8(c, v) SCPI_ResultUInt32Base((c), (uint8_t)(v), 10) 65 | #define SCPI_ResultInt8(c, v) SCPI_ResultInt32((c), (int8_t)(v)) 66 | #define SCPI_ResultUInt16Base(c, v, b) SCPI_ResultUInt32Base((c), (uint16_t)(v), (b)) 67 | #define SCPI_ResultUInt16(c, v) SCPI_ResultUInt32Base((c), (uint16_t)(v), 10) 68 | #define SCPI_ResultInt16(c, v) SCPI_ResultInt32((c), (int16_t)(v)) 69 | size_t SCPI_ResultUInt32Base(scpi_t * context, uint32_t val, int8_t base); 70 | #define SCPI_ResultUInt32(c, v) SCPI_ResultUInt32Base((c), (v), 10) 71 | size_t SCPI_ResultInt32(scpi_t * context, int32_t val); 72 | size_t SCPI_ResultUInt64Base(scpi_t * context, uint64_t val, int8_t base); 73 | #define SCPI_ResultUInt64(c, v) SCPI_ResultUInt64Base((c), (v), 10) 74 | size_t SCPI_ResultInt64(scpi_t * context, int64_t val); 75 | size_t SCPI_ResultFloat(scpi_t * context, float val); 76 | size_t SCPI_ResultDouble(scpi_t * context, double val); 77 | size_t SCPI_ResultText(scpi_t * context, const char * data); 78 | size_t SCPI_ResultError(scpi_t * context, scpi_error_t * error); 79 | size_t SCPI_ResultArbitraryBlock(scpi_t * context, const void * data, size_t len); 80 | size_t SCPI_ResultArbitraryBlockHeader(scpi_t * context, size_t len); 81 | size_t SCPI_ResultArbitraryBlockData(scpi_t * context, const void * data, size_t len); 82 | size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val); 83 | 84 | size_t SCPI_ResultArrayInt8(scpi_t * context, const int8_t * array, size_t count, scpi_array_format_t format); 85 | size_t SCPI_ResultArrayUInt8(scpi_t * context, const uint8_t * array, size_t count, scpi_array_format_t format); 86 | size_t SCPI_ResultArrayInt16(scpi_t * context, const int16_t * array, size_t count, scpi_array_format_t format); 87 | size_t SCPI_ResultArrayUInt16(scpi_t * context, const uint16_t * array, size_t count, scpi_array_format_t format); 88 | size_t SCPI_ResultArrayInt32(scpi_t * context, const int32_t * array, size_t count, scpi_array_format_t format); 89 | size_t SCPI_ResultArrayUInt32(scpi_t * context, const uint32_t * array, size_t count, scpi_array_format_t format); 90 | size_t SCPI_ResultArrayInt64(scpi_t * context, const int64_t * array, size_t count, scpi_array_format_t format); 91 | size_t SCPI_ResultArrayUInt64(scpi_t * context, const uint64_t * array, size_t count, scpi_array_format_t format); 92 | size_t SCPI_ResultArrayFloat(scpi_t * context, const float * array, size_t count, scpi_array_format_t format); 93 | size_t SCPI_ResultArrayDouble(scpi_t * context, const double * array, size_t count, scpi_array_format_t format); 94 | 95 | scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory); 96 | scpi_bool_t SCPI_ParamIsValid(scpi_parameter_t * parameter); 97 | scpi_bool_t SCPI_ParamErrorOccurred(scpi_t * context); 98 | scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed); 99 | scpi_bool_t SCPI_ParamToInt32(scpi_t * context, scpi_parameter_t * parameter, int32_t * value); 100 | scpi_bool_t SCPI_ParamToUInt32(scpi_t * context, scpi_parameter_t * parameter, uint32_t * value); 101 | scpi_bool_t SCPI_ParamToInt64(scpi_t * context, scpi_parameter_t * parameter, int64_t * value); 102 | scpi_bool_t SCPI_ParamToUInt64(scpi_t * context, scpi_parameter_t * parameter, uint64_t * value); 103 | scpi_bool_t SCPI_ParamToFloat(scpi_t * context, scpi_parameter_t * parameter, float * value); 104 | scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value); 105 | scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value); 106 | scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text); 107 | 108 | scpi_bool_t SCPI_ParamInt32(scpi_t * context, int32_t * value, scpi_bool_t mandatory); 109 | scpi_bool_t SCPI_ParamUInt32(scpi_t * context, uint32_t * value, scpi_bool_t mandatory); 110 | scpi_bool_t SCPI_ParamInt64(scpi_t * context, int64_t * value, scpi_bool_t mandatory); 111 | scpi_bool_t SCPI_ParamUInt64(scpi_t * context, uint64_t * value, scpi_bool_t mandatory); 112 | scpi_bool_t SCPI_ParamFloat(scpi_t * context, float * value, scpi_bool_t mandatory); 113 | scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory); 114 | scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory); 115 | scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory); 116 | scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory); 117 | 118 | extern const scpi_choice_def_t scpi_bool_def[]; 119 | scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory); 120 | scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory); 121 | 122 | scpi_bool_t SCPI_ParamArrayInt32(scpi_t * context, int32_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory); 123 | scpi_bool_t SCPI_ParamArrayUInt32(scpi_t * context, uint32_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory); 124 | scpi_bool_t SCPI_ParamArrayInt64(scpi_t * context, int64_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory); 125 | scpi_bool_t SCPI_ParamArrayUInt64(scpi_t * context, uint64_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory); 126 | scpi_bool_t SCPI_ParamArrayFloat(scpi_t * context, float *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory); 127 | scpi_bool_t SCPI_ParamArrayDouble(scpi_t * context, double *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory); 128 | 129 | scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd); 130 | #if USE_COMMAND_TAGS 131 | int32_t SCPI_CmdTag(scpi_t * context); 132 | #endif /* USE_COMMAND_TAGS */ 133 | scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len); 134 | scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len, int32_t default_value); 135 | 136 | #if USE_DEPRECATED_FUNCTIONS 137 | /* deprecated finction, should be removed later */ 138 | #define SCPI_ResultIntBase(context, val, base) SCPI_ResultInt32Base ((context), (val), (base), TRUE) 139 | #define SCPI_ResultInt(context, val) SCPI_ResultInt32 ((context), (val)) 140 | #define SCPI_ParamToInt(context, parameter, value) SCPI_ParamToInt32((context), (parameter), (value)) 141 | #define SCPI_ParamToUnsignedInt(context, parameter, value) SCPI_ParamToUInt32((context), (parameter), (value)) 142 | #define SCPI_ParamInt(context, value, mandatory) SCPI_ParamInt32((context), (value), (mandatory)) 143 | #define SCPI_ParamUnsignedInt(context, value, mandatory) SCPI_ParamUInt32((context), (value), (mandatory)) 144 | #endif /* USE_DEPRECATED_FUNCTIONS */ 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | 150 | #endif /* SCPI_PARSER_H */ 151 | 152 | -------------------------------------------------------------------------------- /src/scpi/types.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer, Richard.hmm 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_types.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI data types 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_TYPES_H 39 | #define SCPI_TYPES_H 40 | 41 | #include 42 | #include 43 | #include "scpi/config.h" 44 | 45 | #if HAVE_STDBOOL 46 | #include 47 | #endif 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | #if !HAVE_STDBOOL 54 | typedef unsigned char bool; 55 | #endif 56 | 57 | #ifndef FALSE 58 | #define FALSE 0 59 | #endif 60 | #ifndef TRUE 61 | #define TRUE (!FALSE) 62 | #endif 63 | 64 | /* basic data types */ 65 | typedef bool scpi_bool_t; 66 | /* typedef enum { FALSE = 0, TRUE } scpi_bool_t; */ 67 | 68 | /* IEEE 488.2 registers */ 69 | enum _scpi_reg_name_t { 70 | SCPI_REG_STB = 0, /* Status Byte */ 71 | SCPI_REG_SRE, /* Service Request Enable Register */ 72 | SCPI_REG_ESR, /* Standard Event Status Register (ESR, SESR) */ 73 | SCPI_REG_ESE, /* Event Status Enable Register */ 74 | SCPI_REG_OPER, /* OPERation Status Register */ 75 | SCPI_REG_OPERE, /* OPERation Status Enable Register */ 76 | SCPI_REG_OPERC, /* OPERation Status Condition Register */ 77 | SCPI_REG_QUES, /* QUEStionable status register */ 78 | SCPI_REG_QUESE, /* QUEStionable status Enable Register */ 79 | SCPI_REG_QUESC, /* QUEStionable status Condition Register */ 80 | 81 | #if USE_CUSTOM_REGISTERS 82 | #ifndef USER_REGISTERS 83 | #error "No user registers defined" 84 | #else 85 | USER_REGISTERS 86 | #endif 87 | #endif 88 | 89 | /* number of registers */ 90 | SCPI_REG_COUNT, 91 | /* last definition - a value for no register */ 92 | SCPI_REG_NONE 93 | }; 94 | typedef enum _scpi_reg_name_t scpi_reg_name_t; 95 | 96 | enum _scpi_ctrl_name_t { 97 | SCPI_CTRL_SRQ = 1, /* service request */ 98 | SCPI_CTRL_GTL, /* Go to local */ 99 | SCPI_CTRL_SDC, /* Selected device clear */ 100 | SCPI_CTRL_PPC, /* Parallel poll configure */ 101 | SCPI_CTRL_GET, /* Group execute trigger */ 102 | SCPI_CTRL_TCT, /* Take control */ 103 | SCPI_CTRL_LLO, /* Device clear */ 104 | SCPI_CTRL_DCL, /* Local lockout */ 105 | SCPI_CTRL_PPU, /* Parallel poll unconfigure */ 106 | SCPI_CTRL_SPE, /* Serial poll enable */ 107 | SCPI_CTRL_SPD, /* Serial poll disable */ 108 | SCPI_CTRL_MLA, /* My local address */ 109 | SCPI_CTRL_UNL, /* Unlisten */ 110 | SCPI_CTRL_MTA, /* My talk address */ 111 | SCPI_CTRL_UNT, /* Untalk */ 112 | SCPI_CTRL_MSA /* My secondary address */ 113 | }; 114 | typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t; 115 | 116 | typedef uint16_t scpi_reg_val_t; 117 | 118 | enum _scpi_reg_class_t { 119 | SCPI_REG_CLASS_STB = 0, 120 | SCPI_REG_CLASS_SRE, 121 | SCPI_REG_CLASS_EVEN, 122 | SCPI_REG_CLASS_ENAB, 123 | SCPI_REG_CLASS_COND, 124 | SCPI_REG_CLASS_NTR, 125 | SCPI_REG_CLASS_PTR, 126 | }; 127 | typedef enum _scpi_reg_class_t scpi_reg_class_t; 128 | 129 | enum _scpi_reg_group_t { 130 | SCPI_REG_GROUP_STB = 0, 131 | SCPI_REG_GROUP_ESR, 132 | SCPI_REG_GROUP_OPER, 133 | SCPI_REG_GROUP_QUES, 134 | 135 | #if USE_CUSTOM_REGISTERS 136 | #ifndef USER_REGISTER_GROUPS 137 | #error "No user register groups defined" 138 | #else 139 | USER_REGISTER_GROUPS 140 | #endif 141 | #endif 142 | 143 | /* last definition - number of register groups */ 144 | SCPI_REG_GROUP_COUNT 145 | }; 146 | typedef enum _scpi_reg_group_t scpi_reg_group_t; 147 | 148 | struct _scpi_reg_info_t { 149 | scpi_reg_class_t type; 150 | scpi_reg_group_t group; 151 | }; 152 | typedef struct _scpi_reg_info_t scpi_reg_info_t; 153 | 154 | struct _scpi_reg_group_info_t { 155 | scpi_reg_name_t event; 156 | scpi_reg_name_t enable; 157 | scpi_reg_name_t condition; 158 | scpi_reg_name_t ptfilt; 159 | scpi_reg_name_t ntfilt; 160 | scpi_reg_name_t parent_reg; 161 | scpi_reg_val_t parent_bit; 162 | }; 163 | typedef struct _scpi_reg_group_info_t scpi_reg_group_info_t; 164 | 165 | /* scpi commands */ 166 | enum _scpi_result_t { 167 | SCPI_RES_OK = 1, 168 | SCPI_RES_ERR = -1 169 | }; 170 | typedef enum _scpi_result_t scpi_result_t; 171 | 172 | typedef struct _scpi_command_t scpi_command_t; 173 | 174 | #if USE_COMMAND_TAGS 175 | #define SCPI_CMD_LIST_END {NULL, NULL, 0} 176 | #else 177 | #define SCPI_CMD_LIST_END {NULL, NULL} 178 | #endif 179 | 180 | 181 | /* scpi interface */ 182 | typedef struct _scpi_t scpi_t; 183 | typedef struct _scpi_interface_t scpi_interface_t; 184 | 185 | struct _scpi_buffer_t { 186 | size_t length; 187 | size_t position; 188 | char * data; 189 | }; 190 | typedef struct _scpi_buffer_t scpi_buffer_t; 191 | 192 | struct _scpi_const_buffer_t { 193 | size_t length; 194 | size_t position; 195 | const char * data; 196 | }; 197 | typedef struct _scpi_const_buffer_t scpi_const_buffer_t; 198 | 199 | typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len); 200 | typedef scpi_result_t(*scpi_write_control_t)(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val); 201 | typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error); 202 | 203 | /* scpi lexer */ 204 | enum _scpi_token_type_t { 205 | SCPI_TOKEN_COMMA, 206 | SCPI_TOKEN_SEMICOLON, 207 | SCPI_TOKEN_COLON, 208 | SCPI_TOKEN_SPECIFIC_CHARACTER, 209 | SCPI_TOKEN_QUESTION, 210 | SCPI_TOKEN_NL, 211 | SCPI_TOKEN_HEXNUM, 212 | SCPI_TOKEN_OCTNUM, 213 | SCPI_TOKEN_BINNUM, 214 | SCPI_TOKEN_PROGRAM_MNEMONIC, 215 | SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA, 216 | SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX, 217 | SCPI_TOKEN_SUFFIX_PROGRAM_DATA, 218 | SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA, 219 | SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA, 220 | SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA, 221 | SCPI_TOKEN_PROGRAM_EXPRESSION, 222 | SCPI_TOKEN_COMPOUND_PROGRAM_HEADER, 223 | SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER, 224 | SCPI_TOKEN_COMMON_PROGRAM_HEADER, 225 | SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER, 226 | SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER, 227 | SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER, 228 | SCPI_TOKEN_WS, 229 | SCPI_TOKEN_ALL_PROGRAM_DATA, 230 | SCPI_TOKEN_INVALID, 231 | SCPI_TOKEN_UNKNOWN, 232 | }; 233 | typedef enum _scpi_token_type_t scpi_token_type_t; 234 | 235 | struct _scpi_token_t { 236 | scpi_token_type_t type; 237 | char * ptr; 238 | int len; 239 | }; 240 | typedef struct _scpi_token_t scpi_token_t; 241 | 242 | struct _lex_state_t { 243 | char * buffer; 244 | char * pos; 245 | int len; 246 | }; 247 | typedef struct _lex_state_t lex_state_t; 248 | 249 | /* scpi parser */ 250 | enum _message_termination_t { 251 | SCPI_MESSAGE_TERMINATION_NONE, 252 | SCPI_MESSAGE_TERMINATION_NL, 253 | SCPI_MESSAGE_TERMINATION_SEMICOLON, 254 | }; 255 | typedef enum _message_termination_t message_termination_t; 256 | 257 | struct _scpi_parser_state_t { 258 | scpi_token_t programHeader; 259 | scpi_token_t programData; 260 | int numberOfParameters; 261 | message_termination_t termination; 262 | }; 263 | typedef struct _scpi_parser_state_t scpi_parser_state_t; 264 | 265 | typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *); 266 | 267 | struct _scpi_error_info_heap_t { 268 | size_t wr; 269 | /* size_t rd; */ 270 | size_t count; 271 | size_t size; 272 | char * data; 273 | }; 274 | typedef struct _scpi_error_info_heap_t scpi_error_info_heap_t; 275 | 276 | struct _scpi_error_t { 277 | int16_t error_code; 278 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION 279 | char * device_dependent_info; 280 | #endif 281 | }; 282 | typedef struct _scpi_error_t scpi_error_t; 283 | 284 | struct _scpi_fifo_t { 285 | int16_t wr; 286 | int16_t rd; 287 | int16_t count; 288 | int16_t size; 289 | scpi_error_t * data; 290 | }; 291 | typedef struct _scpi_fifo_t scpi_fifo_t; 292 | 293 | /* scpi units */ 294 | enum _scpi_unit_t { 295 | SCPI_UNIT_NONE, 296 | SCPI_UNIT_VOLT, 297 | SCPI_UNIT_AMPER, 298 | SCPI_UNIT_OHM, 299 | SCPI_UNIT_HERTZ, 300 | SCPI_UNIT_CELSIUS, 301 | SCPI_UNIT_SECOND, 302 | SCPI_UNIT_METER, 303 | SCPI_UNIT_GRAY, 304 | SCPI_UNIT_BECQUEREL, 305 | SCPI_UNIT_MOLE, 306 | SCPI_UNIT_DEGREE, 307 | SCPI_UNIT_GRADE, 308 | SCPI_UNIT_RADIAN, 309 | SCPI_UNIT_REVOLUTION, 310 | SCPI_UNIT_STERADIAN, 311 | SCPI_UNIT_SIEVERT, 312 | SCPI_UNIT_FARAD, 313 | SCPI_UNIT_COULOMB, 314 | SCPI_UNIT_SIEMENS, 315 | SCPI_UNIT_ELECTRONVOLT, 316 | SCPI_UNIT_JOULE, 317 | SCPI_UNIT_NEWTON, 318 | SCPI_UNIT_LUX, 319 | SCPI_UNIT_HENRY, 320 | SCPI_UNIT_ASTRONOMIC_UNIT, 321 | SCPI_UNIT_INCH, 322 | SCPI_UNIT_FOOT, 323 | SCPI_UNIT_PARSEC, 324 | SCPI_UNIT_MILE, 325 | SCPI_UNIT_NAUTICAL_MILE, 326 | SCPI_UNIT_LUMEN, 327 | SCPI_UNIT_CANDELA, 328 | SCPI_UNIT_WEBER, 329 | SCPI_UNIT_TESLA, 330 | SCPI_UNIT_ATOMIC_MASS, 331 | SCPI_UNIT_KILOGRAM, 332 | SCPI_UNIT_WATT, 333 | SCPI_UNIT_DBM, 334 | SCPI_UNIT_ATMOSPHERE, 335 | SCPI_UNIT_INCH_OF_MERCURY, 336 | SCPI_UNIT_MM_OF_MERCURY, 337 | SCPI_UNIT_PASCAL, 338 | SCPI_UNIT_TORT, 339 | SCPI_UNIT_BAR, 340 | SCPI_UNIT_DECIBEL, 341 | SCPI_UNIT_UNITLESS, 342 | SCPI_UNIT_FAHRENHEIT, 343 | SCPI_UNIT_KELVIN, 344 | SCPI_UNIT_DAY, 345 | SCPI_UNIT_YEAR, 346 | SCPI_UNIT_STROKES, 347 | SCPI_UNIT_POISE, 348 | SCPI_UNIT_LITER 349 | }; 350 | typedef enum _scpi_unit_t scpi_unit_t; 351 | 352 | struct _scpi_unit_def_t { 353 | const char * name; 354 | scpi_unit_t unit; 355 | double mult; 356 | }; 357 | #define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0} 358 | typedef struct _scpi_unit_def_t scpi_unit_def_t; 359 | 360 | enum _scpi_special_number_t { 361 | SCPI_NUM_NUMBER, 362 | SCPI_NUM_MIN, 363 | SCPI_NUM_MAX, 364 | SCPI_NUM_DEF, 365 | SCPI_NUM_UP, 366 | SCPI_NUM_DOWN, 367 | SCPI_NUM_NAN, 368 | SCPI_NUM_INF, 369 | SCPI_NUM_NINF, 370 | SCPI_NUM_AUTO 371 | }; 372 | typedef enum _scpi_special_number_t scpi_special_number_t; 373 | 374 | struct _scpi_choice_def_t { 375 | const char * name; 376 | int32_t tag; 377 | }; 378 | #define SCPI_CHOICE_LIST_END {NULL, -1} 379 | typedef struct _scpi_choice_def_t scpi_choice_def_t; 380 | 381 | struct _scpi_param_list_t { 382 | const scpi_command_t * cmd; 383 | lex_state_t lex_state; 384 | scpi_const_buffer_t cmd_raw; 385 | }; 386 | typedef struct _scpi_param_list_t scpi_param_list_t; 387 | 388 | struct _scpi_number_parameter_t { 389 | scpi_bool_t special; 390 | 391 | union { 392 | double value; 393 | int32_t tag; 394 | } content; 395 | scpi_unit_t unit; 396 | int8_t base; 397 | }; 398 | typedef struct _scpi_number_parameter_t scpi_number_t; 399 | 400 | struct _scpi_data_parameter_t { 401 | const char * ptr; 402 | int32_t len; 403 | }; 404 | typedef struct _scpi_data_parameter_t scpi_data_parameter_t; 405 | 406 | typedef scpi_token_t scpi_parameter_t; 407 | 408 | struct _scpi_command_t { 409 | const char * pattern; 410 | scpi_command_callback_t callback; 411 | #if USE_COMMAND_TAGS 412 | int32_t tag; 413 | #endif /* USE_COMMAND_TAGS */ 414 | }; 415 | 416 | struct _scpi_interface_t { 417 | scpi_error_callback_t error; 418 | scpi_write_t write; 419 | scpi_write_control_t control; 420 | scpi_command_callback_t flush; 421 | scpi_command_callback_t reset; 422 | }; 423 | 424 | struct _scpi_t { 425 | const scpi_command_t * cmdlist; 426 | scpi_buffer_t buffer; 427 | scpi_param_list_t param_list; 428 | scpi_interface_t * interface; 429 | int_fast16_t output_count; 430 | int_fast16_t input_count; 431 | scpi_bool_t first_output; 432 | scpi_bool_t cmd_error; 433 | scpi_fifo_t error_queue; 434 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE 435 | scpi_error_info_heap_t error_info_heap; 436 | #endif 437 | scpi_reg_val_t registers[SCPI_REG_COUNT]; 438 | const scpi_unit_def_t * units; 439 | void * user_context; 440 | scpi_parser_state_t parser_state; 441 | const char * idn[4]; 442 | size_t arbitrary_remaining; 443 | }; 444 | 445 | enum _scpi_array_format_t { 446 | SCPI_FORMAT_ASCII = 0, 447 | SCPI_FORMAT_NORMAL = 1, 448 | SCPI_FORMAT_SWAPPED = 2, 449 | SCPI_FORMAT_BIGENDIAN = SCPI_FORMAT_NORMAL, 450 | SCPI_FORMAT_LITTLEENDIAN = SCPI_FORMAT_SWAPPED, 451 | }; 452 | typedef enum _scpi_array_format_t scpi_array_format_t; 453 | 454 | #ifdef __cplusplus 455 | } 456 | #endif 457 | 458 | #endif /* SCPI_TYPES_H */ 459 | 460 | -------------------------------------------------------------------------------- /src/scpi/units.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_units.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI Units 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_UNITS_H 39 | #define SCPI_UNITS_H 40 | 41 | #include "scpi/types.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | extern const scpi_unit_def_t scpi_units_def[]; 48 | extern const scpi_choice_def_t scpi_special_numbers_def[]; 49 | 50 | scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory); 51 | 52 | scpi_bool_t SCPI_ParamTranslateNumberVal(scpi_t * context, scpi_parameter_t * parameter); 53 | size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif /* SCPI_UNITS_H */ 60 | 61 | -------------------------------------------------------------------------------- /src/scpi/utils.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file utils.h 31 | * 32 | * @brief Conversion routines and string manipulation routines 33 | * 34 | * 35 | */ 36 | 37 | #ifndef SCPI_UTILS_H 38 | #define SCPI_UTILS_H 39 | 40 | #include 41 | #include "scpi/types.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | size_t SCPI_UInt32ToStrBase(uint32_t val, char * str, size_t len, int8_t base); 48 | size_t SCPI_Int32ToStr(int32_t val, char * str, size_t len); 49 | size_t SCPI_UInt64ToStrBase(uint64_t val, char * str, size_t len, int8_t base); 50 | size_t SCPI_Int64ToStr(int64_t val, char * str, size_t len); 51 | size_t SCPI_FloatToStr(float val, char * str, size_t len); 52 | size_t SCPI_DoubleToStr(double val, char * str, size_t len); 53 | 54 | /* deprecated finction, should be removed later */ 55 | #define SCPI_LongToStr(val, str, len, base) SCPI_Int32ToStr((val), (str), (len), (base), TRUE) 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif /* SCPI_UTILS_H */ 62 | 63 | -------------------------------------------------------------------------------- /src/src/error.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | /** 29 | * @file scpi_error.c 30 | * @date Thu Nov 15 10:58:45 UTC 2012 31 | * 32 | * @brief Error handling and storing routines 33 | * 34 | * 35 | */ 36 | 37 | #include 38 | 39 | #include "scpi/parser.h" 40 | #include "scpi/ieee488.h" 41 | #include "scpi/error.h" 42 | #include "fifo_private.h" 43 | #include "scpi/constants.h" 44 | 45 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION 46 | #define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (e)->device_dependent_info = (i); } while(0) 47 | #else 48 | #define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (void)(i);} while(0) 49 | #endif 50 | 51 | /** 52 | * Initialize error queue 53 | * @param context - scpi context 54 | */ 55 | void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size) { 56 | fifo_init(&context->error_queue, data, size); 57 | } 58 | 59 | /** 60 | * Emit no error 61 | * @param context scpi context 62 | */ 63 | static void SCPI_ErrorEmitEmpty(scpi_t * context) { 64 | if ((SCPI_ErrorCount(context) == 0) && (SCPI_RegGet(context, SCPI_REG_STB) & STB_QMA)) { 65 | SCPI_RegClearBits(context, SCPI_REG_STB, STB_QMA); 66 | 67 | if (context->interface && context->interface->error) { 68 | context->interface->error(context, 0); 69 | } 70 | } 71 | } 72 | 73 | /** 74 | * Emit error 75 | * @param context scpi context 76 | * @param err Error to emit 77 | */ 78 | static void SCPI_ErrorEmit(scpi_t * context, int16_t err) { 79 | SCPI_RegSetBits(context, SCPI_REG_STB, STB_QMA); 80 | 81 | if (context->interface && context->interface->error) { 82 | context->interface->error(context, err); 83 | } 84 | } 85 | 86 | /** 87 | * Clear error queue 88 | * @param context - scpi context 89 | */ 90 | void SCPI_ErrorClear(scpi_t * context) { 91 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION 92 | scpi_error_t error; 93 | while (fifo_remove(&context->error_queue, &error)) { 94 | SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false); 95 | } 96 | #endif 97 | fifo_clear(&context->error_queue); 98 | 99 | SCPI_ErrorEmitEmpty(context); 100 | } 101 | 102 | /** 103 | * Pop error from queue 104 | * @param context - scpi context 105 | * @param error 106 | * @return 107 | */ 108 | scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error) { 109 | if (!error || !context) return FALSE; 110 | SCPI_ERROR_SETVAL(error, 0, NULL); 111 | fifo_remove(&context->error_queue, error); 112 | 113 | SCPI_ErrorEmitEmpty(context); 114 | 115 | return TRUE; 116 | } 117 | 118 | /** 119 | * Return number of errors/events in the queue 120 | * @param context 121 | * @return 122 | */ 123 | int32_t SCPI_ErrorCount(scpi_t * context) { 124 | int16_t result = 0; 125 | 126 | fifo_count(&context->error_queue, &result); 127 | 128 | return result; 129 | } 130 | 131 | static scpi_bool_t SCPI_ErrorAddInternal(scpi_t * context, int16_t err, char * info, size_t info_len) { 132 | scpi_error_t error_value; 133 | /* SCPIDEFINE_strndup is sometimes a dumy that does not reference it's arguments. 134 | Since info_len is not referenced elsewhere caoing to void prevents unusd argument warnings */ 135 | (void) info_len; 136 | char * info_ptr = NULL; 137 | if (info) { 138 | info_ptr = SCPIDEFINE_strndup(&context->error_info_heap, info, info_len); 139 | } 140 | SCPI_ERROR_SETVAL(&error_value, err, info_ptr); 141 | if (!fifo_add(&context->error_queue, &error_value)) { 142 | SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true); 143 | fifo_remove_last(&context->error_queue, &error_value); 144 | SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true); 145 | SCPI_ERROR_SETVAL(&error_value, SCPI_ERROR_QUEUE_OVERFLOW, NULL); 146 | fifo_add(&context->error_queue, &error_value); 147 | return FALSE; 148 | } 149 | return TRUE; 150 | } 151 | 152 | struct error_reg { 153 | int16_t from; 154 | int16_t to; 155 | scpi_reg_val_t esrBit; 156 | }; 157 | 158 | #define ERROR_DEFS_N 9 159 | 160 | static const struct error_reg errs[ERROR_DEFS_N] = { 161 | {-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9 */ 162 | {-200, -299, ESR_EER}, /* Execution Error (e.g. range error) ch 21.8.10 */ 163 | {-300, -399, ESR_DER}, /* Device specific error -300, -399 ch 21.8.11 */ 164 | { 1, 32767, ESR_DER}, /* Device designer provided specific error 1, 32767 ch 21.8.11 */ 165 | {-400, -499, ESR_QER}, /* Query error -400, -499 ch 21.8.12 */ 166 | {-500, -599, ESR_PON}, /* Power on event -500, -599 ch 21.8.13 */ 167 | {-600, -699, ESR_URQ}, /* User Request Event -600, -699 ch 21.8.14 */ 168 | {-700, -799, ESR_REQ}, /* Request Control Event -700, -799 ch 21.8.15 */ 169 | {-800, -899, ESR_OPC}, /* Operation Complete Event -800, -899 ch 21.8.16 */ 170 | }; 171 | 172 | /** 173 | * Push error to queue 174 | * @param context 175 | * @param err - error number 176 | * @param info - additional text information or NULL for no text 177 | * @param info_len - length of text or 0 for automatic length 178 | */ 179 | void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len) { 180 | int i; 181 | /* automatic calculation of length */ 182 | if (info && info_len == 0) { 183 | info_len = SCPIDEFINE_strnlen(info, SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH); 184 | } 185 | scpi_bool_t queue_overflow = !SCPI_ErrorAddInternal(context, err, info, info_len); 186 | 187 | for (i = 0; i < ERROR_DEFS_N; i++) { 188 | if ((err <= errs[i].from) && (err >= errs[i].to)) { 189 | SCPI_RegSetBits(context, SCPI_REG_ESR, errs[i].esrBit); 190 | } 191 | } 192 | 193 | SCPI_ErrorEmit(context, err); 194 | if (queue_overflow) { 195 | SCPI_ErrorEmit(context, SCPI_ERROR_QUEUE_OVERFLOW); 196 | } 197 | 198 | if (context) { 199 | context->cmd_error = TRUE; 200 | } 201 | } 202 | 203 | /** 204 | * Push error to queue 205 | * @param context - scpi context 206 | * @param err - error number 207 | */ 208 | void SCPI_ErrorPush(scpi_t * context, int16_t err) { 209 | SCPI_ErrorPushEx(context, err, NULL, 0); 210 | return; 211 | } 212 | 213 | /** 214 | * Translate error number to string 215 | * @param err - error number 216 | * @return Error string representation 217 | */ 218 | const char * SCPI_ErrorTranslate(int16_t err) { 219 | switch (err) { 220 | #define X(def, val, str) case def: return str; 221 | #if USE_FULL_ERROR_LIST 222 | #define XE X 223 | #else 224 | #define XE(def, val, str) 225 | #endif 226 | LIST_OF_ERRORS 227 | 228 | #if USE_USER_ERROR_LIST 229 | LIST_OF_USER_ERRORS 230 | #endif 231 | #undef X 232 | #undef XE 233 | default: return "Unknown error"; 234 | } 235 | } 236 | 237 | 238 | -------------------------------------------------------------------------------- /src/src/expression.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file expression.c 31 | * 32 | * @brief Expressions handling 33 | * 34 | * 35 | */ 36 | 37 | #include "scpi/expression.h" 38 | #include "scpi/error.h" 39 | #include "scpi/parser.h" 40 | 41 | #include "lexer_private.h" 42 | 43 | /** 44 | * Parse one range or single value 45 | * @param state lexer state 46 | * @param isRange return true if parsed expression is range 47 | * @param valueFrom return parsed value from 48 | * @param valueTo return parsed value to 49 | * @return SCPI_EXPR_OK - parsing was succesful 50 | * SCPI_EXPR_ERROR - parser error 51 | * SCPI_EXPR_NO_MORE - no more data 52 | */ 53 | static scpi_expr_result_t numericRange(lex_state_t * state, scpi_bool_t * isRange, scpi_token_t * valueFrom, scpi_token_t * valueTo) { 54 | if (scpiLex_DecimalNumericProgramData(state, valueFrom)) { 55 | if (scpiLex_Colon(state, valueTo)) { 56 | *isRange = TRUE; 57 | if (scpiLex_DecimalNumericProgramData(state, valueTo)) { 58 | return SCPI_EXPR_OK; 59 | } else { 60 | return SCPI_EXPR_ERROR; 61 | } 62 | } else { 63 | *isRange = FALSE; 64 | return SCPI_EXPR_OK; 65 | } 66 | } 67 | 68 | return SCPI_EXPR_NO_MORE; 69 | } 70 | 71 | /** 72 | * Parse entry on specified position 73 | * @param context scpi context 74 | * @param param input parameter 75 | * @param index index of position (start from 0) 76 | * @param isRange return true if expression at index was range 77 | * @param valueFrom return value from 78 | * @param valueTo return value to 79 | * @return SCPI_EXPR_OK - parsing was succesful 80 | * SCPI_EXPR_ERROR - parser error 81 | * SCPI_EXPR_NO_MORE - no more data 82 | * @see SCPI_ExprNumericListEntryInt, SCPI_ExprNumericListEntryDouble 83 | */ 84 | scpi_expr_result_t SCPI_ExprNumericListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, scpi_parameter_t * valueFrom, scpi_parameter_t * valueTo) { 85 | lex_state_t lex; 86 | int i; 87 | scpi_expr_result_t res = SCPI_EXPR_OK; 88 | 89 | if (!isRange || !valueFrom || !valueTo || !param) { 90 | SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 91 | return SCPI_EXPR_ERROR; 92 | } 93 | 94 | if (param->type != SCPI_TOKEN_PROGRAM_EXPRESSION) { 95 | SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 96 | return SCPI_EXPR_ERROR; 97 | } 98 | 99 | lex.buffer = param->ptr + 1; 100 | lex.pos = lex.buffer; 101 | lex.len = param->len - 2; 102 | 103 | for (i = 0; i <= index; i++) { 104 | res = numericRange(&lex, isRange, valueFrom, valueTo); 105 | if (res != SCPI_EXPR_OK) { 106 | break; 107 | } 108 | if (i != index) { 109 | if (!scpiLex_Comma(&lex, valueFrom)) { 110 | res = scpiLex_IsEos(&lex) ? SCPI_EXPR_NO_MORE : SCPI_EXPR_ERROR; 111 | break; 112 | } 113 | } 114 | } 115 | 116 | if (res == SCPI_EXPR_ERROR) { 117 | SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR); 118 | } 119 | return res; 120 | } 121 | 122 | /** 123 | * Parse entry on specified position and convert result to int32_t 124 | * @param context scpi context 125 | * @param param input parameter 126 | * @param index index of position (start from 0) 127 | * @param isRange return true if expression at index was range 128 | * @param valueFrom return value from 129 | * @param valueTo return value to 130 | * @return SCPI_EXPR_OK - parsing was succesful 131 | * SCPI_EXPR_ERROR - parser error 132 | * SCPI_EXPR_NO_MORE - no more data 133 | * @see SCPI_ExprNumericListEntry, SCPI_ExprNumericListEntryDouble 134 | */ 135 | scpi_expr_result_t SCPI_ExprNumericListEntryInt(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valueFrom, int32_t * valueTo) { 136 | scpi_expr_result_t res; 137 | scpi_bool_t range = FALSE; 138 | scpi_parameter_t paramFrom; 139 | scpi_parameter_t paramTo; 140 | 141 | res = SCPI_ExprNumericListEntry(context, param, index, &range, ¶mFrom, ¶mTo); 142 | if (res == SCPI_EXPR_OK) { 143 | *isRange = range; 144 | SCPI_ParamToInt32(context, ¶mFrom, valueFrom); 145 | if (range) { 146 | SCPI_ParamToInt32(context, ¶mTo, valueTo); 147 | } 148 | } 149 | 150 | return res; 151 | } 152 | 153 | /** 154 | * Parse entry on specified position and convert result to double 155 | * @param context scpi context 156 | * @param param input parameter 157 | * @param index index of position (start from 0) 158 | * @param isRange return true if expression at index was range 159 | * @param valueFrom return value from 160 | * @param valueTo return value to 161 | * @return SCPI_EXPR_OK - parsing was succesful 162 | * SCPI_EXPR_ERROR - parser error 163 | * SCPI_EXPR_NO_MORE - no more data 164 | * @see SCPI_ExprNumericListEntry, SCPI_ExprNumericListEntryInt 165 | */ 166 | scpi_expr_result_t SCPI_ExprNumericListEntryDouble(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, double * valueFrom, double * valueTo) { 167 | scpi_expr_result_t res; 168 | scpi_bool_t range = FALSE; 169 | scpi_parameter_t paramFrom; 170 | scpi_parameter_t paramTo; 171 | 172 | res = SCPI_ExprNumericListEntry(context, param, index, &range, ¶mFrom, ¶mTo); 173 | if (res == SCPI_EXPR_OK) { 174 | *isRange = range; 175 | SCPI_ParamToDouble(context, ¶mFrom, valueFrom); 176 | if (range) { 177 | SCPI_ParamToDouble(context, ¶mTo, valueTo); 178 | } 179 | } 180 | 181 | return res; 182 | } 183 | 184 | /** 185 | * Parse one channel_spec e.g. "1!5!8" 186 | * @param context 187 | * @param state lexer state 188 | * @param values range values 189 | * @param length length of values array 190 | * @param dimensions real number of dimensions 191 | */ 192 | static scpi_expr_result_t channelSpec(scpi_t * context, lex_state_t * state, int32_t * values, size_t length, size_t * dimensions) { 193 | scpi_parameter_t param; 194 | size_t i = 0; 195 | while (scpiLex_DecimalNumericProgramData(state, ¶m)) { 196 | if (i < length) { 197 | SCPI_ParamToInt32(context, ¶m, &values[i]); 198 | } 199 | 200 | if (scpiLex_SpecificCharacter(state, ¶m, '!')) { 201 | i++; 202 | } else { 203 | *dimensions = i + 1; 204 | return SCPI_EXPR_OK; 205 | } 206 | } 207 | 208 | if (i == 0) { 209 | return SCPI_EXPR_NO_MORE; 210 | } else { 211 | /* there was at least one number followed by !, but after ! was not another number */ 212 | return SCPI_EXPR_ERROR; 213 | } 214 | } 215 | 216 | /** 217 | * Parse channel_range e.g. "1!2:5!6" 218 | * @param context 219 | * @param state lexer state 220 | * @param isRange return true if it is range 221 | * @param valuesFrom return array of values from 222 | * @param valuesTo return array of values to 223 | * @param length length of values arrays 224 | * @param dimensions real number of dimensions 225 | */ 226 | static scpi_expr_result_t channelRange(scpi_t * context, lex_state_t * state, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions) { 227 | scpi_token_t token; 228 | scpi_expr_result_t err; 229 | size_t fromDimensions; 230 | size_t toDimensions; 231 | 232 | err = channelSpec(context, state, valuesFrom, length, &fromDimensions); 233 | if (err == SCPI_EXPR_OK) { 234 | if (scpiLex_Colon(state, &token)) { 235 | *isRange = TRUE; 236 | err = channelSpec(context, state, valuesTo, length, &toDimensions); 237 | if (err != SCPI_EXPR_OK) { 238 | return SCPI_EXPR_ERROR; 239 | } 240 | if (fromDimensions != toDimensions) { 241 | return SCPI_EXPR_ERROR; 242 | } 243 | *dimensions = fromDimensions; 244 | } else { 245 | *isRange = FALSE; 246 | *dimensions = fromDimensions; 247 | return SCPI_EXPR_OK; 248 | } 249 | } else if (err == SCPI_EXPR_NO_MORE) { 250 | err = SCPI_EXPR_ERROR; 251 | } 252 | 253 | return err; 254 | } 255 | 256 | /** 257 | * Parse one list entry at specific position e.g. "1!2:5!6" 258 | * @param context 259 | * @param param 260 | * @param index 261 | * @param isRange return true if it is range 262 | * @param valuesFrom return array of values from 263 | * @param valuesTo return array of values to 264 | * @param length length of values arrays 265 | * @param dimensions real number of dimensions 266 | */ 267 | scpi_expr_result_t SCPI_ExprChannelListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions) { 268 | lex_state_t lex; 269 | int i; 270 | scpi_expr_result_t res = SCPI_EXPR_OK; 271 | scpi_token_t token; 272 | 273 | if (!isRange || !param || !dimensions || (length && (!valuesFrom || !valuesTo))) { 274 | SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 275 | return SCPI_EXPR_ERROR; 276 | } 277 | 278 | if (param->type != SCPI_TOKEN_PROGRAM_EXPRESSION) { 279 | SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 280 | return SCPI_EXPR_ERROR; 281 | } 282 | 283 | lex.buffer = param->ptr + 1; 284 | lex.pos = lex.buffer; 285 | lex.len = param->len - 2; 286 | 287 | /* detect channel list expression */ 288 | if (!scpiLex_SpecificCharacter(&lex, &token, '@')) { 289 | SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR); 290 | return SCPI_EXPR_ERROR; 291 | } 292 | 293 | for (i = 0; i <= index; i++) { 294 | res = channelRange(context, &lex, isRange, valuesFrom, valuesTo, (i == index) ? length : 0, dimensions); 295 | if (res != SCPI_EXPR_OK) { 296 | break; 297 | } 298 | if (i != index) { 299 | if (!scpiLex_Comma(&lex, &token)) { 300 | res = scpiLex_IsEos(&lex) ? SCPI_EXPR_NO_MORE : SCPI_EXPR_ERROR; 301 | break; 302 | } 303 | } 304 | } 305 | 306 | if (res == SCPI_EXPR_ERROR) { 307 | SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR); 308 | } 309 | if (res == SCPI_EXPR_NO_MORE) { 310 | if (!scpiLex_IsEos(&lex)) { 311 | res = SCPI_EXPR_ERROR; 312 | SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR); 313 | } 314 | } 315 | return res; 316 | } 317 | -------------------------------------------------------------------------------- /src/src/fifo.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "fifo_private.h" 30 | 31 | /** 32 | * Initialize fifo 33 | * @param fifo 34 | */ 35 | void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) { 36 | fifo->wr = 0; 37 | fifo->rd = 0; 38 | fifo->count = 0; 39 | fifo->data = data; 40 | fifo->size = size; 41 | } 42 | 43 | /** 44 | * Empty fifo 45 | * @param fifo 46 | */ 47 | void fifo_clear(scpi_fifo_t * fifo) { 48 | fifo->wr = 0; 49 | fifo->rd = 0; 50 | fifo->count = 0; 51 | } 52 | 53 | /** 54 | * Test if fifo is empty 55 | * @param fifo 56 | * @return 57 | */ 58 | scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) { 59 | return fifo->count == 0; 60 | } 61 | 62 | /** 63 | * Test if fifo is full 64 | * @param fifo 65 | * @return 66 | */ 67 | scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) { 68 | return fifo->count == fifo->size; 69 | } 70 | 71 | /** 72 | * Add element to fifo. If fifo is full, return FALSE. 73 | * @param fifo 74 | * @param err 75 | * @param info 76 | * @return 77 | */ 78 | scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) { 79 | /* FIFO full? */ 80 | if (fifo_is_full(fifo)) { 81 | return FALSE; 82 | } 83 | if (!value) { 84 | return FALSE; 85 | } 86 | 87 | fifo->data[fifo->wr] = *value; 88 | fifo->wr = (fifo->wr + 1) % (fifo->size); 89 | fifo->count += 1; 90 | return TRUE; 91 | } 92 | 93 | /** 94 | * Remove element form fifo 95 | * @param fifo 96 | * @param value 97 | * @return FALSE - fifo is empty 98 | */ 99 | scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) { 100 | /* FIFO empty? */ 101 | if (fifo_is_empty(fifo)) { 102 | return FALSE; 103 | } 104 | 105 | if (value) { 106 | *value = fifo->data[fifo->rd]; 107 | } 108 | 109 | fifo->rd = (fifo->rd + 1) % (fifo->size); 110 | fifo->count -= 1; 111 | 112 | return TRUE; 113 | } 114 | 115 | /** 116 | * Remove last element from fifo 117 | * @param fifo 118 | * @param value 119 | * @return FALSE - fifo is empty 120 | */ 121 | scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) { 122 | /* FIFO empty? */ 123 | if (fifo_is_empty(fifo)) { 124 | return FALSE; 125 | } 126 | 127 | fifo->wr = (fifo->wr + fifo->size - 1) % (fifo->size); 128 | 129 | if (value) { 130 | *value = fifo->data[fifo->wr]; 131 | } 132 | fifo->count -= 1; 133 | 134 | return TRUE; 135 | } 136 | 137 | /** 138 | * Retrive number of elements in fifo 139 | * @param fifo 140 | * @param value 141 | * @return 142 | */ 143 | scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) { 144 | *value = fifo->count; 145 | return TRUE; 146 | } 147 | -------------------------------------------------------------------------------- /src/src/fifo_private.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_fifo.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief basic FIFO implementation 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_FIFO_H 39 | #define SCPI_FIFO_H 40 | 41 | #include "scpi/types.h" 42 | #include "utils_private.h" 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) LOCAL; 49 | void fifo_clear(scpi_fifo_t * fifo) LOCAL; 50 | scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) LOCAL; 51 | scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) LOCAL; 52 | scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) LOCAL; 53 | scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) LOCAL; 54 | scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) LOCAL; 55 | scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) LOCAL; 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif /* SCPI_FIFO_H */ 62 | -------------------------------------------------------------------------------- /src/src/ieee488.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_ieee488.c 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief Implementation of IEEE488.2 commands and state model 34 | * 35 | * 36 | */ 37 | 38 | #include "scpi/parser.h" 39 | #include "scpi/ieee488.h" 40 | #include "scpi/error.h" 41 | #include "scpi/constants.h" 42 | 43 | #include 44 | 45 | static const scpi_reg_info_t scpi_reg_details[SCPI_REG_COUNT] = { 46 | { SCPI_REG_CLASS_STB, SCPI_REG_GROUP_STB }, 47 | { SCPI_REG_CLASS_SRE, SCPI_REG_GROUP_STB }, 48 | { SCPI_REG_CLASS_EVEN, SCPI_REG_GROUP_ESR }, 49 | { SCPI_REG_CLASS_ENAB, SCPI_REG_GROUP_ESR }, 50 | { SCPI_REG_CLASS_EVEN, SCPI_REG_GROUP_OPER }, 51 | { SCPI_REG_CLASS_ENAB, SCPI_REG_GROUP_OPER }, 52 | { SCPI_REG_CLASS_COND, SCPI_REG_GROUP_OPER }, 53 | { SCPI_REG_CLASS_EVEN, SCPI_REG_GROUP_QUES }, 54 | { SCPI_REG_CLASS_ENAB, SCPI_REG_GROUP_QUES }, 55 | { SCPI_REG_CLASS_COND, SCPI_REG_GROUP_QUES }, 56 | 57 | #if USE_CUSTOM_REGISTERS 58 | #ifndef USER_REGISTER_DETAILS 59 | #error "No user register details defined" 60 | #else 61 | USER_REGISTER_DETAILS 62 | #endif 63 | #endif 64 | 65 | }; 66 | 67 | static const scpi_reg_group_info_t scpi_reg_group_details[SCPI_REG_GROUP_COUNT] = { 68 | { 69 | SCPI_REG_STB, 70 | SCPI_REG_SRE, 71 | SCPI_REG_NONE, 72 | SCPI_REG_NONE, 73 | SCPI_REG_NONE, 74 | SCPI_REG_NONE, 75 | 0 76 | }, /* SCPI_REG_GROUP_STB */ 77 | { 78 | SCPI_REG_ESR, 79 | SCPI_REG_ESE, 80 | SCPI_REG_NONE, 81 | SCPI_REG_NONE, 82 | SCPI_REG_NONE, 83 | SCPI_REG_STB, 84 | STB_ESR 85 | }, /* SCPI_REG_GROUP_ESR */ 86 | { 87 | SCPI_REG_OPER, 88 | SCPI_REG_OPERE, 89 | SCPI_REG_OPERC, 90 | SCPI_REG_NONE, 91 | SCPI_REG_NONE, 92 | SCPI_REG_STB, 93 | STB_OPS 94 | }, /* SCPI_REG_GROUP_OPER */ 95 | { 96 | SCPI_REG_QUES, 97 | SCPI_REG_QUESE, 98 | SCPI_REG_QUESC, 99 | SCPI_REG_NONE, 100 | SCPI_REG_NONE, 101 | SCPI_REG_STB, 102 | STB_QES 103 | }, /* SCPI_REG_GROUP_QUES */ 104 | 105 | #if USE_CUSTOM_REGISTERS 106 | #ifndef USER_REGISTER_GROUP_DETAILS 107 | #error "No user register group details defined" 108 | #else 109 | USER_REGISTER_GROUP_DETAILS 110 | #endif 111 | #endif 112 | 113 | }; 114 | 115 | /** 116 | * Get register value 117 | * @param name - register name 118 | * @return register value 119 | */ 120 | scpi_reg_val_t SCPI_RegGet(scpi_t * context, scpi_reg_name_t name) { 121 | if ((name < SCPI_REG_COUNT) && context) { 122 | return context->registers[name]; 123 | } else { 124 | return 0; 125 | } 126 | } 127 | 128 | /** 129 | * Wrapper function to control interface from context 130 | * @param context 131 | * @param ctrl number of controll message 132 | * @param value value of related register 133 | */ 134 | static size_t writeControl(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) { 135 | if (context && context->interface && context->interface->control) { 136 | return context->interface->control(context, ctrl, val); 137 | } else { 138 | return 0; 139 | } 140 | } 141 | 142 | /** 143 | * Set register value 144 | * @param name - register name 145 | * @param val - new value 146 | */ 147 | void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val) { 148 | if ((name >= SCPI_REG_COUNT) || (context == NULL)) { 149 | return; 150 | } 151 | 152 | scpi_reg_group_info_t register_group; 153 | 154 | do { 155 | scpi_reg_class_t register_type = scpi_reg_details[name].type; 156 | register_group = scpi_reg_group_details[scpi_reg_details[name].group]; 157 | 158 | scpi_reg_val_t ptrans; 159 | 160 | /* store old register value */ 161 | scpi_reg_val_t old_val = context->registers[name]; 162 | 163 | if (old_val == val) { 164 | return; 165 | } else { 166 | context->registers[name] = val; 167 | } 168 | 169 | switch (register_type) { 170 | case SCPI_REG_CLASS_STB: 171 | case SCPI_REG_CLASS_SRE: 172 | { 173 | scpi_reg_val_t stb = context->registers[SCPI_REG_STB] & ~STB_SRQ; 174 | scpi_reg_val_t sre = context->registers[SCPI_REG_SRE] & ~STB_SRQ; 175 | 176 | if (stb & sre) { 177 | ptrans = ((old_val ^ val) & val); 178 | context->registers[SCPI_REG_STB] |= STB_SRQ; 179 | if (ptrans & val) { 180 | writeControl(context, SCPI_CTRL_SRQ, context->registers[SCPI_REG_STB]); 181 | } 182 | } else { 183 | context->registers[SCPI_REG_STB] &= ~STB_SRQ; 184 | } 185 | break; 186 | } 187 | case SCPI_REG_CLASS_EVEN: 188 | { 189 | scpi_reg_val_t enable; 190 | if(register_group.enable != SCPI_REG_NONE) { 191 | enable = SCPI_RegGet(context, register_group.enable); 192 | } else { 193 | enable = 0xFFFF; 194 | } 195 | 196 | scpi_bool_t summary = val & enable; 197 | 198 | name = register_group.parent_reg; 199 | val = SCPI_RegGet(context, register_group.parent_reg); 200 | if (summary) { 201 | val |= register_group.parent_bit; 202 | } else { 203 | val &= ~(register_group.parent_bit); 204 | } 205 | break; 206 | } 207 | case SCPI_REG_CLASS_COND: 208 | { 209 | name = register_group.event; 210 | 211 | if(register_group.ptfilt == SCPI_REG_NONE && register_group.ntfilt == SCPI_REG_NONE) { 212 | val = ((old_val ^ val) & val) | SCPI_RegGet(context, register_group.event); 213 | } else { 214 | scpi_reg_val_t ptfilt = 0, ntfilt = 0; 215 | scpi_reg_val_t transitions; 216 | scpi_reg_val_t ntrans; 217 | 218 | if(register_group.ptfilt != SCPI_REG_NONE) { 219 | ptfilt = SCPI_RegGet(context, register_group.ptfilt); 220 | } 221 | 222 | if(register_group.ntfilt != SCPI_REG_NONE) { 223 | ntfilt = SCPI_RegGet(context, register_group.ntfilt); 224 | } 225 | 226 | transitions = old_val ^ val; 227 | ptrans = transitions & val; 228 | ntrans = transitions & ~ptrans; 229 | 230 | val = ((ptrans & ptfilt) | (ntrans & ntfilt)) | SCPI_RegGet(context, register_group.event); 231 | } 232 | break; 233 | } 234 | case SCPI_REG_CLASS_ENAB: 235 | case SCPI_REG_CLASS_NTR: 236 | case SCPI_REG_CLASS_PTR: 237 | return; 238 | } 239 | } while(register_group.parent_reg != SCPI_REG_NONE); 240 | } 241 | 242 | /** 243 | * Set register bits 244 | * @param name - register name 245 | * @param bits bit mask 246 | */ 247 | void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits) { 248 | SCPI_RegSet(context, name, SCPI_RegGet(context, name) | bits); 249 | } 250 | 251 | /** 252 | * Clear register bits 253 | * @param name - register name 254 | * @param bits bit mask 255 | */ 256 | void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits) { 257 | SCPI_RegSet(context, name, SCPI_RegGet(context, name) & ~bits); 258 | } 259 | 260 | /** 261 | * *CLS - This command clears all status data structures in a device. 262 | * For a device which minimally complies with SCPI. (SCPI std 4.1.3.2) 263 | * @param context 264 | * @return 265 | */ 266 | scpi_result_t SCPI_CoreCls(scpi_t * context) { 267 | SCPI_ErrorClear(context); 268 | int i; 269 | for (i = 0; i < SCPI_REG_GROUP_COUNT; ++i) { 270 | scpi_reg_name_t event_reg = scpi_reg_group_details[i].event; 271 | if (event_reg != SCPI_REG_STB) { 272 | SCPI_RegSet(context, event_reg, 0); 273 | } 274 | } 275 | return SCPI_RES_OK; 276 | } 277 | 278 | /** 279 | * *ESE 280 | * @param context 281 | * @return 282 | */ 283 | scpi_result_t SCPI_CoreEse(scpi_t * context) { 284 | int32_t new_ESE; 285 | if (SCPI_ParamInt32(context, &new_ESE, TRUE)) { 286 | SCPI_RegSet(context, SCPI_REG_ESE, (scpi_reg_val_t) new_ESE); 287 | return SCPI_RES_OK; 288 | } 289 | return SCPI_RES_ERR; 290 | } 291 | 292 | /** 293 | * *ESE? 294 | * @param context 295 | * @return 296 | */ 297 | scpi_result_t SCPI_CoreEseQ(scpi_t * context) { 298 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_ESE)); 299 | return SCPI_RES_OK; 300 | } 301 | 302 | /** 303 | * *ESR? 304 | * @param context 305 | * @return 306 | */ 307 | scpi_result_t SCPI_CoreEsrQ(scpi_t * context) { 308 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_ESR)); 309 | SCPI_RegSet(context, SCPI_REG_ESR, 0); 310 | return SCPI_RES_OK; 311 | } 312 | 313 | /** 314 | * *IDN? 315 | * 316 | * field1: MANUFACTURE 317 | * field2: MODEL 318 | * field4: SUBSYSTEMS REVISIONS 319 | * 320 | * example: MANUFACTURE,MODEL,0,01-02-01 321 | * @param context 322 | * @return 323 | */ 324 | scpi_result_t SCPI_CoreIdnQ(scpi_t * context) { 325 | int i; 326 | for (i = 0; i < 4; i++) { 327 | if (context->idn[i]) { 328 | SCPI_ResultMnemonic(context, context->idn[i]); 329 | } else { 330 | SCPI_ResultMnemonic(context, "0"); 331 | } 332 | } 333 | return SCPI_RES_OK; 334 | } 335 | 336 | /** 337 | * *OPC 338 | * @param context 339 | * @return 340 | */ 341 | scpi_result_t SCPI_CoreOpc(scpi_t * context) { 342 | SCPI_RegSetBits(context, SCPI_REG_ESR, ESR_OPC); 343 | return SCPI_RES_OK; 344 | } 345 | 346 | /** 347 | * *OPC? 348 | * @param context 349 | * @return 350 | */ 351 | scpi_result_t SCPI_CoreOpcQ(scpi_t * context) { 352 | /* Operation is always completed */ 353 | SCPI_ResultInt32(context, 1); 354 | return SCPI_RES_OK; 355 | } 356 | 357 | /** 358 | * *RST 359 | * @param context 360 | * @return 361 | */ 362 | scpi_result_t SCPI_CoreRst(scpi_t * context) { 363 | if (context && context->interface && context->interface->reset) { 364 | return context->interface->reset(context); 365 | } 366 | return SCPI_RES_OK; 367 | } 368 | 369 | /** 370 | * *SRE 371 | * @param context 372 | * @return 373 | */ 374 | scpi_result_t SCPI_CoreSre(scpi_t * context) { 375 | int32_t new_SRE; 376 | if (SCPI_ParamInt32(context, &new_SRE, TRUE)) { 377 | SCPI_RegSet(context, SCPI_REG_SRE, (scpi_reg_val_t) new_SRE); 378 | return SCPI_RES_OK; 379 | } 380 | return SCPI_RES_ERR; 381 | } 382 | 383 | /** 384 | * *SRE? 385 | * @param context 386 | * @return 387 | */ 388 | scpi_result_t SCPI_CoreSreQ(scpi_t * context) { 389 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_SRE)); 390 | return SCPI_RES_OK; 391 | } 392 | 393 | /** 394 | * *STB? 395 | * @param context 396 | * @return 397 | */ 398 | scpi_result_t SCPI_CoreStbQ(scpi_t * context) { 399 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_STB)); 400 | return SCPI_RES_OK; 401 | } 402 | 403 | /** 404 | * *TST? 405 | * @param context 406 | * @return 407 | */ 408 | scpi_result_t SCPI_CoreTstQ(scpi_t * context) { 409 | (void) context; 410 | SCPI_ResultInt32(context, 0); 411 | return SCPI_RES_OK; 412 | } 413 | 414 | /** 415 | * *WAI 416 | * @param context 417 | * @return 418 | */ 419 | scpi_result_t SCPI_CoreWai(scpi_t * context) { 420 | (void) context; 421 | /* NOP */ 422 | return SCPI_RES_OK; 423 | } 424 | 425 | -------------------------------------------------------------------------------- /src/src/lexer.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file lexer.c 31 | * @date Wed Mar 20 19:35:19 UTC 2013 32 | * 33 | * @brief SCPI Lexer 34 | * 35 | * 36 | */ 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include "lexer_private.h" 43 | #include "scpi/error.h" 44 | 45 | /** 46 | * Is white space 47 | * @param c 48 | * @return 49 | */ 50 | static int isws(int c) { 51 | if ((c == ' ') || (c == '\t')) { 52 | return 1; 53 | } 54 | return 0; 55 | } 56 | 57 | /** 58 | * Is binary digit 59 | * @param c 60 | * @return 61 | */ 62 | static int isbdigit(int c) { 63 | if ((c == '0') || (c == '1')) { 64 | return 1; 65 | } 66 | return 0; 67 | } 68 | 69 | /** 70 | * Is hexadecimal digit 71 | * @param c 72 | * @return 73 | */ 74 | static int isqdigit(int c) { 75 | if ((c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') || (c == '5') || (c == '6') || (c == '7')) { 76 | return 1; 77 | } 78 | return 0; 79 | } 80 | 81 | /** 82 | * Is end of string 83 | * @param state 84 | * @return 85 | */ 86 | static int iseos(lex_state_t * state) { 87 | if ((state->buffer + state->len) <= (state->pos)) { 88 | return 1; 89 | } else { 90 | return 0; 91 | } 92 | } 93 | 94 | /** 95 | * Private export of iseos 96 | * @param state 97 | * @return 98 | */ 99 | int scpiLex_IsEos(lex_state_t * state) { 100 | return iseos(state); 101 | } 102 | 103 | /** 104 | * Test current character 105 | * @param state 106 | * @param chr 107 | * @return 108 | */ 109 | static int ischr(lex_state_t * state, char chr) { 110 | return (state->pos[0] == chr); 111 | } 112 | 113 | /** 114 | * Is plus or minus 115 | * @param c 116 | * @return 117 | */ 118 | static int isplusmn(int c) { 119 | return c == '+' || c == '-'; 120 | } 121 | 122 | /** 123 | * Is letter H 124 | * @param c 125 | * @return 126 | */ 127 | static int isH(int c) { 128 | return c == 'h' || c == 'H'; 129 | } 130 | 131 | /** 132 | * Is letter B 133 | * @param c 134 | * @return 135 | */ 136 | static int isB(int c) { 137 | return c == 'b' || c == 'B'; 138 | } 139 | 140 | /** 141 | * Is letter Q 142 | * @param c 143 | * @return 144 | */ 145 | static int isQ(int c) { 146 | return c == 'q' || c == 'Q'; 147 | } 148 | 149 | /** 150 | * Is letter E 151 | * @param c 152 | * @return 153 | */ 154 | static int isE(int c) { 155 | return c == 'e' || c == 'E'; 156 | } 157 | 158 | #define SKIP_NONE 0 159 | #define SKIP_OK 1 160 | #define SKIP_INCOMPLETE -1 161 | 162 | /* skip characters */ 163 | /* 7.4.1 */ 164 | /* TODO: static int skipProgramMessageUnitSeparator(lex_state_t * state) */ 165 | 166 | /** 167 | * Skip all whitespaces 168 | * @param state 169 | * @return 170 | */ 171 | static int skipWs(lex_state_t * state) { 172 | int someSpace = 0; 173 | while (!iseos(state) && isws(state->pos[0])) { 174 | state->pos++; 175 | someSpace++; 176 | } 177 | 178 | return someSpace; 179 | } 180 | 181 | /* 7.4.2 */ 182 | /* static int skipProgramDataSeparator(lex_state_t * state) */ 183 | 184 | /* 7.5.2 */ 185 | /* static int skipProgramMessageTerminator(lex_state_t * state) */ 186 | 187 | /** 188 | * Skip decimal digit 189 | * @param state 190 | * @return 191 | */ 192 | static int skipDigit(lex_state_t * state) { 193 | if (!iseos(state) && isdigit((uint8_t)(state->pos[0]))) { 194 | state->pos++; 195 | return SKIP_OK; 196 | } else { 197 | return SKIP_NONE; 198 | } 199 | } 200 | 201 | /** 202 | * Skip multiple decimal digits 203 | * @param state 204 | * @return 205 | */ 206 | static int skipNumbers(lex_state_t * state) { 207 | int someNumbers = 0; 208 | while (!iseos(state) && isdigit((uint8_t)(state->pos[0]))) { 209 | state->pos++; 210 | someNumbers++; 211 | } 212 | return someNumbers; 213 | } 214 | 215 | /** 216 | * Skip plus or minus 217 | * @param state 218 | * @return 219 | */ 220 | static int skipPlusmn(lex_state_t * state) { 221 | if (!iseos(state) && isplusmn(state->pos[0])) { 222 | state->pos++; 223 | return SKIP_OK; 224 | } else { 225 | return SKIP_NONE; 226 | } 227 | } 228 | 229 | /** 230 | * Skip any character from 'a'-'Z' 231 | * @param state 232 | * @return 233 | */ 234 | static int skipAlpha(lex_state_t * state) { 235 | int someLetters = 0; 236 | while (!iseos(state) && isalpha((uint8_t)(state->pos[0]))) { 237 | state->pos++; 238 | someLetters++; 239 | } 240 | return someLetters; 241 | } 242 | 243 | /** 244 | * Skip exact character chr or nothing 245 | * @param state 246 | * @param chr 247 | * @return 248 | */ 249 | static int skipChr(lex_state_t * state, char chr) { 250 | if (!iseos(state) && ischr(state, chr)) { 251 | state->pos++; 252 | return SKIP_OK; 253 | } else { 254 | return SKIP_NONE; 255 | } 256 | } 257 | 258 | /** 259 | * Skip slash or dot 260 | * @param state 261 | * @return 262 | */ 263 | static int skipSlashDot(lex_state_t * state) { 264 | if (!iseos(state) && (ischr(state, '/') | ischr(state, '.'))) { 265 | state->pos++; 266 | return SKIP_OK; 267 | } else { 268 | return SKIP_NONE; 269 | } 270 | } 271 | 272 | /** 273 | * Skip star 274 | * @param state 275 | * @return 276 | */ 277 | static int skipStar(lex_state_t * state) { 278 | if (!iseos(state) && ischr(state, '*')) { 279 | state->pos++; 280 | return SKIP_OK; 281 | } else { 282 | return SKIP_NONE; 283 | } 284 | } 285 | 286 | /** 287 | * Skip colon 288 | * @param state 289 | * @return 290 | */ 291 | static int skipColon(lex_state_t * state) { 292 | if (!iseos(state) && ischr(state, ':')) { 293 | state->pos++; 294 | return SKIP_OK; 295 | } else { 296 | return SKIP_NONE; 297 | } 298 | } 299 | 300 | /* 7.6.1.2 */ 301 | 302 | /** 303 | * Skip program mnemonic [a-z][a-z0-9_]* 304 | * @param state 305 | * @return 306 | */ 307 | static int skipProgramMnemonic(lex_state_t * state) { 308 | const char * startPos = state->pos; 309 | if (!iseos(state) && isalpha((uint8_t)(state->pos[0]))) { 310 | state->pos++; 311 | while (!iseos(state) && (isalnum((uint8_t)(state->pos[0])) || ischr(state, '_'))) { 312 | state->pos++; 313 | } 314 | } 315 | 316 | if (iseos(state)) { 317 | return (state->pos - startPos) * SKIP_INCOMPLETE; 318 | } else { 319 | return (state->pos - startPos) * SKIP_OK; 320 | } 321 | } 322 | 323 | /* tokens */ 324 | 325 | /** 326 | * Detect token white space 327 | * @param state 328 | * @param token 329 | * @return 330 | */ 331 | int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) { 332 | token->ptr = state->pos; 333 | 334 | skipWs(state); 335 | 336 | token->len = state->pos - token->ptr; 337 | 338 | if (token->len > 0) { 339 | token->type = SCPI_TOKEN_WS; 340 | } else { 341 | token->type = SCPI_TOKEN_UNKNOWN; 342 | } 343 | 344 | return token->len; 345 | } 346 | 347 | /* 7.6.1 */ 348 | 349 | /** 350 | * Skip command program header \* 351 | * @param state 352 | * @return 353 | */ 354 | static int skipCommonProgramHeader(lex_state_t * state) { 355 | int res; 356 | if (skipStar(state)) { 357 | res = skipProgramMnemonic(state); 358 | if (res == SKIP_NONE && iseos(state)) { 359 | return SKIP_INCOMPLETE; 360 | } else if (res <= SKIP_INCOMPLETE) { 361 | return SKIP_OK; 362 | } else if (res >= SKIP_OK) { 363 | return SKIP_OK; 364 | } else { 365 | return SKIP_INCOMPLETE; 366 | } 367 | } 368 | return SKIP_NONE; 369 | } 370 | 371 | /** 372 | * Skip compound program header ::... 373 | * @param state 374 | * @return 375 | */ 376 | static int skipCompoundProgramHeader(lex_state_t * state) { 377 | int res; 378 | int firstColon = skipColon(state); 379 | 380 | res = skipProgramMnemonic(state); 381 | if (res >= SKIP_OK) { 382 | while (skipColon(state)) { 383 | res = skipProgramMnemonic(state); 384 | if (res <= SKIP_INCOMPLETE) { 385 | return SKIP_OK; 386 | } else if (res == SKIP_NONE) { 387 | return SKIP_INCOMPLETE; 388 | } 389 | } 390 | return SKIP_OK; 391 | } else if (res <= SKIP_INCOMPLETE) { 392 | return SKIP_OK; 393 | } else if (firstColon) { 394 | return SKIP_INCOMPLETE; 395 | } else { 396 | return SKIP_NONE; 397 | } 398 | } 399 | 400 | /** 401 | * Detect token command or compound program header 402 | * @param state 403 | * @param token 404 | * @return 405 | */ 406 | int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) { 407 | int res; 408 | token->ptr = state->pos; 409 | token->type = SCPI_TOKEN_UNKNOWN; 410 | 411 | res = skipCommonProgramHeader(state); 412 | if (res >= SKIP_OK) { 413 | if (skipChr(state, '?') >= SKIP_OK) { 414 | token->type = SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER; 415 | } else { 416 | token->type = SCPI_TOKEN_COMMON_PROGRAM_HEADER; 417 | } 418 | } else if (res <= SKIP_INCOMPLETE) { 419 | token->type = SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER; 420 | } else if (res == SKIP_NONE) { 421 | res = skipCompoundProgramHeader(state); 422 | 423 | if (res >= SKIP_OK) { 424 | if (skipChr(state, '?') >= SKIP_OK) { 425 | token->type = SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER; 426 | } else { 427 | token->type = SCPI_TOKEN_COMPOUND_PROGRAM_HEADER; 428 | } 429 | } else if (res <= SKIP_INCOMPLETE) { 430 | token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER; 431 | } 432 | } 433 | 434 | if (token->type != SCPI_TOKEN_UNKNOWN) { 435 | token->len = state->pos - token->ptr; 436 | } else { 437 | token->len = 0; 438 | state->pos = token->ptr; 439 | } 440 | 441 | return token->len; 442 | } 443 | 444 | /* 7.7.1 */ 445 | 446 | /** 447 | * Detect token "Character program data" 448 | * @param state 449 | * @param token 450 | * @return 451 | */ 452 | int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) { 453 | token->ptr = state->pos; 454 | 455 | if (!iseos(state) && isalpha((uint8_t)(state->pos[0]))) { 456 | state->pos++; 457 | while (!iseos(state) && (isalnum((uint8_t)(state->pos[0])) || ischr(state, '_'))) { 458 | state->pos++; 459 | } 460 | } 461 | 462 | token->len = state->pos - token->ptr; 463 | if (token->len > 0) { 464 | token->type = SCPI_TOKEN_PROGRAM_MNEMONIC; 465 | } else { 466 | token->type = SCPI_TOKEN_UNKNOWN; 467 | } 468 | 469 | return token->len; 470 | } 471 | 472 | /* 7.7.2 */ 473 | static int skipMantisa(lex_state_t * state) { 474 | int someNumbers = 0; 475 | 476 | skipPlusmn(state); 477 | 478 | someNumbers += skipNumbers(state); 479 | 480 | if (skipChr(state, '.')) { 481 | someNumbers += skipNumbers(state); 482 | } 483 | 484 | return someNumbers; 485 | } 486 | 487 | static int skipExponent(lex_state_t * state) { 488 | int someNumbers = 0; 489 | 490 | if (!iseos(state) && isE(state->pos[0])) { 491 | state->pos++; 492 | 493 | skipWs(state); 494 | 495 | skipPlusmn(state); 496 | 497 | someNumbers = skipNumbers(state); 498 | } 499 | 500 | return someNumbers; 501 | } 502 | 503 | /** 504 | * Detect token Decimal number 505 | * @param state 506 | * @param token 507 | * @return 508 | */ 509 | int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) { 510 | char * rollback; 511 | token->ptr = state->pos; 512 | 513 | if (skipMantisa(state)) { 514 | rollback = state->pos; 515 | skipWs(state); 516 | if (!skipExponent(state)) { 517 | state->pos = rollback; 518 | } 519 | } else { 520 | state->pos = token->ptr; 521 | } 522 | 523 | token->len = state->pos - token->ptr; 524 | if (token->len > 0) { 525 | token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA; 526 | } else { 527 | token->type = SCPI_TOKEN_UNKNOWN; 528 | } 529 | 530 | return token->len; 531 | } 532 | 533 | /* 7.7.3 */ 534 | int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) { 535 | token->ptr = state->pos; 536 | 537 | skipChr(state, '/'); 538 | 539 | /* TODO: strict parsing : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))* */ 540 | if (skipAlpha(state)) { 541 | skipChr(state, '-'); 542 | skipDigit(state); 543 | 544 | while (skipSlashDot(state)) { 545 | skipAlpha(state); 546 | skipChr(state, '-'); 547 | skipDigit(state); 548 | } 549 | } 550 | 551 | token->len = state->pos - token->ptr; 552 | if ((token->len > 0)) { 553 | token->type = SCPI_TOKEN_SUFFIX_PROGRAM_DATA; 554 | } else { 555 | token->type = SCPI_TOKEN_UNKNOWN; 556 | state->pos = token->ptr; 557 | token->len = 0; 558 | } 559 | 560 | return token->len; 561 | } 562 | 563 | /* 7.7.4 */ 564 | static int skipHexNum(lex_state_t * state) { 565 | int someNumbers = 0; 566 | while (!iseos(state) && isxdigit((uint8_t)(state->pos[0]))) { 567 | state->pos++; 568 | someNumbers++; 569 | } 570 | return someNumbers; 571 | } 572 | 573 | static int skipOctNum(lex_state_t * state) { 574 | int someNumbers = 0; 575 | while (!iseos(state) && isqdigit(state->pos[0])) { 576 | state->pos++; 577 | someNumbers++; 578 | } 579 | return someNumbers; 580 | } 581 | 582 | static int skipBinNum(lex_state_t * state) { 583 | int someNumbers = 0; 584 | while (!iseos(state) && isbdigit(state->pos[0])) { 585 | state->pos++; 586 | someNumbers++; 587 | } 588 | return someNumbers; 589 | } 590 | 591 | /** 592 | * Detect token nondecimal number 593 | * @param state 594 | * @param token 595 | * @return 596 | */ 597 | int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) { 598 | int someNumbers = 0; 599 | token->ptr = state->pos; 600 | if (skipChr(state, '#')) { 601 | if (!iseos(state)) { 602 | if (isH(state->pos[0])) { 603 | state->pos++; 604 | someNumbers = skipHexNum(state); 605 | token->type = SCPI_TOKEN_HEXNUM; 606 | } else if (isQ(state->pos[0])) { 607 | state->pos++; 608 | someNumbers = skipOctNum(state); 609 | token->type = SCPI_TOKEN_OCTNUM; 610 | } else if (isB(state->pos[0])) { 611 | state->pos++; 612 | someNumbers = skipBinNum(state); 613 | token->type = SCPI_TOKEN_BINNUM; 614 | } 615 | } 616 | } 617 | 618 | if (someNumbers) { 619 | token->ptr += 2; /* ignore number prefix */ 620 | token->len = state->pos - token->ptr; 621 | } else { 622 | token->type = SCPI_TOKEN_UNKNOWN; 623 | state->pos = token->ptr; 624 | token->len = 0; 625 | } 626 | return token->len > 0 ? token->len + 2 : 0; 627 | } 628 | 629 | /* 7.7.5 */ 630 | static int isascii7bit(int c) { 631 | return (c >= 0) && (c <= 0x7f); 632 | } 633 | 634 | static void skipQuoteProgramData(lex_state_t * state, char quote) { 635 | while (!iseos(state)) { 636 | if (isascii7bit(state->pos[0]) && !ischr(state, quote)) { 637 | state->pos++; 638 | } else if (ischr(state, quote)) { 639 | state->pos++; 640 | if (!iseos(state) && ischr(state, quote)) { 641 | state->pos++; 642 | } else { 643 | state->pos--; 644 | break; 645 | } 646 | } else { 647 | break; 648 | } 649 | } 650 | } 651 | 652 | static void skipDoubleQuoteProgramData(lex_state_t * state) { 653 | skipQuoteProgramData(state, '"'); 654 | } 655 | 656 | static void skipSingleQuoteProgramData(lex_state_t * state) { 657 | skipQuoteProgramData(state, '\''); 658 | } 659 | 660 | /** 661 | * Detect token String data 662 | * @param state 663 | * @param token 664 | * @return 665 | */ 666 | int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) { 667 | token->ptr = state->pos; 668 | 669 | if (!iseos(state)) { 670 | if (ischr(state, '"')) { 671 | state->pos++; 672 | token->type = SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA; 673 | skipDoubleQuoteProgramData(state); 674 | if (!iseos(state) && ischr(state, '"')) { 675 | state->pos++; 676 | token->len = state->pos - token->ptr; 677 | } else { 678 | state->pos = token->ptr; 679 | } 680 | } else if (ischr(state, '\'')) { 681 | state->pos++; 682 | token->type = SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA; 683 | skipSingleQuoteProgramData(state); 684 | if (!iseos(state) && ischr(state, '\'')) { 685 | state->pos++; 686 | token->len = state->pos - token->ptr; 687 | } else { 688 | state->pos = token->ptr; 689 | } 690 | } 691 | } 692 | 693 | token->len = state->pos - token->ptr; 694 | 695 | if ((token->len > 0)) { 696 | /* token->ptr++; 697 | * token->len -= 2; */ 698 | } else { 699 | token->type = SCPI_TOKEN_UNKNOWN; 700 | state->pos = token->ptr; 701 | token->len = 0; 702 | } 703 | 704 | return token->len > 0 ? token->len : 0; 705 | } 706 | 707 | /* 7.7.6 */ 708 | static int isNonzeroDigit(int c) { 709 | return isdigit(c) && (c != '0'); 710 | } 711 | 712 | /** 713 | * Detect token Block Data 714 | * @param state 715 | * @param token 716 | * @return 717 | */ 718 | int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) { 719 | int i; 720 | int arbitraryBlockLength = 0; 721 | const char * ptr = state->pos; 722 | int validData = -1; 723 | token->ptr = state->pos; 724 | 725 | if (skipChr(state, '#')) { 726 | if (!iseos(state) && isNonzeroDigit(state->pos[0])) { 727 | /* Get number of digits */ 728 | i = state->pos[0] - '0'; 729 | state->pos++; 730 | 731 | for (; i > 0; i--) { 732 | if (!iseos(state) && isdigit((uint8_t)(state->pos[0]))) { 733 | arbitraryBlockLength *= 10; 734 | arbitraryBlockLength += (state->pos[0] - '0'); 735 | state->pos++; 736 | } else { 737 | break; 738 | } 739 | } 740 | 741 | if (i == 0) { 742 | state->pos += arbitraryBlockLength; 743 | if ((state->buffer + state->len) >= (state->pos)) { 744 | token->ptr = state->pos - arbitraryBlockLength; 745 | token->len = arbitraryBlockLength; 746 | validData = 1; 747 | } else { 748 | validData = 0; 749 | } 750 | } else if (iseos(state)) { 751 | validData = 0; 752 | } 753 | } else if (iseos(state)) { 754 | validData = 0; 755 | } 756 | } 757 | 758 | if (validData == 1) { 759 | /* valid */ 760 | token->type = SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA; 761 | } else if (validData == 0) { 762 | /* incomplete */ 763 | token->type = SCPI_TOKEN_UNKNOWN; 764 | token->len = 0; 765 | state->pos = state->buffer + state->len; 766 | } else { 767 | /* invalid */ 768 | token->type = SCPI_TOKEN_UNKNOWN; 769 | state->pos = token->ptr; 770 | token->len = 0; 771 | } 772 | 773 | return token->len + (token->ptr - ptr); 774 | } 775 | 776 | /* 7.7.7 */ 777 | static int isProgramExpression(int c) { 778 | if ((c >= 0x20) && (c <= 0x7e)) { 779 | if ((c != '"') 780 | && (c != '#') 781 | && (c != '\'') 782 | && (c != '(') 783 | && (c != ')') 784 | && (c != ';')) { 785 | return 1; 786 | } 787 | } 788 | 789 | return 0; 790 | } 791 | 792 | static void skipProgramExpression(lex_state_t * state) { 793 | while (!iseos(state) && isProgramExpression(state->pos[0])) { 794 | state->pos++; 795 | } 796 | } 797 | 798 | /* TODO: 7.7.7.2-2 recursive - any program data */ 799 | 800 | /** 801 | * Detect token Expression 802 | * @param state 803 | * @param token 804 | * @return 805 | */ 806 | int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) { 807 | token->ptr = state->pos; 808 | 809 | if (!iseos(state) && ischr(state, '(')) { 810 | state->pos++; 811 | skipProgramExpression(state); 812 | 813 | if (!iseos(state) && ischr(state, ')')) { 814 | state->pos++; 815 | token->len = state->pos - token->ptr; 816 | } else { 817 | token->len = 0; 818 | } 819 | } 820 | 821 | if ((token->len > 0)) { 822 | token->type = SCPI_TOKEN_PROGRAM_EXPRESSION; 823 | } else { 824 | token->type = SCPI_TOKEN_UNKNOWN; 825 | state->pos = token->ptr; 826 | token->len = 0; 827 | } 828 | 829 | return token->len; 830 | } 831 | 832 | /** 833 | * Detect token comma 834 | * @param state 835 | * @param token 836 | * @return 837 | */ 838 | int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) { 839 | token->ptr = state->pos; 840 | 841 | if (skipChr(state, ',')) { 842 | token->len = 1; 843 | token->type = SCPI_TOKEN_COMMA; 844 | } else { 845 | token->len = 0; 846 | token->type = SCPI_TOKEN_UNKNOWN; 847 | } 848 | 849 | return token->len; 850 | } 851 | 852 | /** 853 | * Detect token semicolon 854 | * @param state 855 | * @param token 856 | * @return 857 | */ 858 | int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) { 859 | token->ptr = state->pos; 860 | 861 | if (skipChr(state, ';')) { 862 | token->len = 1; 863 | token->type = SCPI_TOKEN_SEMICOLON; 864 | } else { 865 | token->len = 0; 866 | token->type = SCPI_TOKEN_UNKNOWN; 867 | } 868 | 869 | return token->len; 870 | } 871 | 872 | /** 873 | * Detect token colon 874 | * @param state 875 | * @param token 876 | * @return 877 | */ 878 | int scpiLex_Colon(lex_state_t * state, scpi_token_t * token) { 879 | token->ptr = state->pos; 880 | 881 | if (skipChr(state, ':')) { 882 | token->len = 1; 883 | token->type = SCPI_TOKEN_COLON; 884 | } else { 885 | token->len = 0; 886 | token->type = SCPI_TOKEN_UNKNOWN; 887 | } 888 | 889 | return token->len; 890 | } 891 | 892 | /** 893 | * Detect specified character 894 | * @param state 895 | * @param token 896 | * @return 897 | */ 898 | int scpiLex_SpecificCharacter(lex_state_t * state, scpi_token_t * token, char chr) { 899 | token->ptr = state->pos; 900 | 901 | if (skipChr(state, chr)) { 902 | token->len = 1; 903 | token->type = SCPI_TOKEN_SPECIFIC_CHARACTER; 904 | } else { 905 | token->len = 0; 906 | token->type = SCPI_TOKEN_UNKNOWN; 907 | } 908 | 909 | return token->len; 910 | } 911 | 912 | /** 913 | * Detect token New line 914 | * @param state 915 | * @param token 916 | * @return 917 | */ 918 | int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) { 919 | token->ptr = state->pos; 920 | 921 | skipChr(state, '\r'); 922 | skipChr(state, '\n'); 923 | 924 | token->len = state->pos - token->ptr; 925 | 926 | if ((token->len > 0)) { 927 | token->type = SCPI_TOKEN_NL; 928 | } else { 929 | token->type = SCPI_TOKEN_UNKNOWN; 930 | state->pos = token->ptr; 931 | token->len = 0; 932 | } 933 | 934 | return token->len; 935 | } 936 | -------------------------------------------------------------------------------- /src/src/lexer_private.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file lexer.h 31 | * @date Thu Mar 21 15:00:58 UTC 2013 32 | * 33 | * @brief SCPI Lexer 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_LEXER_H 39 | #define SCPI_LEXER_H 40 | 41 | #include "scpi/types.h" 42 | #include "utils_private.h" 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | int scpiLex_IsEos(lex_state_t * state) LOCAL; 49 | int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) LOCAL; 50 | int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) LOCAL; 51 | int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; 52 | int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; 53 | int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; 54 | int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) LOCAL; 55 | int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; 56 | int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; 57 | int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) LOCAL; 58 | int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) LOCAL; 59 | int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) LOCAL; 60 | int scpiLex_Colon(lex_state_t * state, scpi_token_t * token) LOCAL; 61 | int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) LOCAL; 62 | int scpiLex_SpecificCharacter(lex_state_t * state, scpi_token_t * token, char chr) LOCAL; 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #endif /* SCPI_LEXER_H */ 69 | 70 | -------------------------------------------------------------------------------- /src/src/minimal.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_minimal.c 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI minimal implementation 34 | * 35 | * 36 | */ 37 | 38 | 39 | #include "scpi/parser.h" 40 | #include "scpi/minimal.h" 41 | #include "scpi/constants.h" 42 | #include "scpi/error.h" 43 | #include "scpi/ieee488.h" 44 | #include "utils_private.h" 45 | 46 | /** 47 | * Command stub function 48 | * @param context 49 | * @return 50 | */ 51 | scpi_result_t SCPI_Stub(scpi_t * context) { 52 | (void) context; 53 | return SCPI_RES_OK; 54 | } 55 | 56 | /** 57 | * Query command stub function 58 | * @param context 59 | * @return 60 | */ 61 | scpi_result_t SCPI_StubQ(scpi_t * context) { 62 | SCPI_ResultInt32(context, 0); 63 | return SCPI_RES_OK; 64 | } 65 | 66 | /** 67 | * SYSTem:VERSion? 68 | * @param context 69 | * @return 70 | */ 71 | scpi_result_t SCPI_SystemVersionQ(scpi_t * context) { 72 | SCPI_ResultMnemonic(context, SCPI_STD_VERSION_REVISION); 73 | return SCPI_RES_OK; 74 | } 75 | 76 | /** 77 | * SYSTem:ERRor[:NEXT]? 78 | * @param context 79 | * @return 80 | */ 81 | scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context) { 82 | scpi_error_t error; 83 | SCPI_ErrorPop(context, &error); 84 | SCPI_ResultError(context, &error); 85 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION 86 | SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false); 87 | #endif 88 | return SCPI_RES_OK; 89 | } 90 | 91 | /** 92 | * SYSTem:ERRor:COUNt? 93 | * @param context 94 | * @return 95 | */ 96 | scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context) { 97 | SCPI_ResultInt32(context, SCPI_ErrorCount(context)); 98 | 99 | return SCPI_RES_OK; 100 | } 101 | 102 | /** 103 | * STATus:QUEStionable:CONDition? 104 | * @param context 105 | * @return 106 | */ 107 | scpi_result_t SCPI_StatusQuestionableConditionQ(scpi_t * context) { 108 | /* return value */ 109 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_QUESC)); 110 | 111 | return SCPI_RES_OK; 112 | } 113 | 114 | /** 115 | * STATus:QUEStionable[:EVENt]? 116 | * @param context 117 | * @return 118 | */ 119 | scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context) { 120 | /* return value */ 121 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_QUES)); 122 | 123 | /* clear register */ 124 | SCPI_RegSet(context, SCPI_REG_QUES, 0); 125 | 126 | return SCPI_RES_OK; 127 | } 128 | 129 | /** 130 | * STATus:QUEStionable:ENABle? 131 | * @param context 132 | * @return 133 | */ 134 | scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context) { 135 | /* return value */ 136 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_QUESE)); 137 | 138 | return SCPI_RES_OK; 139 | } 140 | 141 | /** 142 | * STATus:QUEStionable:ENABle 143 | * @param context 144 | * @return 145 | */ 146 | scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context) { 147 | int32_t new_QUESE; 148 | if (SCPI_ParamInt32(context, &new_QUESE, TRUE)) { 149 | SCPI_RegSet(context, SCPI_REG_QUESE, (scpi_reg_val_t) new_QUESE); 150 | } 151 | return SCPI_RES_OK; 152 | } 153 | 154 | /** 155 | * STATus:OPERation:CONDition? 156 | * @param context 157 | * @return 158 | */ 159 | scpi_result_t SCPI_StatusOperationConditionQ(scpi_t * context) { 160 | /* return value */ 161 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_OPERC)); 162 | 163 | return SCPI_RES_OK; 164 | } 165 | 166 | /** 167 | * STATus:OPERation[:EVENt]? 168 | * @param context 169 | * @return 170 | */ 171 | scpi_result_t SCPI_StatusOperationEventQ(scpi_t * context) { 172 | /* return value */ 173 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_OPER)); 174 | 175 | /* clear register */ 176 | SCPI_RegSet(context, SCPI_REG_OPER, 0); 177 | 178 | return SCPI_RES_OK; 179 | } 180 | 181 | /** 182 | * STATus:OPERation:ENABle? 183 | * @param context 184 | * @return 185 | */ 186 | scpi_result_t SCPI_StatusOperationEnableQ(scpi_t * context) { 187 | /* return value */ 188 | SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_OPERE)); 189 | 190 | return SCPI_RES_OK; 191 | } 192 | 193 | /** 194 | * STATus:OPERation:ENABle 195 | * @param context 196 | * @return 197 | */ 198 | scpi_result_t SCPI_StatusOperationEnable(scpi_t * context) { 199 | int32_t new_OPERE; 200 | if (SCPI_ParamInt32(context, &new_OPERE, TRUE)) { 201 | SCPI_RegSet(context, SCPI_REG_OPERE, (scpi_reg_val_t) new_OPERE); 202 | } 203 | return SCPI_RES_OK; 204 | } 205 | 206 | /** 207 | * STATus:PRESet 208 | * @param context 209 | * @return 210 | */ 211 | scpi_result_t SCPI_StatusPreset(scpi_t * context) { 212 | /* clear STATUS:... */ 213 | SCPI_RegSet(context, SCPI_REG_QUES, 0); 214 | return SCPI_RES_OK; 215 | } 216 | -------------------------------------------------------------------------------- /src/src/parser_private.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file parser_private.h 31 | * 32 | * @brief SCPI Parser private definitions 33 | * 34 | * 35 | */ 36 | 37 | #ifndef SCPI_PARSER_PRIVATE_H 38 | #define SCPI_PARSER_PRIVATE_H 39 | 40 | #include "scpi/types.h" 41 | #include "utils_private.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; 48 | int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) LOCAL; 49 | int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) LOCAL; 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif /* SCPI_PARSER_PRIVATE_H */ 56 | 57 | -------------------------------------------------------------------------------- /src/src/scpi.g: -------------------------------------------------------------------------------- 1 | grammar scpi; 2 | 3 | terminatedProgramMessage 4 | : programMessage NL? EOF 5 | ; 6 | 7 | programMessage 8 | : programMessageUnit (SEMICOLON programMessageUnit)* 9 | ; 10 | 11 | 12 | programMessageUnit 13 | : WS* programHeader (WS programData (COMMA programData)*)? 14 | ; 15 | 16 | programHeader 17 | : compoundProgramHeader 18 | | commonProgramHeader 19 | ; 20 | 21 | compoundProgramHeader 22 | : COLON? PROGRAM_MNEMONIC (COLON PROGRAM_MNEMONIC)* QUESTION? 23 | ; 24 | 25 | commonProgramHeader 26 | : STAR PROGRAM_MNEMONIC QUESTION? 27 | ; 28 | 29 | programDataSeparator 30 | : WS* 31 | ; 32 | 33 | programData 34 | : WS* programDataType WS* 35 | ; 36 | 37 | programDataType 38 | : nondecimalNumericProgramData 39 | | characterProgramData 40 | | decimalNumericProgramData 41 | | stringProgramData 42 | | arbitraryBlockProgramData 43 | | expressionProgramData 44 | // | suffixProgramData 45 | ; 46 | 47 | nondecimalNumericProgramData 48 | : HEXNUM 49 | | OCTNUM 50 | | BINNUM 51 | ; 52 | 53 | characterProgramData 54 | : PROGRAM_MNEMONIC 55 | ; 56 | 57 | decimalNumericProgramData 58 | : DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX 59 | ; 60 | 61 | //suffixProgramData 62 | // : PROGRAM_MNEMONIC//SUFFIX_PROGRAM_DATA 63 | // ; 64 | 65 | stringProgramData 66 | : SINGLE_QUOTE_PROGRAM_DATA 67 | | DOUBLE_QUOTE_PROGRAM_DATA 68 | ; 69 | 70 | expressionProgramData 71 | : PROGRAM_EXPRESSION 72 | ; 73 | 74 | // support only nonzero prefix 75 | arbitraryBlockProgramData 76 | : SHARP NONZERO_DIGIT NUMBER .* 77 | ; 78 | 79 | PROGRAM_MNEMONIC : ALPHA (ALPHA | DIGIT | UNDERSCORE)*; 80 | HEXNUM : SHARP H HEXDIGIT*; 81 | BINNUM : SHARP Q OCTDIGIT*; 82 | OCTNUM : SHARP B BINDIGIT*; 83 | UNDERSCORE : '_'; 84 | SEMICOLON : ';'; 85 | QUESTION : '?'; 86 | COLON : ':'; 87 | COMMA : ','; 88 | STAR : '*'; 89 | NL : '\r'? '\n' ; 90 | WS : (SPACE | TAB); 91 | 92 | DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX : DECIMAL_NUMERIC_PROGRAM_DATA WS* (SUFFIX_PROGRAM_DATA)?; 93 | fragment DECIMAL_NUMERIC_PROGRAM_DATA : MANTISA WS* (EXPONENT)?; 94 | SINGLE_QUOTE_PROGRAM_DATA : SINGLE_QUOTE ( (NON_SINGLE_QUOTE) | (SINGLE_QUOTE SINGLE_QUOTE))* SINGLE_QUOTE; 95 | DOUBLE_QUOTE_PROGRAM_DATA : DOUBLE_QUOTE ( (NON_DOUBLE_QUOTE) | (DOUBLE_QUOTE DOUBLE_QUOTE))* DOUBLE_QUOTE; 96 | //SUFFIX_PROGRAM_DATA : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))*; 97 | fragment SUFFIX_PROGRAM_DATA : SLASH? ALPHA+ ((SLASH | DOT) ALPHA+)*; 98 | //fragment SUFFIX_PROGRAM_DATA : ALPHA+; 99 | 100 | fragment PROGRAM_EXPRESSION_CHARACTER : (SPACE | '!' | '$'..'&' | '*'..':' | '<' ..'~'); 101 | PROGRAM_EXPRESSION : LBRACKET PROGRAM_EXPRESSION_CHARACTER RBRACKET; 102 | 103 | fragment PLUSMN : (PLUS | MINUS); 104 | fragment MANTISA : PLUSMN? ( (NUMBER) | (NUMBER DOT NUMBER?) | (DOT NUMBER)); 105 | 106 | //fragment EXPONENT : WS* E WS* PLUSMN? NUMBER; 107 | fragment EXPONENT : E WS* PLUSMN? NUMBER; 108 | 109 | fragment NUMBER : DIGIT+; 110 | 111 | fragment LBRACKET : '('; 112 | fragment RBRACKET : ')'; 113 | 114 | fragment ALPHA : ('a'..'z'|'A'..'Z'); 115 | fragment DIGIT : ('0'..'9'); 116 | fragment NONZERO_DIGIT : ('1'..'9'); 117 | 118 | fragment HEXDIGIT : (DIGIT | 'a'..'f' | 'A'..'F'); 119 | fragment OCTDIGIT : ('0'..'7'); 120 | fragment BINDIGIT : ('0' | '1'); 121 | 122 | fragment SHARP : '#'; 123 | 124 | fragment E : ('E'|'e'); 125 | fragment H : ('H'|'h'); 126 | fragment Q : ('Q'|'q'); 127 | fragment B : ('B'|'b'); 128 | 129 | fragment SPACE : ' '; 130 | fragment TAB : '\t'; 131 | 132 | fragment PLUS : '+'; 133 | fragment MINUS : '-'; 134 | fragment DOT : '.'; 135 | fragment SLASH : '/'; 136 | fragment SINGLE_QUOTE : '\''; 137 | fragment DOUBLE_QUOTE : '"'; 138 | fragment NON_SINGLE_QUOTE : ~SINGLE_QUOTE; 139 | fragment NON_DOUBLE_QUOTE : ~DOUBLE_QUOTE; 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/src/units.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_units.c 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief SCPI units 34 | * 35 | * 36 | */ 37 | 38 | #include 39 | #include "scpi/parser.h" 40 | #include "scpi/units.h" 41 | #include "utils_private.h" 42 | #include "scpi/utils.h" 43 | #include "scpi/error.h" 44 | #include "lexer_private.h" 45 | 46 | 47 | /* 48 | * multipliers IEEE 488.2-1992 tab 7-2 49 | * 1E18 EX 50 | * 1E15 PE 51 | * 1E12 T 52 | * 1E9 G 53 | * 1E6 MA (use M for OHM and HZ) 54 | * 1E3 K 55 | * 1E-3 M (disaalowed for OHM and HZ) 56 | * 1E-6 U 57 | * 1E-9 N 58 | * 1E-12 P 59 | * 1E-15 F 60 | * 1E-18 A 61 | */ 62 | 63 | /* 64 | * units definition IEEE 488.2-1992 tab 7-1 65 | */ 66 | const scpi_unit_def_t scpi_units_def[] = { 67 | #if USE_UNITS_PARTICLES 68 | /* Absorbet dose */ 69 | {/* name */ "GY", /* unit */ SCPI_UNIT_GRAY, /* mult */ 1}, 70 | 71 | /* Activity of radionuclide */ 72 | {/* name */ "BQ", /* unit */ SCPI_UNIT_BECQUEREL, /* mult */ 1}, 73 | 74 | /* Amount of substance */ 75 | {/* name */ "MOL", /* unit */ SCPI_UNIT_MOLE, /* mult */ 1}, 76 | 77 | /* Dose equivalent */ 78 | {/* name */ "NSV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e-9}, 79 | {/* name */ "USV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e-6}, 80 | {/* name */ "MSV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e-3}, 81 | {/* name */ "SV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1}, 82 | {/* name */ "KSV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e3}, 83 | {/* name */ "MASV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e6}, 84 | 85 | /* Energy */ 86 | {/* name */ "EV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1}, 87 | {/* name */ "KEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e3}, 88 | {/* name */ "MAEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e6}, 89 | {/* name */ "GEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e9}, 90 | {/* name */ "TEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e12}, 91 | 92 | /* Mass */ 93 | {/* name */ "U", /* unit */ SCPI_UNIT_ATOMIC_MASS, /* mult */ 1}, 94 | #endif /* USE_UNITS_PARTICLES */ 95 | 96 | #if USE_UNITS_ANGLE 97 | /* Angle */ 98 | {/* name */ "DEG", /* unit */ SCPI_UNIT_DEGREE, /* mult */ 1}, 99 | {/* name */ "GON", /* unit */ SCPI_UNIT_GRADE, /* mult */ 1}, 100 | {/* name */ "MNT", /* unit */ SCPI_UNIT_DEGREE, /* mult */ 1. / 60.}, 101 | {/* name */ "RAD", /* unit */ SCPI_UNIT_RADIAN, /* mult */ 1}, 102 | {/* name */ "SEC", /* unit */ SCPI_UNIT_DEGREE, /* mult */ 1. / 3600.}, 103 | {/* name */ "REV", /* unit */ SCPI_UNIT_REVOLUTION, /* mult */ 1}, 104 | {/* name */ "RS", /* unit */ SCPI_UNIT_STERADIAN, /* mult */ 1}, 105 | #endif /* USE_UNITS_ANGLE */ 106 | 107 | #if USE_UNITS_ELECTRIC 108 | /* Electric - capacitance */ 109 | {/* name */ "PF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-12}, 110 | {/* name */ "NF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-9}, 111 | {/* name */ "UF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-6}, 112 | {/* name */ "MF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-3}, 113 | {/* name */ "F", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1}, 114 | 115 | /* Electric - current */ 116 | {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6}, 117 | {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3}, 118 | {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1}, 119 | {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3}, 120 | 121 | /* Electric - potential */ 122 | {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6}, 123 | {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3}, 124 | {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1}, 125 | {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3}, 126 | 127 | /* Electric - resistance */ 128 | {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1}, 129 | {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3}, 130 | {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6}, 131 | 132 | /* Inductance */ 133 | {/* name */ "UH", /* unit */ SCPI_UNIT_HENRY, /* mult */ 1e-6}, 134 | {/* name */ "MH", /* unit */ SCPI_UNIT_HENRY, /* mult */ 1e-3}, 135 | {/* name */ "H", /* unit */ SCPI_UNIT_HENRY, /* mult */ 1}, 136 | #endif /* USE_UNITS_ELECTRIC */ 137 | 138 | #if USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE 139 | /* Electric - charge */ 140 | {/* name */ "C", /* unit */ SCPI_UNIT_COULOMB, /* mult */ 1}, 141 | 142 | /* Electric - conductance */ 143 | {/* name */ "USIE", /* unit */ SCPI_UNIT_SIEMENS, /* mult */ 1e-6}, 144 | {/* name */ "MSIE", /* unit */ SCPI_UNIT_SIEMENS, /* mult */ 1e-3}, 145 | {/* name */ "SIE", /* unit */ SCPI_UNIT_SIEMENS, /* mult */ 1}, 146 | #endif /* USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE */ 147 | 148 | #if USE_UNITS_ENERGY_FORCE_MASS 149 | /* Energy */ 150 | {/* name */ "J", /* unit */ SCPI_UNIT_JOULE, /* mult */ 1}, 151 | {/* name */ "KJ", /* unit */ SCPI_UNIT_JOULE, /* mult */ 1e3}, 152 | {/* name */ "MAJ", /* unit */ SCPI_UNIT_JOULE, /* mult */ 1e6}, 153 | 154 | /* Force */ 155 | {/* name */ "N", /* unit */ SCPI_UNIT_NEWTON, /* mult */ 1}, 156 | {/* name */ "KN", /* unit */ SCPI_UNIT_NEWTON, /* mult */ 1e3}, 157 | 158 | /* Pressure */ 159 | {/* name */ "ATM", /* unit */ SCPI_UNIT_ATMOSPHERE, /* mult */ 1}, 160 | {/* name */ "INHG", /* unit */ SCPI_UNIT_INCH_OF_MERCURY, /* mult */ 1}, 161 | {/* name */ "MMHG", /* unit */ SCPI_UNIT_MM_OF_MERCURY, /* mult */ 1}, 162 | 163 | {/* name */ "TORR", /* unit */ SCPI_UNIT_TORT, /* mult */ 1}, 164 | {/* name */ "BAR", /* unit */ SCPI_UNIT_BAR, /* mult */ 1}, 165 | 166 | {/* name */ "PAL", /* unit */ SCPI_UNIT_PASCAL, /* mult */ 1}, 167 | {/* name */ "KPAL", /* unit */ SCPI_UNIT_PASCAL, /* mult */ 1e3}, 168 | {/* name */ "MAPAL", /* unit */ SCPI_UNIT_PASCAL, /* mult */ 1e6}, 169 | 170 | /* Viscosity kinematic */ 171 | {/* name */ "ST", /* unit */ SCPI_UNIT_STROKES, /* mult */ 1}, 172 | 173 | /* Viscosity dynamic */ 174 | {/* name */ "P", /* unit */ SCPI_UNIT_POISE, /* mult */ 1}, 175 | 176 | /* Viscosity dynamic */ 177 | {/* name */ "L", /* unit */ SCPI_UNIT_LITER, /* mult */ 1}, 178 | 179 | /* Mass */ 180 | {/* name */ "MG", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1e-6}, 181 | {/* name */ "G", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1e-3}, 182 | {/* name */ "KG", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1}, 183 | {/* name */ "TNE", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1000}, 184 | #endif /* USE_UNITS_ENERGY_FORCE_MASS */ 185 | 186 | #if USE_UNITS_FREQUENCY 187 | /* Frequency */ 188 | {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1}, 189 | {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3}, 190 | {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6}, 191 | {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9}, 192 | #endif /* USE_UNITS_FREQUENCY */ 193 | 194 | #if USE_UNITS_DISTANCE 195 | /* Length */ 196 | {/* name */ "ASU", /* unit */ SCPI_UNIT_ASTRONOMIC_UNIT, /* mult */ 1}, 197 | {/* name */ "PRS", /* unit */ SCPI_UNIT_PARSEC, /* mult */ 1}, 198 | #if USE_UNITS_IMPERIAL 199 | {/* name */ "IN", /* unit */ SCPI_UNIT_INCH, /* mult */ 1}, 200 | {/* name */ "FT", /* unit */ SCPI_UNIT_FOOT, /* mult */ 1}, 201 | {/* name */ "MI", /* unit */ SCPI_UNIT_MILE, /* mult */ 1}, 202 | {/* name */ "NAMI", /* unit */ SCPI_UNIT_NAUTICAL_MILE, /* mult */ 1}, 203 | #endif /* USE_UNITS_IMPERIAL */ 204 | 205 | {/* name */ "NM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e-9}, 206 | {/* name */ "UM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e-6}, 207 | {/* name */ "MM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e-3}, 208 | {/* name */ "M", /* unit */ SCPI_UNIT_METER, /* mult */ 1}, 209 | {/* name */ "KM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e3}, 210 | #endif /* USE_UNITS_DISTANCE */ 211 | 212 | #if USE_UNITS_LIGHT 213 | /* Illuminance */ 214 | {/* name */ "LX", /* unit */ SCPI_UNIT_LUX, /* mult */ 1}, 215 | 216 | /* Luminous flux */ 217 | {/* name */ "LM", /* unit */ SCPI_UNIT_LUMEN, /* mult */ 1}, 218 | 219 | /* Luminous intensity */ 220 | {/* name */ "CD", /* unit */ SCPI_UNIT_CANDELA, /* mult */ 1}, 221 | #endif /* USE_UNITS_LIGHT */ 222 | 223 | #if USE_UNITS_MAGNETIC 224 | /* Magnetic flux */ 225 | {/* name */ "WB", /* unit */ SCPI_UNIT_WEBER, /* mult */ 1}, 226 | 227 | /* Magnetic induction */ 228 | {/* name */ "NT", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1e-9}, 229 | {/* name */ "UT", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1e-6}, 230 | {/* name */ "MT", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1e-3}, 231 | {/* name */ "T", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1}, 232 | #endif /* USE_UNITS_MAGNETIC */ 233 | 234 | #if USE_UNITS_POWER 235 | /* Power */ 236 | {/* name */ "W", /* unit */ SCPI_UNIT_WATT, /* mult */ 1}, 237 | {/* name */ "DBM", /* unit */ SCPI_UNIT_DBM, /* mult */ 1}, 238 | {/* name */ "DBMW", /* unit */ SCPI_UNIT_DBM, /* mult */ 1}, 239 | #endif /* USE_UNITS_POWER */ 240 | 241 | #if USE_UNITS_RATIO 242 | /* Ratio */ 243 | {/* name */ "DB", /* unit */ SCPI_UNIT_DECIBEL, /* mult */ 1}, 244 | {/* name */ "PCT", /* unit */ SCPI_UNIT_UNITLESS, /* mult */ 1e-2}, 245 | {/* name */ "PPM", /* unit */ SCPI_UNIT_UNITLESS, /* mult */ 1e-6}, 246 | #endif /* USE_UNITS_RATIO */ 247 | 248 | #if USE_UNITS_TEMPERATURE 249 | /* Temperature */ 250 | {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1}, 251 | #if USE_UNITS_IMPERIAL 252 | {/* name */ "FAR", /* unit */ SCPI_UNIT_FAHRENHEIT, /* mult */ 1}, 253 | #endif /* USE_UNITS_IMPERIAL */ 254 | {/* name */ "K", /* unit */ SCPI_UNIT_KELVIN, /* mult */ 1}, 255 | #endif /* USE_UNITS_TEMPERATURE */ 256 | 257 | #if USE_UNITS_TIME 258 | /* Time */ 259 | {/* name */ "PS", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-12}, 260 | {/* name */ "NS", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-9}, 261 | {/* name */ "US", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-6}, 262 | {/* name */ "MS", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-3}, 263 | {/* name */ "S", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1}, 264 | {/* name */ "MIN", /* unit */ SCPI_UNIT_SECOND, /* mult */ 60}, 265 | {/* name */ "HR", /* unit */ SCPI_UNIT_SECOND, /* mult */ 3600}, 266 | {/* name */ "D", /* unit */ SCPI_UNIT_DAY, /* mult */ 1}, 267 | {/* name */ "ANN", /* unit */ SCPI_UNIT_YEAR, /* mult */ 1}, 268 | #endif /* USE_UNITS_TIME */ 269 | 270 | SCPI_UNITS_LIST_END, 271 | }; 272 | 273 | /* 274 | * Special number values definition 275 | */ 276 | const scpi_choice_def_t scpi_special_numbers_def[] = { 277 | {/* name */ "MINimum", /* type */ SCPI_NUM_MIN}, 278 | {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX}, 279 | {/* name */ "DEFault", /* type */ SCPI_NUM_DEF}, 280 | {/* name */ "UP", /* type */ SCPI_NUM_UP}, 281 | {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN}, 282 | {/* name */ "NAN", /* type */ SCPI_NUM_NAN}, 283 | {/* name */ "INFinity", /* type */ SCPI_NUM_INF}, 284 | {/* name */ "NINF", /* type */ SCPI_NUM_NINF}, 285 | {/* name */ "AUTO", /* type */ SCPI_NUM_AUTO}, 286 | SCPI_CHOICE_LIST_END, 287 | }; 288 | 289 | /** 290 | * Convert string describing unit to its representation 291 | * @param units units patterns 292 | * @param unit text representation of unknown unit 293 | * @param len length of text representation 294 | * @return pointer of related unit definition or NULL 295 | */ 296 | static const scpi_unit_def_t * translateUnit(const scpi_unit_def_t * units, const char * unit, size_t len) { 297 | int i; 298 | 299 | if (units == NULL) { 300 | return NULL; 301 | } 302 | 303 | for (i = 0; units[i].name != NULL; i++) { 304 | if (compareStr(unit, len, units[i].name, strlen(units[i].name))) { 305 | return &units[i]; 306 | } 307 | } 308 | 309 | return NULL; 310 | } 311 | 312 | /** 313 | * Convert unit definition to string 314 | * @param units units definitions (patterns) 315 | * @param unit type of unit 316 | * @return string representation of unit 317 | */ 318 | static const char * translateUnitInverse(const scpi_unit_def_t * units, const scpi_unit_t unit) { 319 | int i; 320 | 321 | if (units == NULL) { 322 | return NULL; 323 | } 324 | 325 | for (i = 0; units[i].name != NULL; i++) { 326 | if ((units[i].unit == unit) && (units[i].mult == 1)) { 327 | return units[i].name; 328 | } 329 | } 330 | 331 | return NULL; 332 | } 333 | 334 | /** 335 | * Transform number to base units 336 | * @param context 337 | * @param unit text representation of unit 338 | * @param len length of text representation 339 | * @param value preparsed numeric value 340 | * @return TRUE if value parameter was converted to base units 341 | */ 342 | static scpi_bool_t transformNumber(scpi_t * context, const char * unit, size_t len, scpi_number_t * value) { 343 | size_t s; 344 | const scpi_unit_def_t * unitDef; 345 | s = skipWhitespace(unit, len); 346 | 347 | if (s == len) { 348 | value->unit = SCPI_UNIT_NONE; 349 | return TRUE; 350 | } 351 | 352 | unitDef = translateUnit(context->units, unit + s, len - s); 353 | 354 | if (unitDef == NULL) { 355 | SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SUFFIX); 356 | return FALSE; 357 | } 358 | 359 | value->content.value *= unitDef->mult; 360 | value->unit = unitDef->unit; 361 | 362 | return TRUE; 363 | } 364 | 365 | /** 366 | * Parse parameter as number, number with unit or special value (min, max, default, ...) 367 | * @param context 368 | * @param value return value 369 | * @param mandatory if the parameter is mandatory 370 | * @return 371 | */ 372 | scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory) { 373 | scpi_token_t token; 374 | lex_state_t state; 375 | scpi_parameter_t param; 376 | scpi_bool_t result; 377 | int32_t tag; 378 | 379 | if (!value) { 380 | SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 381 | return FALSE; 382 | } 383 | 384 | result = SCPI_Parameter(context, ¶m, mandatory); 385 | 386 | if (!result) { 387 | return result; 388 | } 389 | 390 | state.buffer = param.ptr; 391 | state.pos = state.buffer; 392 | state.len = param.len; 393 | 394 | switch (param.type) { 395 | case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 396 | case SCPI_TOKEN_HEXNUM: 397 | case SCPI_TOKEN_OCTNUM: 398 | case SCPI_TOKEN_BINNUM: 399 | case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 400 | case SCPI_TOKEN_PROGRAM_MNEMONIC: 401 | value->unit = SCPI_UNIT_NONE; 402 | value->special = FALSE; 403 | result = TRUE; 404 | break; 405 | default: 406 | break; 407 | } 408 | 409 | switch (param.type) { 410 | case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 411 | case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 412 | case SCPI_TOKEN_PROGRAM_MNEMONIC: 413 | value->base = 10; 414 | break; 415 | case SCPI_TOKEN_BINNUM: 416 | value->base = 2; 417 | break; 418 | case SCPI_TOKEN_HEXNUM: 419 | value->base = 16; 420 | break; 421 | case SCPI_TOKEN_OCTNUM: 422 | value->base = 8; 423 | break; 424 | default: 425 | break; 426 | } 427 | 428 | switch (param.type) { 429 | case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 430 | SCPI_ParamToDouble(context, ¶m, &(value->content.value)); 431 | break; 432 | case SCPI_TOKEN_HEXNUM: 433 | SCPI_ParamToDouble(context, ¶m, &(value->content.value)); 434 | break; 435 | case SCPI_TOKEN_OCTNUM: 436 | SCPI_ParamToDouble(context, ¶m, &(value->content.value)); 437 | break; 438 | case SCPI_TOKEN_BINNUM: 439 | SCPI_ParamToDouble(context, ¶m, &(value->content.value)); 440 | break; 441 | case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 442 | scpiLex_DecimalNumericProgramData(&state, &token); 443 | scpiLex_WhiteSpace(&state, &token); 444 | scpiLex_SuffixProgramData(&state, &token); 445 | 446 | SCPI_ParamToDouble(context, ¶m, &(value->content.value)); 447 | 448 | result = transformNumber(context, token.ptr, token.len, value); 449 | break; 450 | case SCPI_TOKEN_PROGRAM_MNEMONIC: 451 | scpiLex_WhiteSpace(&state, &token); 452 | scpiLex_CharacterProgramData(&state, &token); 453 | 454 | /* convert string to special number type */ 455 | result = SCPI_ParamToChoice(context, &token, special, &tag); 456 | 457 | value->special = TRUE; 458 | value->content.tag = tag; 459 | 460 | break; 461 | default: 462 | result = FALSE; 463 | } 464 | 465 | return result; 466 | } 467 | 468 | /** 469 | * Convert scpi_number_t to string 470 | * @param context 471 | * @param value number value 472 | * @param str target string 473 | * @param len max length of string including null-character termination 474 | * @return number of chars written to string 475 | */ 476 | size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len) { 477 | const char * type; 478 | const char * unit; 479 | size_t result; 480 | 481 | if (!value || !str || len==0) { 482 | return 0; 483 | } 484 | 485 | if (value->special) { 486 | if (SCPI_ChoiceToName(special, value->content.tag, &type)) { 487 | strncpy(str, type, len); 488 | result = SCPIDEFINE_strnlen(str, len - 1); 489 | str[result] = '\0'; 490 | return result; 491 | } else { 492 | str[0] = '\0'; 493 | return 0; 494 | } 495 | } 496 | 497 | result = SCPI_DoubleToStr(value->content.value, str, len); 498 | 499 | if (result + 1 < len) { 500 | unit = translateUnitInverse(context->units, value->unit); 501 | 502 | if (unit) { 503 | strncat(str, " ", len - result); 504 | if (result + 2 < len) { 505 | strncat(str, unit, len - result - 1); 506 | } 507 | result = strlen(str); 508 | } 509 | } 510 | 511 | return result; 512 | } 513 | -------------------------------------------------------------------------------- /src/src/utils_private.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2012-2018, Jan Breuer 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * @file scpi_utils.h 31 | * @date Thu Nov 15 10:58:45 UTC 2012 32 | * 33 | * @brief Conversion routines and string manipulation routines 34 | * 35 | * 36 | */ 37 | 38 | #ifndef SCPI_UTILS_PRIVATE_H 39 | #define SCPI_UTILS_PRIVATE_H 40 | 41 | #include 42 | #include "scpi/config.h" 43 | #include "scpi/types.h" 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | #if defined(__GNUC__) && (__GNUC__ >= 4) 50 | #define LOCAL __attribute__((visibility ("hidden"))) 51 | #else 52 | #define LOCAL 53 | #endif 54 | 55 | char * strnpbrk(const char *str, size_t size, const char *set) LOCAL; 56 | scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL; 57 | scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) LOCAL; 58 | size_t UInt32ToStrBaseSign(uint32_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) LOCAL; 59 | size_t UInt64ToStrBaseSign(uint64_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) LOCAL; 60 | size_t strBaseToInt32(const char * str, int32_t * val, int8_t base) LOCAL; 61 | size_t strBaseToUInt32(const char * str, uint32_t * val, int8_t base) LOCAL; 62 | size_t strBaseToInt64(const char * str, int64_t * val, int8_t base) LOCAL; 63 | size_t strBaseToUInt64(const char * str, uint64_t * val, int8_t base) LOCAL; 64 | size_t strToFloat(const char * str, float * val) LOCAL; 65 | size_t strToDouble(const char * str, double * val) LOCAL; 66 | scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; 67 | scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; 68 | size_t skipWhitespace(const char * cmd, size_t len) LOCAL; 69 | scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) LOCAL; 70 | scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len, int32_t default_value) LOCAL; 71 | scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) LOCAL; 72 | 73 | #define SCPI_DTOSTRE_UPPERCASE 1 74 | #define SCPI_DTOSTRE_ALWAYS_SIGN 2 75 | #define SCPI_DTOSTRE_PLUS_SIGN 4 76 | char * SCPI_dtostre(double __val, char * __s, size_t __ssize, unsigned char __prec, unsigned char __flags); 77 | 78 | scpi_array_format_t SCPI_GetNativeFormat(void); 79 | uint16_t SCPI_Swap16(uint16_t val); 80 | uint32_t SCPI_Swap32(uint32_t val); 81 | uint64_t SCPI_Swap64(uint64_t val); 82 | 83 | #if !HAVE_STRNLEN 84 | size_t BSD_strnlen(const char *s, size_t maxlen) LOCAL; 85 | #endif 86 | 87 | #if !HAVE_STRNCASECMP && !HAVE_STRNICMP 88 | int OUR_strncasecmp(const char *s1, const char *s2, size_t n) LOCAL; 89 | #endif 90 | 91 | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE 92 | void scpiheap_init(scpi_error_info_heap_t * heap, char * error_info_heap, size_t error_info_heap_length); 93 | char * scpiheap_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) LOCAL; 94 | void scpiheap_free(scpi_error_info_heap_t * heap, char *s, scpi_bool_t rollback) LOCAL; 95 | scpi_bool_t scpiheap_get_parts(scpi_error_info_heap_t * heap, const char *s1, size_t * len1, const char ** s2, size_t * len2) LOCAL; 96 | #endif 97 | 98 | #if !HAVE_STRNDUP 99 | char *OUR_strndup(const char *s, size_t n); 100 | #endif 101 | 102 | #ifndef min 103 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 104 | #endif 105 | 106 | #ifndef max 107 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 108 | #endif 109 | 110 | #if 0 111 | #define max(a,b) \ 112 | ({ __typeof__ (a) _a = (a); \ 113 | __typeof__ (b) _b = (b); \ 114 | _a > _b ? _a : _b; }) 115 | 116 | #define min(a,b) \ 117 | ({ __typeof__ (a) _a = (a); \ 118 | __typeof__ (b) _b = (b); \ 119 | _a < _b ? _a : _b; }) 120 | 121 | #endif 122 | 123 | #ifdef __cplusplus 124 | } 125 | #endif 126 | 127 | #endif /* SCPI_UTILS_PRIVATE_H */ 128 | 129 | --------------------------------------------------------------------------------