memory_table_data.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #include <stdio.h>
  2. #define PRINT_VALUE_MIN_SPACE (40) // DO NOT TOUCH! =40, see @printValues
  3. #define SCPI_ARGS_N 3
  4. #define SCPI_ARGS_MANDATORY_N 2
  5. #include "app/scpi/scpi_handler.h"
  6. // -----
  7. // @argTokens, @argTypes
  8. // Declare argument parser entities
  9. // Supported arguments: 1=CHARACTER, 2=CHARACTER, 3=CHARACTER
  10. DECLARE_SCPI_ARGS( eScpiArg_Character, eScpiArg_Character, eScpiArg_Character );
  11. // Argument 1 Character Values allowed list / ACM Path
  12. DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( MemTable_AllowedValues_AcmPath, "A","B","C","D","AB","AC","AD","BC","BD","CD","CHECk" ); // Order is set by @ePortComb_t
  13. // Argument 2 Character Values allowed list / S-parameter
  14. DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( MemTable_AllowedValues_SParam, "SHORt", "OPEN","LOAD","LOAD2","OPEN2","S11","S21","S12","S22","S13","S14","S23","S24", "S31","S32","S33","S34","S41","S42","S43","S44" ); // Order is set by @ePortStateId_t
  15. // Argument 3 Character Values allowed list / Memory Bank
  16. DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Bank );
  17. #include "app/scpi/commandHandlers/memory_table_data.h"
  18. #include "app/nfm/nfm_base.h"
  19. // Refer to:
  20. // [1] SCPI Specification, revision 1999.0
  21. // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
  22. // [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
  23. // Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
  24. // [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
  25. // "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
  26. // =================================================================================
  27. // @fsqvbl_CommandHandlerMemoryTableData
  28. // State's virtual table
  29. static size_t printValues( char * pcBuffer, size_t szBuffer, const sNFMChrzPoint_t * pValues, size_t nValues, bool theLastOne );
  30. static void fsqe_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
  31. static void fsql_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
  32. static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
  33. const fFSeqVTable_t fsqvbl_CommandHandlerMemoryTableData =
  34. {
  35. .f = fsqf_CommandHandlerMemoryTableData,
  36. .enter = fsqe_CommandHandlerMemoryTableData,
  37. .leave = fsql_CommandHandlerMemoryTableData
  38. };
  39. static void fsqe_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
  40. {
  41. sProcessProgramDataCommonContext_t * common_ctx = ctx;
  42. SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
  43. common_ctx->MemTableData.idx = 0;
  44. common_ctx->MemTableData.nchs = 0;
  45. common_ctx->MemTableData.bank = 0;
  46. common_ctx->MemTableData.comb = 0;
  47. common_ctx->MemTableData.state = 0;
  48. common_ctx->MemTableData.init = false;
  49. common_ctx->MemTableData.isdone = false;
  50. memset( &common_ctx->MemTableData.getctx, 0, sizeof(common_ctx->MemTableData.getctx) );
  51. }
  52. static void fsql_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
  53. {
  54. }
  55. static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this,
  56. tFSeqCtx_t ctx,
  57. const struct fFSeqEntry_t * * pDeferredNext )
  58. {
  59. const fFSeqEntry_t * nextstate = NULL;
  60. sProcessProgramDataCommonContext_t * common_ctx = ctx;
  61. sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
  62. switch( common_ctx->event )
  63. {
  64. case eProgramData_Event_Write:
  65. {
  66. if( ! common_ctx->isQuery )
  67. {
  68. common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
  69. }
  70. else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
  71. {
  72. common_ctx->status = eProgramDataArgumentSyntax; // parameter syntax error, caller should generate error message
  73. }
  74. else
  75. {
  76. common_ctx->status = eProgramDataIllegalArgument; // forward set, illegal parameter value, caller should generate error message
  77. // Get acm path (port combination)
  78. common_ctx->MemTableData.comb = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_AcmPath, 0 );
  79. if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableData.comb ) break; // eProgramDataIllegalArgument
  80. // Get S-Param (port state)
  81. common_ctx->MemTableData.state = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_SParam, 1 );
  82. if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableData.state ) break; // eProgramDataIllegalArgument
  83. // Get memory bank
  84. if( common_ctx->args > 2 )
  85. // process first argument (bank)
  86. common_ctx->MemTableData.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 2 );
  87. else
  88. // default parameter
  89. common_ctx->MemTableData.bank = 0; // Factory
  90. // check result
  91. if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableData.bank ) break; // eProgramDataIllegalArgument
  92. ePortStateId_t portState = (ePortStateId_t)((ePortStateId_MIN) + common_ctx->MemTableData.state);
  93. if( ! NFMClass->methods.checkPortStateAvailable( portState ) )
  94. {
  95. common_ctx->status = eProgramDataIllegalArgument;
  96. common_ctx->argErrIdx = 1; // specify erroneous argument index: S-param
  97. break;
  98. }
  99. ePortComb_t portComb = (ePortComb_t)((ePortComb_MIN) + common_ctx->MemTableData.comb);
  100. if( ! NFMClass->methods.checkPortCombinationAvailable( portComb ) )
  101. {
  102. common_ctx->status = eProgramDataIllegalArgument;
  103. common_ctx->argErrIdx = 0; // specify erroneous argument index: ACM-Path
  104. break;
  105. }
  106. // Check if the combination of ACM-path and port state is legal:
  107. if( NFMClass->methods.checkTableParams( portComb, portState ) )
  108. {
  109. common_ctx->status = eProgramDataNeedRead; // request processed, wait for reading...
  110. }
  111. else
  112. {
  113. common_ctx->status = eProgramDataIllegalArgument; // illegal parameter for this device
  114. common_ctx->argErrIdx = 1; // specify erroneous argument index: S-param
  115. }
  116. }
  117. }
  118. break;
  119. case eProgramData_Event_Read:
  120. {
  121. do
  122. {
  123. // @idx - current position of the source data to be outputed
  124. if( common_ctx->MemTableData.idx >= common_ctx->MemTableData.nchs )
  125. {
  126. if( common_ctx->MemTableData.isdone ) break;
  127. // There no already prepared data in @tempBuffer
  128. if( ! common_ctx->MemTableData.init ) // first reading
  129. {
  130. eChrz_t tableId = (eChrz_t)((eChFactory) + common_ctx->MemTableData.bank);
  131. ePortComb_t portComb = (ePortComb_t)((ePortComb_MIN) + common_ctx->MemTableData.comb);
  132. ePortStateId_t portState = (ePortStateId_t)((ePortStateId_MIN) + common_ctx->MemTableData.state);
  133. common_ctx->status = eProgramDataIllegalArgument; // forward set
  134. if( 0 == NFMClass->methods.xCharacterization.getPoints_Init( tableId,
  135. portComb,
  136. portState,
  137. common_ctx->MemTableData.dDataPoints,
  138. cellsof(common_ctx->MemTableData.dDataPoints),
  139. &common_ctx->MemTableData.getctx ) )
  140. {
  141. goto L_TableData_DATAERR;
  142. }
  143. else
  144. {
  145. common_ctx->MemTableData.init = true;
  146. }
  147. }
  148. #if SCPI_MAX_CMD_TEMP_BUFFER < PRINT_VALUE_MIN_SPACE
  149. #error Invalid value 'SCPI_MAX_CMD_TEMP_BUFFER'
  150. #endif
  151. // The length of temporary string buffer, length of one printable number and number of cells in @MemTableData.dFreqPoints
  152. // are interconnected. Number of cells @MemTableData.dFreqPoints should be equal or be greater than maximum number of
  153. // printed numbers into the @tempBuffer. But it is recommend that these numbers be equal.
  154. // Equal (no unused cells in @dDataPoints):
  155. STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) == cellsof(common_ctx->MemTableData.dDataPoints), "Invalid size" );
  156. // Greater (there is unused cells in @dFreqPoints):
  157. //STATIC_ASSERT( (sizeof(common_ctx->dDataPoints) / PRINT_VALUE_MIN_SPACE) <= cellsof(common_ctx->MemTableData.dDataPoints), "Invalid size" );
  158. size_t nPointsRetrieve = sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE;
  159. switch( NFMClass->methods.xCharacterization.getPoints_Next( &common_ctx->MemTableData.getctx,
  160. &nPointsRetrieve ) )
  161. {
  162. case eNFMGetPointError_Success: common_ctx->MemTableData.isdone = true;
  163. case eNFMGetPointError_OutOfBuffer:
  164. case eNFMGetPointError_Limit:
  165. {
  166. size_t l = 0;
  167. if( nPointsRetrieve > 0 )
  168. {
  169. l = printValues( common_ctx->tempBuffer, sizeof( common_ctx->tempBuffer ),
  170. common_ctx->MemTableData.dDataPoints, nPointsRetrieve, common_ctx->MemTableData.isdone );
  171. }
  172. common_ctx->tempBuffer[ l ] = '\0';
  173. common_ctx->MemTableData.idx = 0; // reset prepared characters index
  174. common_ctx->MemTableData.nchs = l; // prepared characters in buffer
  175. }
  176. break;
  177. case eNFMGetPointError_DataError: goto L_TableData_DATAERR;
  178. case eNFMGetPointError_InvalidValue:
  179. default: goto L_TableData_PARAMERR;
  180. }
  181. }
  182. // Since @done flag is set, this dispatcher shall not be called anymore.
  183. // Since this handler is implemented as a single-state automat, there no
  184. // ... other states to go to:
  185. (void)nextstate;
  186. // modify current postion index:
  187. SCPI_RESPONSE_HELPER_EXTDONE_IDXINC( common_ctx, common_ctx->MemTableData.idx, common_ctx->MemTableData.isdone );
  188. }
  189. // While output buffer swallows all the prepared data from @tempBuffer
  190. while( (common_ctx->MemTableData.idx >= common_ctx->MemTableData.nchs) );
  191. bool bufferEmpty = (common_ctx->MemTableData.idx >= common_ctx->MemTableData.nchs);
  192. SCPI_RESPONSE_HELPER_EXTDONE_SET( common_ctx, bufferEmpty && common_ctx->MemTableData.isdone );
  193. }
  194. break;
  195. }
  196. return nextstate;
  197. L_TableData_DATAERR:
  198. // Formal call: in case the parameter is optional, the token is unfilled.
  199. // So it is required to fill the token with correct values from allowed list.
  200. SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
  201. common_ctx->MemTableData.bank,
  202. &common_ctx->argTokens[2] );
  203. fsq_RaiseErrorEx( SCPI_ERROR_DATA_CORRUPTED, SCPI_ERROR_DATA_CORRUPTED_MSG,
  204. common_ctx->argTokens[2].shead,
  205. common_ctx->argTokens[2].stail,
  206. global_ctx->sParser.xHandlerToken.shead,
  207. global_ctx->sParser.xHandlerToken.stail );
  208. common_ctx->status = eProgramData_SpecificError; // specific error already generated
  209. return NULL;
  210. L_TableData_PARAMERR:
  211. fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
  212. SCPI_ERROR_INTERNAL_DEVICE_MSG,
  213. global_ctx->sParser.xHandlerToken.shead,
  214. global_ctx->sParser.xHandlerToken.stail );
  215. common_ctx->status = eProgramData_SpecificError; // specific error already generated
  216. return NULL;
  217. }
  218. // @printValues
  219. // Prints an array of double points into the buffer.
  220. // If there no free space in the output buffer while not all the numbers are printed, function returns 0;
  221. // @pcBuffer - output buffer;
  222. // @szBuffer - size of output buffer;
  223. // @pValues - an array of numbers to print;
  224. // @nValues - amount of numbers to print;
  225. // @theLastOne - the last call indicator
  226. // Returns:
  227. // - In case all of numbers are printed: number of bytes printed into the output buffer;
  228. // - 0 otherwise
  229. static size_t printValues( char * pcBuffer, size_t szBuffer, const sNFMChrzPoint_t * pValues, size_t nValues, bool theLastOne )
  230. {
  231. // One point has the following format:
  232. // <Magn>,<SPACE>,<Phase>,<SPACE>
  233. // where <magn> and <phase> is a floating point numbers: Mantissa+Exponent
  234. // Mantissa: sign, integer digit, dot, 10 floating point digits, exp-character, exp-sign, exponent value (2 digits)
  235. // So one number has 17 symbols length plus 2 (comma and space)
  236. // So, 19*2=38 characters required to print one point.
  237. // To prevent overflowing by _snprintf() with printing null-term,
  238. // it is required at lease 40 characters free, see @PRINT_VALUE_MIN_SPACE
  239. size_t idx = 0;
  240. while( nValues > 0 )
  241. {
  242. size_t l = 0;
  243. if( (szBuffer-idx) >= PRINT_VALUE_MIN_SPACE )
  244. {
  245. if( theLastOne && (nValues==1) )
  246. l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%+1.10e%c%c%+1.10e", pValues->magn, ',' , ' ', pValues->phase );
  247. else
  248. l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%+1.10e%c%c%+1.10e%c%c", pValues->magn, ',' , ' ', pValues->phase, ',' , ' ' );
  249. pValues++;
  250. }
  251. if( l == 0 || l >= (szBuffer-idx) )
  252. {
  253. return 0; // insuffecient buffer
  254. }
  255. idx += l;
  256. nValues--;
  257. }
  258. return idx;
  259. }