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

Dependents:   scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers units.c Source File

units.c

00001 /*-
00002  * Copyright (c) 2012-2013 Jan Breuer,
00003  *
00004  * All Rights Reserved
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are
00008  * met:
00009  * 1. Redistributions of source code must retain the above copyright notice,
00010  *    this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00018  * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
00019  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00022  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00023  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00024  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 /**
00029  * @file   scpi_units.c
00030  * @date   Thu Nov 15 10:58:45 UTC 2012
00031  * 
00032  * @brief  SCPI units
00033  * 
00034  * 
00035  */
00036 
00037 #include <string.h>
00038 #include "scpi/parser.h"
00039 #include "scpi/units.h"
00040 #include "utils_private.h"
00041 #include "scpi/utils.h"
00042 #include "scpi/error.h"
00043 #include "lexer_private.h"
00044 
00045 
00046 /*
00047  * multipliers IEEE 488.2-1992 tab 7-2
00048  * 1E18         EX
00049  * 1E15         PE
00050  * 1E12         T
00051  * 1E9          G
00052  * 1E6          MA (use M for OHM and HZ)
00053  * 1E3          K
00054  * 1E-3         M (disaalowed for OHM and HZ)
00055  * 1E-6         U
00056  * 1E-9         N
00057  * 1E-12        P
00058  * 1E-15        F
00059  * 1E-18        A
00060  */
00061 
00062 /*
00063  * units definition IEEE 488.2-1992 tab 7-1
00064  */
00065 const scpi_unit_def_t scpi_units_def[] = {
00066     /* voltage */
00067     {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6},
00068     {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3},
00069     {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1},
00070     {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3},
00071 
00072     /* current */
00073     {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6},
00074     {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3},
00075     {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1},
00076     {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3},
00077 
00078     /* resistance */
00079     {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1},
00080     {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3},
00081     {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6},
00082 
00083     /* frequency */
00084     {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1},
00085     {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3},
00086     {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6},
00087     {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9},
00088 
00089     /* temperature */
00090     {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1},
00091 
00092     /* time */
00093     {/* name */ "PS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-12},
00094     {/* name */ "NS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-9},
00095     {/* name */ "US", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-6},
00096     {/* name */ "MS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-3},
00097     {/* name */ "S", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1},
00098     {/* name */ "MIN", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 60},
00099     {/* name */ "HR", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 3600},
00100 
00101     SCPI_UNITS_LIST_END,
00102 };
00103 
00104 /*
00105  * Special number values definition
00106  */
00107 const scpi_choice_def_t scpi_special_numbers_def[] = {
00108     {/* name */ "MINimum", /* type */ SCPI_NUM_MIN},
00109     {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX},
00110     {/* name */ "DEFault", /* type */ SCPI_NUM_DEF},
00111     {/* name */ "UP", /* type */ SCPI_NUM_UP},
00112     {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN},
00113     {/* name */ "NAN", /* type */ SCPI_NUM_NAN},
00114     {/* name */ "INFinity", /* type */ SCPI_NUM_INF},
00115     {/* name */ "NINF", /* type */ SCPI_NUM_NINF},
00116     {/* name */ "AUTO", /* type */ SCPI_NUM_AUTO},
00117     SCPI_CHOICE_LIST_END,
00118 };
00119 
00120 /**
00121  * Convert string describing unit to its representation
00122  * @param units units patterns
00123  * @param unit text representation of unknown unit
00124  * @param len length of text representation
00125  * @return pointer of related unit definition or NULL
00126  */
00127 static const scpi_unit_def_t * translateUnit(const scpi_unit_def_t * units, const char * unit, size_t len) {
00128     int i;
00129 
00130     if (units == NULL) {
00131         return NULL;
00132     }
00133 
00134     for (i = 0; units[i].name != NULL; i++) {
00135         if (compareStr(unit, len, units[i].name, strlen(units[i].name))) {
00136             return &units[i];
00137         }
00138     }
00139 
00140     return NULL;
00141 }
00142 
00143 /**
00144  * Convert unit definition to string
00145  * @param units units definitions (patterns)
00146  * @param unit type of unit
00147  * @return string representation of unit
00148  */
00149 static const char * translateUnitInverse(const scpi_unit_def_t * units, const scpi_unit_t unit) {
00150     int i;
00151 
00152     if (units == NULL) {
00153         return NULL;
00154     }
00155 
00156     for (i = 0; units[i].name != NULL; i++) {
00157         if ((units[i].unit == unit) && (units[i].mult == 1)) {
00158             return units[i].name;
00159         }
00160     }
00161 
00162     return NULL;
00163 }
00164 
00165 /**
00166  * Transform number to base units
00167  * @param context
00168  * @param unit text representation of unit
00169  * @param len length of text representation
00170  * @param value preparsed numeric value
00171  * @return TRUE if value parameter was converted to base units
00172  */
00173 static scpi_bool_t transformNumber(scpi_t * context, const char * unit, size_t len, scpi_number_t * value) {
00174     size_t s;
00175     const scpi_unit_def_t * unitDef;
00176     s = skipWhitespace(unit, len);
00177 
00178     if (s == len) {
00179         value->unit = SCPI_UNIT_NONE;
00180         return TRUE;
00181     }
00182 
00183     unitDef = translateUnit(context->units, unit + s, len - s);
00184 
00185     if (unitDef == NULL) {
00186         SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SUFFIX);
00187         return FALSE;
00188     }
00189 
00190     value->value *= unitDef->mult;
00191     value->unit = unitDef->unit;
00192 
00193     return TRUE;
00194 }
00195 
00196 /**
00197  * Parse parameter as number, number with unit or special value (min, max, default, ...)
00198  * @param context
00199  * @param value return value
00200  * @param mandatory if the parameter is mandatory
00201  * @return 
00202  */
00203 scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory)
00204 {
00205     scpi_token_t token;
00206     lex_state_t state;
00207     scpi_parameter_t param;
00208     scpi_bool_t result;
00209     int32_t tag;
00210 
00211     if (!value) {
00212         SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
00213         return FALSE;
00214     }
00215 
00216     result = SCPI_Parameter(context, &param, mandatory);
00217 
00218     if (!result) {
00219         return result;
00220     }
00221 
00222     state.buffer = param.ptr;
00223     state.pos = state.buffer;
00224     state.len = param.len;
00225 
00226     switch(param.type) {
00227         case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
00228         case SCPI_TOKEN_HEXNUM:
00229         case SCPI_TOKEN_OCTNUM:
00230         case SCPI_TOKEN_BINNUM:
00231         case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
00232         case SCPI_TOKEN_PROGRAM_MNEMONIC:
00233             value->unit = SCPI_UNIT_NONE;
00234             value->special = FALSE;
00235             result = TRUE;
00236             break;
00237     }
00238 
00239     switch(param.type) {
00240         case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
00241         case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
00242         case SCPI_TOKEN_PROGRAM_MNEMONIC:
00243             value->base = 10;
00244             break;
00245         case SCPI_TOKEN_BINNUM:
00246             value->base = 2;
00247             break;
00248         case SCPI_TOKEN_HEXNUM:
00249             value->base = 16;
00250             break;
00251         case SCPI_TOKEN_OCTNUM:
00252             value->base = 8;
00253             break;
00254     }
00255 
00256     switch(param.type) {
00257         case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
00258             SCPI_ParamToDouble(context, &param, &(value->value));
00259             break;
00260         case SCPI_TOKEN_HEXNUM:
00261             SCPI_ParamToDouble(context, &param, &(value->value));
00262             break;
00263         case SCPI_TOKEN_OCTNUM:
00264             SCPI_ParamToDouble(context, &param, &(value->value));
00265             break;
00266         case SCPI_TOKEN_BINNUM:
00267             SCPI_ParamToDouble(context, &param, &(value->value));
00268             break;
00269         case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
00270             scpiLex_DecimalNumericProgramData(&state, &token);
00271             scpiLex_WhiteSpace(&state, &token);
00272             scpiLex_SuffixProgramData(&state, &token);
00273 
00274             SCPI_ParamToDouble(context, &param, &(value->value));
00275 
00276             result = transformNumber(context, token.ptr, token.len, value);
00277             break;
00278         case SCPI_TOKEN_PROGRAM_MNEMONIC:
00279             scpiLex_WhiteSpace(&state, &token);
00280             scpiLex_CharacterProgramData(&state, &token);
00281 
00282             /* convert string to special number type */
00283             SCPI_ParamToChoice(context, &token, special, &tag);
00284 
00285             value->special = TRUE;
00286             value->tag = tag;
00287 
00288             break;
00289         default:
00290             result = FALSE;
00291     }
00292 
00293     return result;
00294 }
00295 
00296 /**
00297  * Convert scpi_number_t to string
00298  * @param context
00299  * @param value number value
00300  * @param str target string
00301  * @param len max length of string
00302  * @return number of chars written to string
00303  */
00304 size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len) {
00305     const char * type;
00306     const char * unit;
00307     size_t result;
00308 
00309     if (!value || !str) {
00310         return 0;
00311     }
00312 
00313     if (value->special) {
00314         if (SCPI_ChoiceToName(special, value->tag, &type)) {
00315             strncpy(str, type, len);
00316             return min(strlen(type), len);
00317         } else {
00318             str[0] = 0;
00319             return 0;
00320         }
00321     }
00322 
00323     result = SCPI_DoubleToStr(value->value, str, len);
00324 
00325     unit = translateUnitInverse(context->units, value->unit);
00326 
00327     if (unit) {
00328         strncat(str, " ", len);
00329         strncat(str, unit, len);
00330         result += strlen(unit) + 1;
00331     }
00332 
00333     return result;
00334 }