| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h'
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include "app/scpi/scpi_core.h"
- #include "app/scpi/scpi_core_private.h"
- #include "app/scpi/scpi_commands.h"
- #include "app/scpi/scpi_parser.h"
- #include "app/scpi/scpi_numeric.h"
- //----------------------------------------------------------------
- // Refer to:
- // [1] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
- // "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
- // Standard Digital Interface for Programmable Instrumentation"
- // [2] SCPI Specification, revision 1999.0
- // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
- //----------------------------------------------------------------
- // @processNumericArgument
- // Numeric argument validation and conversion function.
- // Processes specified SCPI Numeric Parameter (Numeric Program Data) with the most length SCPI_MAX_NUMBER_LENGTH.
- // References:
- // "7.7.2 <DECIMAL NUMERIC PROGRAM DATA>", [1]
- // "7.7.2.2 Encoding Syntax", [1]
- // "7.7.4 <NONDECIMAL NUMERIC PROGRAM DATA>", [1]
- // "7.7.4.2 Encoding Syntax", [1]
- // Parameters:
- // @pObj - numeric conversion context;
- // @argToken - numeric argument token to process;
- // @entityType - SCPI entity type [eScpiEntityType_t] (see @getParsedEntityDetails, 'peEntityType' argument)
- // @range - allowed values range structure, optional
- // Return:
- // - true: parameter processed successfully, the result is stored inside numeric conversion context
- // - false: paramenter processing failed.
- bool processNumericArgument( sProcessNumericEntry_t * pObj, const sStrToken_t * argToken, uint8_t entityType, const sNumericRange_t * range )
- {
- bool status = false;
- assert( pObj );
- assert( argToken );
-
- // keep at least one free character left in the end of the buffer for null-character
- if( ((ptrdiff_t)argToken->stail - (ptrdiff_t)argToken->shead) >= SCPI_MAX_NUMBER_LENGTH )
- {
- pObj->valueEntry.error = ScpiNumericError_DEVICE_RANGE; // too long number
- return false;
- }
- pObj->valueEntry.error = ScpiNumericError;
- // fill buffer with zeros, the last character must be '\0'
- memset( pObj->numberBuffer, 0, sizeof(pObj->numberBuffer) );
- // copy number to the null-terminated buffer
- strncpy( pObj->numberBuffer, argToken->shead, ((ptrdiff_t)argToken->stail - (ptrdiff_t)argToken->shead) );
- // fill the @valueType to specify the value type to be accessed in @pObj->Value
- pObj->valueEntry.valueType = entityType;
-
- int base = 0; // forward set to invalid
- char * pEnd = NULL;
- switch( entityType )
- {
- // --- Float ----
- case eScpiEntityTypeDemicalFloatNumber: // Demical Number (float, only mantissa)
- case eScpiEntityTypeDemicalExpNumber: // Demical Number (scientific, mantissa+exponent)
- {
- // check range type
- if( ! SCPI_NUMERIC_LIMIT_TYPE_IS_FLOAT(range->type) )
- {
- // invalid range: user limit is set in integer limits
- // user expects that the value is integer, but it is not
- pObj->valueEntry.error = ScpiNumericError_USER_TYPE;
- (void)status; // false
- }
- else
- {
- pObj->valueEntry.Value.demicalFloat = strtold( pObj->numberBuffer, &pEnd );
- // check for conversion error
- if( errno != 0 /*ERANGE*/ )
- {
- // invalid float conversion: ERANGE?
- pObj->valueEntry.error = ScpiNumericError_DEVICE_RANGE;
- (void)status; // false
- }
- // check for limits
- else if( NULL != range ) // user limit is set
- {
- status = ( range->min.f <= pObj->valueEntry.Value.demicalFloat &&
- range->max.f >= pObj->valueEntry.Value.demicalFloat );
- if( !status )
- pObj->valueEntry.error = ScpiNumericError_USER_RANGE;
- else
- pObj->valueEntry.error = ScpiNumericSuccess;
- }
- else
- {
- status = true;
- pObj->valueEntry.error = ScpiNumericSuccess;
- }
- }
- }
- break;
-
- // --- Integer ---
- case eScpiEntityTypeHexNumber: // Hexademical Number
- if( 0 == base ) base = 16;
- case eScpiEntityTypeOctNumber: // Octal Number
- if( 0 == base ) base = 8;
- case eScpiEntityTypeBinNumber: // Binary Number
- if( 0 == base ) base = 2;
- case eScpiEntityTypeDemicalIntegerNumber: // Integer number only, extension for Demical Number
- if( 0 == base ) base = 10;
- {
- pObj->valueEntry.Value.demicalInteger = strtoll( pObj->numberBuffer, &pEnd, base );
-
- // check for conversion error
- if( errno != 0 /*ERANGE*/ )
- {
- // invalid float conversion: ERANGE?
- pObj->valueEntry.error = ScpiNumericError_DEVICE_RANGE;
- (void)status; // false
- }
- // check for limits
- else if( NULL != range ) // user limit is set
- {
- // check if the float range is set, but actually integer received
- if( SCPI_NUMERIC_LIMIT_TYPE_IS_FLOAT(range->type) )
- {
- // yep: change processed value type to float (integer promotion to float)
- // convert value
- pObj->valueEntry.Value.demicalFloat = pObj->valueEntry.Value.demicalInteger; // {type cast}
- // change type
- pObj->valueEntry.valueType = eScpiEntityTypeDemicalExpNumber;
- // check limits
- status = ( range->min.f <= pObj->valueEntry.Value.demicalFloat &&
- range->max.f >= pObj->valueEntry.Value.demicalFloat );
- if( !status )
- pObj->valueEntry.error = ScpiNumericError_USER_RANGE;
- else
- pObj->valueEntry.error = ScpiNumericSuccess;
- }
- else
- if( SCPI_NUMERIC_LIMIT_TYPE_IS_INTEGER(range->type) )
- {
- // no: integer limit for integer value
- status = ( range->min.i <= pObj->valueEntry.Value.demicalInteger &&
- range->max.i >= pObj->valueEntry.Value.demicalInteger );
- if( !status )
- pObj->valueEntry.error = ScpiNumericError_USER_RANGE;
- else
- pObj->valueEntry.error = ScpiNumericSuccess;
- }
- else
- {
- (void)status; (void)pObj->valueEntry.error; // false, ScpiNumericError
- }
- }
- else
- {
- status = true;
- pObj->valueEntry.error = ScpiNumericSuccess;
- }
- }
- break;
- default: (void)status; (void)pObj->valueEntry.error; // false, ScpiNumericError;
- }
- if( status )
- pObj->valueEntry.error = ScpiNumericSuccess;
- return status;
- }
|