scpi_numeric.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h'
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include "app/scpi/scpi_core.h"
  6. #include "app/scpi/scpi_core_private.h"
  7. #include "app/scpi/scpi_commands.h"
  8. #include "app/scpi/scpi_parser.h"
  9. #include "app/scpi/scpi_numeric.h"
  10. //----------------------------------------------------------------
  11. // Refer to:
  12. // [1] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
  13. // "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
  14. // Standard Digital Interface for Programmable Instrumentation"
  15. // [2] SCPI Specification, revision 1999.0
  16. // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
  17. //----------------------------------------------------------------
  18. // @processNumericArgument
  19. // Numeric argument validation and conversion function.
  20. // Processes specified SCPI Numeric Parameter (Numeric Program Data) with the most length SCPI_MAX_NUMBER_LENGTH.
  21. // References:
  22. // "7.7.2 <DECIMAL NUMERIC PROGRAM DATA>", [1]
  23. // "7.7.2.2 Encoding Syntax", [1]
  24. // "7.7.4 <NONDECIMAL NUMERIC PROGRAM DATA>", [1]
  25. // "7.7.4.2 Encoding Syntax", [1]
  26. // Parameters:
  27. // @pObj - numeric conversion context;
  28. // @argToken - numeric argument token to process;
  29. // @entityType - SCPI entity type [eScpiEntityType_t] (see @getParsedEntityDetails, 'peEntityType' argument)
  30. // @range - allowed values range structure, optional
  31. // Return:
  32. // - true: parameter processed successfully, the result is stored inside numeric conversion context
  33. // - false: paramenter processing failed.
  34. bool processNumericArgument( sProcessNumericEntry_t * pObj, const sStrToken_t * argToken, uint8_t entityType, const sNumericRange_t * range )
  35. {
  36. bool status = false;
  37. assert( pObj );
  38. assert( argToken );
  39. // keep at least one free character left in the end of the buffer for null-character
  40. if( ((ptrdiff_t)argToken->stail - (ptrdiff_t)argToken->shead) >= SCPI_MAX_NUMBER_LENGTH )
  41. {
  42. pObj->valueEntry.error = ScpiNumericError_DEVICE_RANGE; // too long number
  43. return false;
  44. }
  45. pObj->valueEntry.error = ScpiNumericError;
  46. // fill buffer with zeros, the last character must be '\0'
  47. memset( pObj->numberBuffer, 0, sizeof(pObj->numberBuffer) );
  48. // copy number to the null-terminated buffer
  49. strncpy( pObj->numberBuffer, argToken->shead, ((ptrdiff_t)argToken->stail - (ptrdiff_t)argToken->shead) );
  50. // fill the @valueType to specify the value type to be accessed in @pObj->Value
  51. pObj->valueEntry.valueType = entityType;
  52. int base = 0; // forward set to invalid
  53. char * pEnd = NULL;
  54. switch( entityType )
  55. {
  56. // --- Float ----
  57. case eScpiEntityTypeDemicalFloatNumber: // Demical Number (float, only mantissa)
  58. case eScpiEntityTypeDemicalExpNumber: // Demical Number (scientific, mantissa+exponent)
  59. {
  60. // check range type
  61. if( ! SCPI_NUMERIC_LIMIT_TYPE_IS_FLOAT(range->type) )
  62. {
  63. // invalid range: user limit is set in integer limits
  64. // user expects that the value is integer, but it is not
  65. pObj->valueEntry.error = ScpiNumericError_USER_TYPE;
  66. (void)status; // false
  67. }
  68. else
  69. {
  70. pObj->valueEntry.Value.demicalFloat = strtold( pObj->numberBuffer, &pEnd );
  71. // check for conversion error
  72. if( errno != 0 /*ERANGE*/ )
  73. {
  74. // invalid float conversion: ERANGE?
  75. pObj->valueEntry.error = ScpiNumericError_DEVICE_RANGE;
  76. (void)status; // false
  77. }
  78. // check for limits
  79. else if( NULL != range ) // user limit is set
  80. {
  81. status = ( range->min.f <= pObj->valueEntry.Value.demicalFloat &&
  82. range->max.f >= pObj->valueEntry.Value.demicalFloat );
  83. if( !status )
  84. pObj->valueEntry.error = ScpiNumericError_USER_RANGE;
  85. else
  86. pObj->valueEntry.error = ScpiNumericSuccess;
  87. }
  88. else
  89. {
  90. status = true;
  91. pObj->valueEntry.error = ScpiNumericSuccess;
  92. }
  93. }
  94. }
  95. break;
  96. // --- Integer ---
  97. case eScpiEntityTypeHexNumber: // Hexademical Number
  98. if( 0 == base ) base = 16;
  99. case eScpiEntityTypeOctNumber: // Octal Number
  100. if( 0 == base ) base = 8;
  101. case eScpiEntityTypeBinNumber: // Binary Number
  102. if( 0 == base ) base = 2;
  103. case eScpiEntityTypeDemicalIntegerNumber: // Integer number only, extension for Demical Number
  104. if( 0 == base ) base = 10;
  105. {
  106. pObj->valueEntry.Value.demicalInteger = strtoll( pObj->numberBuffer, &pEnd, base );
  107. // check for conversion error
  108. if( errno != 0 /*ERANGE*/ )
  109. {
  110. // invalid float conversion: ERANGE?
  111. pObj->valueEntry.error = ScpiNumericError_DEVICE_RANGE;
  112. (void)status; // false
  113. }
  114. // check for limits
  115. else if( NULL != range ) // user limit is set
  116. {
  117. // check if the float range is set, but actually integer received
  118. if( SCPI_NUMERIC_LIMIT_TYPE_IS_FLOAT(range->type) )
  119. {
  120. // yep: change processed value type to float (integer promotion to float)
  121. // convert value
  122. pObj->valueEntry.Value.demicalFloat = pObj->valueEntry.Value.demicalInteger; // {type cast}
  123. // change type
  124. pObj->valueEntry.valueType = eScpiEntityTypeDemicalExpNumber;
  125. // check limits
  126. status = ( range->min.f <= pObj->valueEntry.Value.demicalFloat &&
  127. range->max.f >= pObj->valueEntry.Value.demicalFloat );
  128. if( !status )
  129. pObj->valueEntry.error = ScpiNumericError_USER_RANGE;
  130. else
  131. pObj->valueEntry.error = ScpiNumericSuccess;
  132. }
  133. else
  134. if( SCPI_NUMERIC_LIMIT_TYPE_IS_INTEGER(range->type) )
  135. {
  136. // no: integer limit for integer value
  137. status = ( range->min.i <= pObj->valueEntry.Value.demicalInteger &&
  138. range->max.i >= pObj->valueEntry.Value.demicalInteger );
  139. if( !status )
  140. pObj->valueEntry.error = ScpiNumericError_USER_RANGE;
  141. else
  142. pObj->valueEntry.error = ScpiNumericSuccess;
  143. }
  144. else
  145. {
  146. (void)status; (void)pObj->valueEntry.error; // false, ScpiNumericError
  147. }
  148. }
  149. else
  150. {
  151. status = true;
  152. pObj->valueEntry.error = ScpiNumericSuccess;
  153. }
  154. }
  155. break;
  156. default: (void)status; (void)pObj->valueEntry.error; // false, ScpiNumericError;
  157. }
  158. if( status )
  159. pObj->valueEntry.error = ScpiNumericSuccess;
  160. return status;
  161. }