#include "lpc176x.h" #include "usb_hardware.h" #ifdef USBTMC // #endif в конце файла #include "utils.h" #include "../usbtmc/gpib_parser.h" #include "../usbtmc/gpib_parser_validators.h" #include "../usbtmc/gpib_parser_strutils.h" #include "../usbtmc/gpib_parser_numutils.h" #include "usb_enumeration.h" #include "../usbtmc/usbtmc.h" #include "../usbtmc/utilits.h" #include "usb_options.h" #include "options.h" #include "usb_application.h" #include "usb_proto.h" #include #include #include // ptrdiff_t static char SCPIBParam[ MEMORY_SIZE_PARAMQUEUE ]; // Парсинг GPIB комманд. Комманды типа :COMMAND1:COMMAND2:COMMAND3 разбиваются на отдельные // комманды COMMAND1, COMMAND2, COMMAND3. Изначально, требуется определить, какие комманлы будут поддерживаться. // Каждая комманда представляет собой некую структуру данных, описанную ниже (sScpiCommand_t). Она имеет заголовок, // тоесть собственно имя комманды, сокращенное имя комманды, указатель на функцию, которая будет выполнена, // если комманда принята, и указатель на список дочерних комманд. Так, например, комманда :SYSTem может иметь // две дочерние комманды INFO и VERsion. Для парсинга строится дерево комманд. Сначала нужно объявить корневую комманду, // которая не имеет имени, но имеет дочерние комманды, так называемая root комманда. ПРи начале разбора, комманды // будут изначально искаться именно в дочерних коммандах root. Для того, чтобы объявить root, вызовем функцию // GPIB_InitializeCommand(sScpiCommand_t * Pointer, char * header, char *shortheader, TCmdParser_f function, unsigned int childcount ) // где Pointer - указатель на выделенную под струтуру память, header и shortheader указатели на строки, содержащие // полное и сокращенные имена комманды соответсвенно (они могут быть размещены в секции кода), function - указатель на // функцию - обработчик типа TCmdParser_f, которая принимает два параметра - указатель на строку, и на USB_DEVICE_INFO // childcount - количество дочерних комманд, необходимо указать точное количество комманд в секции root для выделения под них // памяти. После того, как GPIB_InitializeCommand вернет указатель на структуру sScpiCommand_t, его можно запомнить в переменную и использовать // как список комманд при передаче в функцию parse(). После создания root, добавляем все комманды, вызывая // GPIB_AddChildCommand( sScpiCommand_t * OwnerCommand, char * header, char *shortheader, TCmdParser_f function, unsigned int childcount ) // где OwnerCommand - указатель на комманду, для которой добавляемая комманда будет дочерней. Если добавляемая комманда не должна быть // дочерней, а должна быть основной (:SYSTem), нужно передать указатель root. Остальные параметры аналогичны GPIB_InitializeCommand // Каждый вызов GPIB_AddChildCommand возвращает указатель на вновь созданную комманду, который нужно сохранить в переменной, // если создаваемая комманда будет иметь дочерние комманды. /* char * fGPIB_Parser_CMD1(char*); // -- прототипы char * fGPIB_Parser_CMD2(char*); // char * fGPIB_Parser_CMD3(char*); // char * fGPIB_Parser_CMD4(char*); // char * fGPIB_Parser_CMD5_1(char*); // //------------------------------------------------------------------------------------------------------------ sScpiCommand_t Root; // -- переменная хранит комманду root sScpiCommand_t * root = GPIB_InitializeCommand( &Root, NULL, NULL, NULL, 5 ); // -- предполагается создать 5 комманд в root sScpiCommand_t * Command1 = GPIB_AddChildCommand( root, "CoMmanD1","CMD1", fGPIB_Parser_CMD1, 0 ); // -- комманда CMD1 не будет иметь дочерних. Обрабатываться комманда будет функцией char * fGPIB_Parser_CMD1(char*) sScpiCommand_t * Command2 = GPIB_AddChildCommand( root, "CoMmanD2","CMD2", fGPIB_Parser_CMD2, 0 ); sScpiCommand_t * Command3 = GPIB_AddChildCommand( root, "CoMmanD3","CMD3", fGPIB_Parser_CMD3, 0 ); sScpiCommand_t * Command4 = GPIB_AddChildCommand( root, "CoMmanD4","CMD4", fGPIB_Parser_CMD4, 0 ); sScpiCommand_t * Command5 = GPIB_AddChildCommand( root, "CoMmanD5","CMD5", fGPIB_Parser_CMD5, 1 ); // -- комманда будет иметь дочернюю sScpiCommand_t * Command5_1 = GPIB_AddChildCommand( Command5, "CoMmanD5_1","CM51", fGPIB_Parser_CMD5_1, 0 ); // -- комманда добавлена к комманде Command5 как дочерняя */ // Таким образом, добавлять и изменять количество и поддержку комманд значительно проще, чем обрабатывать // всю строку в лоб с кучей if-ов // ==================== прототипы ========================================================= // ============================= СЕРВИСНЫЕ ФУНКЦИИ =================================================== // GPIB_InitializeCommand: // Initializes the GPIB command // @pointer - the pointer to the command entry to initialize // @header - the command header (name) // @shortheader - the short command name // @function - command handler // @childMax - the maximum amount of child commands // @enablerequest - boolean flag, allows the request mode for the command sScpiCommand_t * GPIB_InitializeCommand ( sScpiCommand_t * pCmd, const char * header, const char *shortheader, TCmdParser_f function, size_t childMax, BOOL enablerequest ) { if( !IsCorrectPointer(pCmd) ) return NULL; pCmd->enablerequest = enablerequest; // request mode enable pCmd->header = header; // full header pCmd->shortheader = shortheader; // short header pCmd->function = function; // handler pCmd->childcount = 0; // amount of child commands pCmd->childcountmax = childMax; // maximum available of child commands pCmd->pcommands = (sScpiCommand_t*)malloc( sizeof(sScpiCommand_t) * childMax ); // allocate memory for child commands pCmd->bTagArgUsed = FALSE; if( (NULL == pCmd->pcommands) && (childMax > 0) ) { return NULL; } return pCmd; } //----------------------------------------------------------------------------------------------------- // GPIB_MakeSpecialCommand() transform the command to special command // Special command has an extra tag parameter to specialize the handler call. BOOL GPIB_MakeSpecialCommand ( sScpiCommand_t * pCmd, int xTag, BOOL bUsed ) { if( !IsCorrectPointer(pCmd) ) return FALSE; pCmd->bTagArgUsed = bUsed; pCmd->xTagArg = xTag; return TRUE; } // ------------------------------------------------------------------------------------------------------ // GPIB_AddChildCommand: // Appends the child command to the specified owner @pOwnerCommand sScpiCommand_t * GPIB_AddChildCommand( sScpiCommand_t * pOwnerCommand, char * header, char * shortheader, TCmdParser_f function, size_t childMax, BOOL enablerequest ) { if( !IsCorrectPointer(pOwnerCommand) ) return NULL; sScpiCommand_t * ChildCommand; // check the limit of children if( pOwnerCommand->childcountmax > pOwnerCommand->childcount ) { // Use already allocated memory for child command in @pOwnerCommand->pcommands block. ChildCommand = GPIB_InitializeCommand( &pOwnerCommand->pcommands[ pOwnerCommand->childcount ], header, shortheader, function, childMax, enablerequest ); if( ChildCommand != NULL ) pOwnerCommand->childcount++; // increment count of children } else ChildCommand = NULL; //error return ChildCommand; } //------------------------------------------------------------------------------- // GPIB_Parse: // Parse one command with parameters. // Note: the command must be without subsystem-character in the begining (semicolon) // E.g. SYSTem:TRIGger // sScpiCommand_t * GPIB_Parse( USB_DEVICE_INFO * udi, char * str, BOOL request, char * end ) { sScpiCommand_t * searchRoot = udi->usbtmcGpib.gpib_search; // retrieve the root of the search // ----------------------------------------------------------------------------------------------------------- // Validate the pointer @searchRoot if( ! IsCorrectPointer(searchRoot) ) return NULL; // error // Validate the pointers @str and @end // It must be non NULL. if( NULL == str || NULL == end ) return NULL; // Check if the @end greater than @str if( ChooseLowestPtrConst(str, end) == end ) // error: the @str greater than @end // @end it's end of the string and must be greater. return NULL; // ----------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------- // @sysNodeBegin: search for the subsystem delimiter (semicolon) char * sysNodeBegin = GPIB_StrChr_rw( str, GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN, end); // @sysNodeEnd: search for the end of all subsystems (whole command header, e.g. space btw cmd and data) //char * sysNodeEnd = strwhite( str ); // So, search for first white-charater char * sysNodeEnd = searchHeaderEnd( str, end ); // Search for the end of the header char charWhite = *sysNodeEnd; // Save the white character by offset @sysNodeEnd. // Calculate the string length size_t strLength = (int)((ptrdiff_t)(end) - (ptrdiff_t)(str)); size_t strLength2 = strlen(str); // Choose the shortest one between strlen() and substraction btw @end and @str strLength = (strLengthchildcount; ++i ) { bCommandFound = FALSE; do { // ------------------------------------------------------------- // Attempt 1. // ------------------------------------------------------------- // Compare the command header if( GPIB_HeaderCompare( searchRoot->pcommands[i].header, str ) // the command header matchs || GPIB_HeaderCompare( searchRoot->pcommands[i].shortheader, str ) ) // the command short header matchs { bCommandFound = TRUE; // In case searchRoot->pcommands[i].enablerequest is FALSE, but // the command actually is a request, the header contain a request // character in the end. It is required to set @bRequst to appropriate value. if( GPIB_CHAR_REQUEST_SIGN == *(sysNodeEnd - 1) ) bRequest = TRUE; break; // do-while } // ------------------------------------------------------------- // Attempt 2. // ------------------------------------------------------------- // Note: if @enablerequest it means the command in the list is registered // without question mark, e.g. ESE, but not ESE?. So it means the command // can be used as either "command" and "request". In this case GPIB_HeaderCompare // does not find full match // Check if the command is registered without the request mark (?). if( searchRoot->pcommands[i].enablerequest ) { // get the header length // Note: @str string had been cut with null-terminator above. strLength = strlen( str ); // Check if @str contain a request character if( (GPIB_CHAR_REQUEST_SIGN == str[ strLength-1 ]) && (strLength > 1) ) { // replace the request character with a null-terminator. str[ strLength-1 ] = '\0'; // Perform another comparaion of the command header if( GPIB_HeaderCompare( searchRoot->pcommands[i].header, str ) // the command header matchs || GPIB_HeaderCompare( searchRoot->pcommands[i].shortheader, str ) ) // the command short header matchs { bCommandFound = TRUE; bRequest = TRUE; str[ strLength-1 ] = GPIB_CHAR_REQUEST_SIGN; // restore the request character break; // do-while } str[ strLength-1 ] = GPIB_CHAR_REQUEST_SIGN; // restore the request character } } } while(0); if( bCommandFound ) { // Check is there next subsystem separator in the string. // If there no such separator, the the whole input command string is processed. if( sysNodeBegin != NULL ) { // There are more subsystem separators *sysNodeBegin = GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN; // restore subsystem separator if( sysNodeEnd != NULL ) *sysNodeEnd = charWhite; // restore white character udi->usbtmcGpib.gpib_owner = udi->usbtmcGpib.gpib_search; // save the command owner: searchRoot->pcommands[i] udi->usbtmcGpib.gpib_search = &searchRoot->pcommands[i]; // set the root for the searching in the next recursive call sysNodeBegin++; // skip subsystem separator return GPIB_Parse( udi, sysNodeBegin, bRequest, end ); // parse the command recursive in the found command } else // if the input string is processed til the end { if( sysNodeEnd != NULL ) // if there is a white character in the tail of header { // Note: a white character always presents. *sysNodeEnd = charWhite; // restore white character size_t nRespondBytes = 0; // @nRespondBytes - amount of sent bytes size_t nOffset = 0; // It is required to insert the delimiter between replies // relating to the different input requests in case more than one // command is in the string. if( bRequest ) { /* // pointer to the buffer for respond BULKIN_HEADER * pBulkInHeader= (BULKIN_HEADER*) udi->EPBulkStatus.InPipe.pData; // if there are any bytes in the respond buffer - it must be a reply of another command if( 0 < pBulkInHeader->stRespondMessage.TransferSize ) { // insert a delimiter udi->usbtmcGpib.pData[0] = GPIB_CHAR_RPLSEPARATOR_SIGN; udi->usbtmcGpib.pData++; nOffset++; } */ if( udi->BulkRespondStatus.dwDeviceOut > 0 ) { // insert a delimiter udi->usbtmcGpib.pData[0] = GPIB_CHAR_RPLSEPARATOR_SIGN; udi->usbtmcGpib.pData++; nOffset++; } } size_t paramLength = 0; // ------------- // If the end of header reached - set @sysNodeEnd to NULL, and set @paramLength to 0 sysNodeEnd++; if( sysNodeEnd >= end ) sysNodeEnd = NULL; else paramLength = SubPointers( end, sysNodeEnd ); // ------------- // Enumerate parameters and pack it into the queue QUEUE QParameters; queue_create( SCPIBParam, MEMORY_SIZE_PARAMQUEUE, &QParameters ); // @SCPIBParam - global and static buffer // Check command tag: if(searchRoot->pcommands[i].bTagArgUsed == TRUE) { // push the tag-parameter into the queue queue_add( &QParameters, (char*)&searchRoot->pcommands[i].xTagArg, sizeof(searchRoot->pcommands[i].xTagArg) ); } // Allow unlimited amount of non-request commands, and limited amount of requests if( !bRequest || udi->usbtmcGpib.cRequestCountSupport > 0 ) { // request: decrease amount of allowed requests (@cRequestCountSupport) if( bRequest ) udi->usbtmcGpib.cRequestCountSupport--; int rcEnum = 1; if( NULL != sysNodeEnd && 0 != paramLength ) { // Enumerate all the parameters and pack it into the queue @QParameters rcEnum = GPIB_EnumParameters( sysNodeEnd, paramLength, &QParameters, NULL ); } if( rcEnum > 0 ) { QParameters.nStringLen = paramLength; QParameters.pString = sysNodeEnd; // ---------------------------------------------------------------------------- // It is required to keep command context to give // enough time the current command to send it's reply. // --- usbtmc_delete_function_context( udi ) --- // see USBTMC spec, rev 1.0, 2003, page 16, table 12, index 1 // Stall and abort the endpoint in case the IRQ-transfer is in progress if(udi->BulkRespondStatus.INTransferInProgress == TRUE && bRequest) usbtmc_bulkin_stall_and_abort( udi ); // call the command processor nRespondBytes += (searchRoot->pcommands[i].function( udi, &QParameters, bRequest )); udi->usbtmcGpib.pData += nRespondBytes; // shift the pointer of the reply buffer udi->BulkRespondStatus.RespondBufferSize -= (nRespondBytes + nOffset); // and decrease amount of free space. udi->BulkRespondStatus.dwDeviceOut += (nRespondBytes + nOffset); // Increase of output transfer. } else { // 27/08/18 // GPIB_RaiseStandartError( udi, ERROR_GPIB_INVALID_ENUM_PARAMETERS, NULL, GPIB_ERROR_ID_EXE ); GPIB_RaiseStandartError( udi, ERROR_GPIB_INVALID_ENUM_PARAMETERS, NULL, errClass_Autodetect ); } } else { // 27/08/18 // GPIB_RaiseStandartError( udi, ERROR_GPIB_TOO_MANY_REQUESTS, NULL, GPIB_ERROR_ID_EXE ); GPIB_RaiseStandartError( udi, ERROR_GPIB_TOO_MANY_REQUESTS, NULL, errClass_Command ); } return searchRoot; } break; } } } } // Reach this point in case the command header not found. if( bCommandFound == FALSE ) { sScpiCommand_t * pseudo_result; sScpiCommand_t * SearchSave; sScpiCommand_t * OwnerSave; searchRoot = udi->usbtmcGpib.gpib_owner; // get the owner for the search // it is possible that optional header is omitted if( sysNodeBegin != NULL ) *sysNodeBegin = GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN; // restore subsystem separator if( sysNodeEnd != NULL ) *sysNodeEnd = charWhite; // restore white character for( size_t i = 0; i < searchRoot->childcount; ++i ) { if( IsOptionalHeader( searchRoot->pcommands[i].shortheader ) || IsOptionalHeader( searchRoot->pcommands[i].header ) ) // optional header found { /*!*/SearchSave = udi->usbtmcGpib.gpib_search; // save the search pointer /*!*/OwnerSave = udi->usbtmcGpib.gpib_owner; // save the owner command udi->usbtmcGpib.gpib_owner = udi->usbtmcGpib.gpib_search; udi->usbtmcGpib.gpib_search = &searchRoot->pcommands[i]; // change the search point for a while pseudo_result = GPIB_Parse( udi, str, request, end); // call the parser recursively /*!*/udi->usbtmcGpib.gpib_search = SearchSave; // restore the search pointer /*!*/udi->usbtmcGpib.gpib_owner = OwnerSave; // restore the owner command if( pseudo_result != NULL ) return pseudo_result; // command found among optional commands } } } return NULL; } /* //------------------------------------------------------------------------------- // // Parameters: str - указатель на одну комманду. Пример, "SYSTem:TRIGger" // Комманда ":SYSTem:TRIGger" некорректна, так как имеется незначащее двоеточие в начале. // Нужно убирать двоеточие в начале sScpiCommand_t * parse( USB_DEVICE_INFO * udi, char * str, BOOL request, char * end) { sScpiCommand_t * Search = udi->usbtmcGpib.gpib_search; // -- нод дерева, с которого начинается поиск BULKIN_HEADER * pBulkInHeader= (BULKIN_HEADER*) udi->EPBulkStatus.InPipe.pData; // указатель на начало буфера-ответа, указатель на заголовок Bulk-IN // ----------------------------------------------------------------------------------------------------------- if( !IsCorrectPointer(Search) ) return NULL; // -- проверяем корректность указателя // ----------------------------------------------------------------------------------------------------------- char * p = GPIB_StrChr_rw( str, GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN, end); // -- ищем следующий нод в строке char * s = strwhite( str ); // -- ищем завершающий символ команды char _s = *s; // -- сохраняем завершающий символ комманды int l; // -- хранит длинну строки BOOL bCommandFound = FALSE; // -- комманда ненайдена BOOL q = FALSE; // -- равен TRUE если пришел запрос "*REQUEST?", Хотя имеется комманда "*REQUEST" if( p != NULL ) *p = 0; // -- если нашли след. нод, укорачиваем комманду, делая из последовательности комманд одну комманду if( s != NULL ) *s = 0; // -- если нашли завершающий символ, заменяем его на нуль терминатор // ----------------------------------------------------------------------------------------------------------- if( GPIB_CheckHeader(str) != TRUE ) { // сначала генерим ошибку, strlen дойдет до '\0' // а потом уже вернем пробел на место if( usbtmc_RaiseError( udi, GPIB_ERROR_ID_EXE, ERROR_USBTMC_EXECUTION, "'", 1 )) if(usbtmc_RaiseError_CatDescription( udi, str, strlen(str))) usbtmc_RaiseError_CatDescription( udi, "'", 1); if( p != NULL ) *p = GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN; // -- восстанавливаем двоеточие if( s != NULL ) *s = _s; // -- восстанавливаем white символ, (если это например пробел, отделяющий данные) } else { if(!( *str == GPIB_CHAR_MANDATORY_IEEE488_SIGN && strlen(str)<=2 )) for(int i=0; i< Search->childcount; i++) // -- ищем по текущему ноду поиска нужную комманду // ------ проверяем совпадения комманд... // -------------------------------------- if( TRUE==GPIB_HeaderCompare( Search->pcommands[i].header, str ) || // -- или если совпало имя комманды TRUE==GPIB_HeaderCompare( Search->pcommands[i].shortheader, str ) || // -- или если совпала аббревиатура комманды // ---------- проверяем совпадение запроса............... // -- проверка дальше, если имя и аббревиатура не совпали (Search->pcommands[i].enablerequest == TRUE && // -- или если разрешено сравнение без '?' ( // ---------- проверяем, есть ли в конце запросный символ '?' ((l = strlen( str )) && (str[l-1] == '?')) && // ---- и '?' есть в конце строки ( // --------- символ есть, сравниваем без символа 0==strncmp( Search->pcommands[i].header, str, l-1 ) || // -- сверяем имя без '?' 0==strncmp( Search->pcommands[i].shortheader, str, l-1 ) // -- сверяем аббр без '?' ) && (l>1) && ((q = TRUE),q) // -- если все условия выполнены, q=TRUE ) ) ) { bCommandFound = TRUE; if (p != NULL ) // -- если строка разобрана не полностью { if( p != NULL ) *p = GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN; // -- восстанавливаем двоеточие if( s != NULL ) *s = _s; // -- восстанавливаем white символ, (если это например пробел, отделяющий данные) udi->usbtmcGpib.gpib_owner = udi->usbtmcGpib.gpib_search; // сохраняем владельца комманды Search->pcommands[i] udi->usbtmcGpib.gpib_search = &Search->pcommands[i]; return parse( udi, p+1, q, end); // -- рекурсивно парсим следующую комманду. поиск в уже найденом ноде } else // -- если строка разобрана полностью if( s != NULL ) // -- если имеется white символ, а он всегда имеется { *s = _s; // -- восстанавливаем его int dwRespondBytes=0; // -- dwRespondBytes - количество байт, отправляемых в ответ на комманду int dwOffset=0; if( q == FALSE && *(s-1) == '?' ) q = TRUE; // если комманда добавлена как RequestOnly, ее header содержит '?'. q=FALSE если комманда RequestOnly. Эта строка исправляет ситуацию // --------------------- вставка разделителя ; в ответное сообщение между ответами ------------------------ // -------------------------------------------------------------------------------------------------------- if(q==TRUE // -- если пришел ЗАПРОС && pBulkInHeader->stRespondMessage.TransferSize // -- если уже были данные в буфере от предыдущей комманде && (++dwOffset)) // -- увеличиваем Offset (udi->usbtmcGpib.pData++)[0] = ';'; // -- вставляем разделитель // -------------------------------------------------------------------------------------------------------- if( end <= ++s ) s = NULL; // если конец строки или конец комманды (разделитель следом) то s=NULL unsigned int strl = SubPointers(end,s); // -------------------------- энумеруем параметры и ложим их в очередь -------- QUEUE QParameters; queue_create( SCPIBParam, MEMORY_SIZE_PARAMQUEUE, &QParameters ); // буфер очереди глобальный и статический. if(Search->pcommands[i].bTagArgUsed == TRUE) queue_add( &QParameters, (char*)&Search->pcommands[i].xTagArg, sizeof(Search->pcommands[i].xTagArg) ); if( !q || (q && udi->usbtmcGpib.cRequestCountSupport-- > 0) ) if( GPIB_EnumParameters( s, strl, &QParameters, NULL ) != -1 ) { QParameters.strl = strl; QParameters.str = s; // ---------------------------------------------------------------------------- //-- перед выполнением GPIB функции нельзя удалять контекст, //-- ведь след комманда может его и не использует, //-- а текущая не успеет передать данные //usbtmc_delete_function_context( udi ); // see USBTMC spec, rev 1.0, 2003, page 16, table 12, index 1 if(udi->BulkRespondStatus.INTransferInProgress == TRUE && q) usbtmc_bulkin_stall_and_abort( udi ); dwRespondBytes+= (Search->pcommands[i].function( udi, &QParameters, q )); // -- вызываем обработчик комманды, передавая ему оставшуюся часть строки после white символа udi->usbtmcGpib.pData+=dwRespondBytes; // -- сдвигаем указатель буфера, в который складываются ответы udi->BulkRespondStatus.RespondBufferSize -= (dwRespondBytes+dwOffset); // -- уменьшаем объем доступного места в буфере udi->BulkRespondStatus.dwDeviceOut+=(dwRespondBytes+dwOffset); // -- увеличиваем размер ответной передачи } else GPIB_RaiseStandartError( udi, ERROR_GPIB_INVALID_ENUM_PARAMETERS, NULL, GPIB_ERROR_ID_EXE ); else GPIB_RaiseStandartError( udi, ERROR_GPIB_TOO_MANY_REQUESTS, NULL, GPIB_ERROR_ID_EXE ); return Search; } break; } // -- сюда мы попадем если комманда не найдена! if( bCommandFound == FALSE ) { sScpiCommand_t * pseudo_result; sScpiCommand_t * SearchSave; sScpiCommand_t * OwnerSave; Search = udi->usbtmcGpib.gpib_owner; // получаем хозяина // -- возможно опущен необязательный заголовок! if( p != NULL ) *p = GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN; // -- восстанавливаем двоеточие if( s != NULL ) *s = _s; for(int i=0; i< Search->childcount; i++) if( IsOptionalHeader(Search->pcommands[i].shortheader) || IsOptionalHeader(Search->pcommands[i].header)) // если найдена опциональная комманда { // !!!!!!!!!!!!! SearchSave = udi->usbtmcGpib.gpib_search; // сохраняем текущий указатель на точку поиска OwnerSave = udi->usbtmcGpib.gpib_owner; // сохраняем текущий указатель на владельца комманды // !!!!!!!!!!!!! udi->usbtmcGpib.gpib_owner = udi->usbtmcGpib.gpib_search; udi->usbtmcGpib.gpib_search = &Search->pcommands[i]; // изменяем на время текущий указатель на точку поиска pseudo_result = parse( udi, str, request, end); // !!!!!!!!!!!!! udi->usbtmcGpib.gpib_search = SearchSave; // восстанавливаем прежний указатель на точку поиска udi->usbtmcGpib.gpib_owner = OwnerSave; // восстанавливаем прежний указатель на владельца комманды // !!!!!!!!!!!!! if( pseudo_result != NULL ) return pseudo_result; // ура, нашли комманду в дерева в одном из опциональных нодов } } } // CheckHeader return NULL; } */ //---------------------------------------------------------------------- // GPIB_InitializeAllCommands: // Create a list of supported commands of the device. sScpiCommand_t * GPIB_InitializeAllCommands() { // Allocate memory for the root command sScpiCommand_t * root = (sScpiCommand_t *)malloc( sizeof(sScpiCommand_t) ); if( !IsCorrectPointer(root) ) return NULL; // ------------------------------------------------------------------------------------------------- // Create a root command: root = GPIB_InitializeCommand( root, "root" , NULL, GPIB_DUMMY_FUNCTION, 16, FALSE ); // ------------------------------------------------------------------------------------------------- // Mandatory commands, add as a child of root command: GPIB_AddChildCommand( root, "*IDN?", "*IDN?", GPIB_Identification , 0, FALSE); GPIB_AddChildCommand( root, "*CLS" , "*CLS" , GPIB_Clear , 0, FALSE); GPIB_AddChildCommand( root, "*RST" , "*RST" , GPIB_Reset , 0, FALSE); GPIB_AddChildCommand( root, "*ESE" , "*ESE" , GPIB_EventStatusEnable , 0, TRUE ); GPIB_AddChildCommand( root, "*ESR" , "*ESR" , GPIB_EventStatusRegister , 0, TRUE ); GPIB_AddChildCommand( root, "*STB" , "*STB" , GPIB_StatusRegister , 0, TRUE ); GPIB_AddChildCommand( root, "*SRE" , "*SRE" , GPIB_StatusEnableRegister, 0, TRUE ); GPIB_AddChildCommand( root, "*TRG" , "*TRG" , GPIB_Trigger , 0, FALSE); // ? GPIB_AddChildCommand( root, "*WAI" , "*WAI" , GPIB_Wait , 0, FALSE); // ? GPIB_AddChildCommand( root, "*OPC" , "*OPC" , GPIB_OperationComplete , 0, TRUE ); // ------------------------------------------------------------------------------------------------- // Child commands of root: sScpiCommand_t * gpib_Mem = GPIB_AddChildCommand( root, "MEMORY", "MEM", GPIB_DEF_FUNCTION , 1, FALSE ); // ------------------------------------------------------------------------------------------------- // Child commands of "MEMORY": sScpiCommand_t * gpib_MemTable = GPIB_AddChildCommand( gpib_Mem, "TABLE", "TABL", GPIB_DEF_FUNCTION , 12, FALSE ); // ------------------------------------------------------------------------------------------------- // Create child commands for "MEMORY:TABLE": GPIB_AddChildCommand( gpib_MemTable, "POINTS", "POIN", GPIB_MemoryTablePoints , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "DATE", "DATE", GPIB_MemoryTableDate , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "TIME", "TIME", GPIB_MemoryTableTime , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "TEMPERATURE", "TEMP", GPIB_MemoryTableTemp , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "CONNECTOR", "CONN", GPIB_MemoryTableConnector, 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "ADAPTER", "ADAP", GPIB_MemoryTableAdapter , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "ANALYZER", "ANAL", GPIB_MemoryTableAnalyzer , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "OPERATOR", "OPER", GPIB_MemoryTableOperator , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "PLACE", "PLAC", GPIB_MemoryTablePlace , 0, TRUE ); GPIB_AddChildCommand( gpib_MemTable, "DATA", "DATA", GPIB_MemoryTableData , 0, TRUE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of "MEMORY:TABLE": sScpiCommand_t * gpib_MemTableTher = GPIB_AddChildCommand( gpib_MemTable, "THERMO", "THER", GPIB_DEF_FUNCTION , 1, FALSE ); sScpiCommand_t * gpib_MemTableTherCorr = GPIB_AddChildCommand( gpib_MemTableTher, "CORRECTION", "CORR", GPIB_DEF_FUNCTION , 4, FALSE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of "MEMORY:TABLE:THERMO:CORRECTION": //GPIB_MakeSpecialCommand( GPIB_AddChildCommand( gpib_MemTableTherCorr,"MAGNITUDE", "MAGN", GPIB_MemTableTherCorrMagniture, 0, TRUE ); GPIB_AddChildCommand( gpib_MemTableTherCorr,"PHASE" , "PHAS", GPIB_MemTableTherCorrPhase, 0, TRUE ); GPIB_AddChildCommand( gpib_MemTableTherCorr,"POINTS" , "POIN", GPIB_MemTableTherCorrPoints, 0, TRUE ); sScpiCommand_t * gpib_MemTableTherCorrFreq = GPIB_AddChildCommand( gpib_MemTableTherCorr,"FREQUENCY", "FREQ", GPIB_DEF_FUNCTION, 2, FALSE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of "MEMORY:TABLE:THERMOCOMPENSATION:FREQUENCY": GPIB_AddChildCommand( gpib_MemTableTherCorrFreq, "START", "STAR", GPIB_MemTableTherCorrFreqStart, 0, TRUE ); GPIB_AddChildCommand( gpib_MemTableTherCorrFreq, "STOP" , "STOP", GPIB_MemTableTherCorrFreqStop, 0, TRUE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of "MEMORY:TABLE": sScpiCommand_t * gpib_MemTableFreq = GPIB_AddChildCommand( gpib_MemTable, "FREQUENCY", "FREQ", GPIB_DEF_FUNCTION, 5, FALSE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of "MEMORY:TABLE:FREQUENCY": // MEMORY:TABLE:FREQUENCY:START? GPIB_AddChildCommand( gpib_MemTableFreq, "START", "STAR", GPIB_MemoryTableFreqStart, 0, TRUE ), // MEMORY:TABLE:FREQUENCY:STOP? GPIB_AddChildCommand( gpib_MemTableFreq, "STOP", "STOP" , GPIB_MemoryTableFreqStop, 0, TRUE ), // MEMORY:TABLE:FREQUENCY:TYPE? GPIB_AddChildCommand( gpib_MemTableFreq, "TYPE", "TYPE", GPIB_MemoryTableFreqType, 0, TRUE ); sScpiCommand_t * gpib_MemTableFreqSegm = // MEMORY:TABLE:FREQUENCY:SEGM GPIB_AddChildCommand( gpib_MemTableFreq, "SEGM", "SEGM", GPIB_DEF_FUNCTION, 1, FALSE ); // MEMORY:TABLE:FREQUENCY:SEGM:DATA? GPIB_AddChildCommand( gpib_MemTableFreqSegm,"DATA", "DATA", GPIB_MemoryTableFreqSegmData,0,TRUE ); // MEMORY:TABLE:FREQUENCY:DATA? GPIB_AddChildCommand( gpib_MemTableFreq, "DATA", "DATA", GPIB_MemoryTableFreqData, 0, TRUE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of root: sScpiCommand_t * gpib_DeviceDependent = GPIB_AddChildCommand( root, "MEASURE", "MEAS", GPIB_DEF_FUNCTION, 1, FALSE); //root function 8 // --------------------------------------------------------------------------------------------------------------- // Child commands of "MEASURE": GPIB_AddChildCommand( gpib_DeviceDependent, "TEMPERATURE", "TEMP", GPIB_GetTemperature, 0, TRUE); //Cчитывает температуру внутри калибровочного модуля (только запрос). // --------------------------------------------------------------------------------------------------------------- // Child commands of root: sScpiCommand_t * gpib_Interface = GPIB_AddChildCommand( root, "INTERFACE", "INT", GPIB_DEF_FUNCTION, 1, FALSE ); //root function 7 // --------------------------------------------------------------------------------------------------------------- // Child commands of "INTERFACE": GPIB_AddChildCommand( gpib_Interface, "SWITCH", "SW", GPIB_InterfaceSwitch, 0, TRUE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of root: sScpiCommand_t * gpib_System = GPIB_AddChildCommand( root, "[SYSTEM]", "[SYST]", GPIB_DEF_FUNCTION, 3, FALSE ); //root function 4 // --------------------------------------------------------------------------------------------------------------- // Child commands of "SYSTEM": GPIB_AddChildCommand( gpib_System, "VERSION?", "VERS?", GPIB_SystemVersion, 0, FALSE ); sScpiCommand_t * gpib_SystemErr = GPIB_AddChildCommand( gpib_System, "ERROR", "ERR", GPIB_SystemError, 2, TRUE ); sScpiCommand_t * gpib_Source = GPIB_AddChildCommand( gpib_System, "[SWITCH]", "[SWIT]", GPIB_DEF_FUNCTION, 3, FALSE ); //root function 9 // --------------------------------------------------------------------------------------------------------------- // Child commands of "SYSTEM:ERR": GPIB_AddChildCommand( gpib_SystemErr, "NEXT?", "NEXT?", GPIB_SystemError, 0, FALSE); GPIB_AddChildCommand( gpib_SystemErr, "ALL?", "ALL?", GPIB_SystemErrorAll, 0, FALSE); // --------------------------------------------------------------------------------------------------------------- // Child commands of "SYSTEM:SWITCH" GPIB_AddChildCommand( gpib_Source, "COUNT", "COUN", GPIB_SwitchCount, 0, TRUE ); GPIB_AddChildCommand( gpib_Source, "STATE", "STAT", GPIB_SwitchState, 0, TRUE ); GPIB_AddChildCommand( gpib_Source, "LIST", "LIST", GPIB_SwitchList, 0, TRUE ); // --------------------------------------------------------------------------------------------------------------- // Child commands of root: // sScpiCommand_t * gpib_Status = // GPIB_AddChildCommand( root, "STATUS", "STAT", GPIB_DEF_FUNCTION, 3, FALSE ); //root function 5 // --------------------------------------------------------------------------------------------------------------- // Child commands of "STATUS": // GPIB_AddChildCommand( gpib_Status, "PRESET", "PRES", GPIB_StatusPreset, 0, FALSE ); // No Subcomands // sScpiCommand_t * gpib_StatusOperation = // GPIB_AddChildCommand( gpib_Status, "OPERATION", "OPER", GPIB_StatusOperationEvent, 3, TRUE ); // 3 Subcommands, Request Enable -> EVENt? // sScpiCommand_t * gpib_StatusQuestionable = // GPIB_AddChildCommand( gpib_Status, "QUESTIONABLE","QUES", GPIB_StatusQuestionableEvent, 3, TRUE ); // 3 Subcommands, Request Enable -> EVENt? // --------------------------------------------------------------------------------------------------------------- // Child commands of "STATUS:OPERATION": // GPIB_AddChildCommand( gpib_StatusOperation, "EVENT?", "ENENt?", GPIB_StatusOperationEvent, 0, FALSE ); // No Subcomands, Request Only // GPIB_AddChildCommand( gpib_StatusOperation, "CONDition?", "COND?", GPIB_StatusOperationCondition, 0, FALSE ); // No Subcomands, Request Only // GPIB_AddChildCommand( gpib_StatusOperation, "ENABLE", "ENAB", GPIB_StatusOperationEnable, 0, TRUE ); // No Subcomands, Request enable // --------------------------------------------------------------------------------------------------------------- // Child commands of "STATUS:QUESTIONABLE": // GPIB_AddChildCommand( gpib_StatusQuestionable, "EVENT?", "ENENt?", GPIB_StatusQuestionableEvent, 0, FALSE ); // No Subcomands, Request Only // GPIB_AddChildCommand( gpib_StatusQuestionable, "CONDition?","COND?", GPIB_StatusQuestionableCondition, 0, FALSE ); // No Subcomands, Request Only // GPIB_AddChildCommand( gpib_StatusQuestionable, "ENABLE", "ENAB", GPIB_StatusQuestionableEnable, 0, TRUE ); // No Subcomands, request enable // --------------------------------------------------------------------------------------------------------------- return root; } // GPIB_TrimCommand: // Removes either the leading and trailing white characters from the command string // Returns the length of command int GPIB_TrimCommand( char * begin, char * end, char * * pCmdStart, char * * pCmdEnd ) { // check the input pointers if( NULL == end || NULL == begin || NULL == pCmdStart || NULL == pCmdEnd ) return -1; if( SubPointers(end, begin) <= 0 ) return -1; // Skip leading white characters while( IsWhiteOrEndChar( *begin ) ) { begin++; } // Skip trailing white characters do { end--; } while( IsWhiteOrEndChar( *end ) ); end++; *pCmdEnd = end; *pCmdStart = begin; return SubPointers( end, begin ); } // GPIB_SearchCommand: // Searches for the end of command in the string @begin til the @end. // @ppCmdEnd - the pointer to the receiving cell of pointer to the end of command // Note: the function processes GPIB strings and GPIB datablocks. int GPIB_SearchCommand( const char * begin, const char * end, const char * * ppCmdEnd ) { // check the input pointers if( NULL == end || NULL == begin ) return -1; // check the input pointers if( SubPointers(end, begin) <= 0 ) return -1; const char * iter = begin; const char * near; do { // Search for special characters in the string since @iter til the @end const char * separator = GPIB_StrChr( iter, GPIB_CHAR_CMDSEPARATOR_SIGN, end ); // search for the command separator const char * datablock = GPIB_StrChr( iter, GPIB_CHAR_DATATABLE_SIGN, end ); // search for the datablock const char * squote = GPIB_StrChr( iter, GPIB_CHAR_SINGLEQUOTE_SIGN, end ); // search for the quoted string const char * dquote = GPIB_StrChr( iter, GPIB_CHAR_DOUBLEQUOTE_SIGN, end ); // search for the quoted string // Select the first faced special character in the string since @iter til the @end near = ChooseLowestPtrConst( squote, dquote ); near = ChooseLowestPtrConst( near, separator ); near = ChooseLowestPtrConst( near, datablock ); // check the simplest case: no separator characters found (and any other special characters) if( NULL == near ) { // the whole string [@begin ... @end] is a command if( NULL != ppCmdEnd ) *ppCmdEnd = end; // return the length of command return SubPointers( end, begin ); } // check if the first command does contain neither datablock or quotes // In this case a separator is faced first if( separator == near ) { // the string [@iter ... @separator] is a command if( NULL != ppCmdEnd ) // fixed: 23/08/18 { *ppCmdEnd = separator; } // return the length of command return SubPointers( separator, iter ); } // check if the double quote is faced first if( dquote == near ) { // the string contains GPIB string. It is required to skip it. // search a closing quote dquote = GPIB_StrChr( iter, GPIB_CHAR_DOUBLEQUOTE_SIGN, end ); if( NULL == dquote ) { // error: unpaired quote found return -1; } // skip the quoted string iter = (dquote + 1); continue; } // check if the single quote is faced first if( squote == near ) { // the string contains GPIB string. It is required to skip it. // search a closing quote squote = GPIB_StrChr( iter, GPIB_CHAR_SINGLEQUOTE_SIGN, end ); if( NULL == squote ) { // error: unpaired quote found return -1; } // skip the quoted string iter = (squote + 1); continue; } // check if the datablock is faced first if( datablock == near ) { size_t nDataBlock; // check if it is valid datablock if( IsDataBlock( datablock, SubPointers(end, datablock), &nDataBlock, NULL ) ) { // datablock is valid // skip datablock iter = (datablock + nDataBlock); } else { // datablock is invalid // skip the datablock signature // maybe, it is not datablock. iter = (datablock + 1); } continue; } } // continue until the end of string (@end is reached) // and interrupt in case @near is null. while( (NULL != near) && SubPointers(end, iter) > 0 ); // no separator found if( NULL != ppCmdEnd ) *ppCmdEnd = end; // the whole string is a command // return the length of command return SubPointers( end, begin ); } // ----------------------------------- // GPIB_CommandExecute() выполнение строки комманд GPIB. // root - указатель на root комманду дерева комманд // GPIB_Commands_String - указатель на стоку комманд GPIB, разделенных точкой с запятой int GPIB_CommandExecute( USB_DEVICE_INFO * udi, const char * input_str ) { size_t length = udi->BulkMessageStatus.OutTransferSize; // get the input string length char * iter = GPIB_StrCopyToCache( input_str, length ); // bufferize the string into internal cache // now @iter points to the cached string if( NULL == iter ) // Check if the string is cached successfully return -1; // error: cache overflow char * end = iter + length; // end of input string // Check the end of string: check the last character if( GPIB_CHAR_ENDLINE_SIGN == *(end-1) ) { // Shift @end back for one character // Now: @end points to end-of-line character end --; } else { // error: end-of-line character not found. // Maybe, input string is too long. return -1; } //-------------------------------------------------------------------------- sScpiCommand_t * xResult; // pointer to the processed command sScpiCommand_t * pCmdRoot = udi->usbtmcGpib.gpib_root; // root-command sScpiCommand_t * pCmdSearch = pCmdRoot; // search pointer in the tree //-------------------------------------------------------------------------- udi->usbtmcGpib.cRequestCountSupport = 1; //-------------------------------------------------------------------------- udi->usbtmcGpib.gpib_owner = pCmdRoot; // search in ROOT by default //-------------------------------------------------------------------------- size_t nCmdProcessed = 0; // count of processed commands int nCmdLength = 0; do { // Skip the only first command separator if( GPIB_CHAR_CMDSEPARATOR_SIGN == *iter ) { iter++; } // Search for the end of the command nCmdLength = GPIB_SearchCommand( iter, end, NULL ); if( nCmdLength > 0 ) { char * cmdStart; char * cmdEnd; // Trim the command if( GPIB_TrimCommand( iter, (iter + nCmdLength), &cmdStart, &cmdEnd ) > 0 ) { if( GPIB_CHAR_MANDATORY_IEEE488_SIGN == *cmdStart ) { pCmdSearch = pCmdRoot; // change the search pointer to the root } else if( GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN == *cmdStart ) { pCmdSearch = pCmdRoot; // change the search pointer to the root cmdStart++; // skip subsystem separator } udi->usbtmcGpib.gpib_search = pCmdSearch; udi->usbtmcGpib.sgpib_current = cmdStart; xResult = GPIB_Parse( udi, cmdStart, FALSE, cmdEnd ); if( NULL != xResult ) { // Success nCmdProcessed++; // increment the processed command counter } else { // Error // Form a error message /* 27/08/18 if(usbtmc_RaiseError( udi, GPIB_ERROR_ID_EXE, ERROR_USBTMC_INVALID_HEADER, "'", 1)) */ if(usbtmc_RaiseError( udi, errClass_Command, ERROR_USBTMC_INVALID_HEADER, "'", 1)) { if(usbtmc_RaiseError_CatDescription( udi, cmdStart, SubPointers(cmdEnd, cmdStart) ) ) { if( !usbtmc_RaiseError_CatDescription( udi, "'", 1 ) ) { usbtmc_ErrorQueue_RestoreCheckpoint( udi ); } } else usbtmc_ErrorQueue_RestoreCheckpoint( udi ); } else usbtmc_ErrorQueue_RestoreCheckpoint( udi ); xResult = pCmdSearch; } pCmdSearch = xResult; // set the search point for the next command iter += nCmdLength; } else break; } } while( nCmdLength > 0 ); return nCmdProcessed; } // //// ----------------------------------- //// GPIB_CommandExecute() выполнение строки комманд GPIB. //// root - указатель на root комманду дерева комманд //// GPIB_Commands_String - указатель на стоку комманд GPIB, разделенных точкой с запятой //int GPIB_CommandExecute( USB_DEVICE_INFO * udi, char * str ) { // // ---------------------------------------------------------------------------------------------------------- // // sScpiCommand_t * rc; // -- указатель на выполненную комманду // sScpiCommand_t * root = udi->usbtmcGpib.gpib_root; // -- корневая комманда древа комманд // sScpiCommand_t * Search=root; // -- указатель на текущий "путь" поиска комманды ////----------------------------------------------------- // unsigned int datatablesize = 0; // -- размер таблицы данных // unsigned int strl; // -- размер вх строки // unsigned int ret_val = 0; // -- возвращаемое значение количества распознанных комманд ////----------------------------------------------------- // BOOL datatable_found; // -- таблица данных найдена в строке ////----------------------------------------------------- // char * semicolon=NULL; // -- указатель на разделитель комманд, если такой есть в строке // char * datatable; // -- указатель на таблицу данных // char * stre; // -- конец строки // char * cmde; // конец комманды, // char * gstre; // -- конец строки GPIB ("") // char * squote; // -- кавычки строки GPIB // char * dquote; // -- кавычки строки GPIB // char * quote; // -- кавычки строки GPIB ////----------------------------------------------------- // // // ------------------------------- // udi->usbtmcGpib.gpib_owner = root; // -- поиск в root // // ------------------------------- // udi->usbtmcGpib.cRequestCountSupport = 1; // -- только один запрос в строке // // ------------------------------------------- // strl = udi->BulkMessageStatus.OutTransferSize; // -- длинна переданной строки комманд // str = GPIB_StrCopyToCache( str, strl ); // -- добавляет нуль символ к концу строки // stre = str + strl - 1; // -- конец строки. до 0x0A // if(str == NULL) return -1; // -- ОШИБКА ! НЕТ ПАМЯТИ! // // ------------------------------------------- // // // // ------- ИНИЦИАЛИЗАЦИЯ ПЕРЕДАЧИ ------ // // произведена в DEV_DEP_MSG_OUT() // // ------------------------------------- // // strucase( str, strl); // -- переводим строку в ВЕРХНИЙ РЕГИСТР // // while( *str || semicolon != NULL) // -- пока не дошли до конца строки // { // gstre = str; // // // ---------------------------------------------------------------------------------------- // // -- пропуск строки GPIB // do // { // // datatable = GPIB_StrChr_rw( gstre, GPIB_CHAR_DATATABLE_SIGN, stre ); // +поиск сигнатуры таблицы данных // semicolon = GPIB_StrChr_rw( gstre, GPIB_CHAR_CMDSEPARATOR_SIGN, stre ); // +поиск разделителя коммад // squote = GPIB_StrChr_rw( gstre, GPIB_CHAR_SINGLEQUOTE_SIGN, stre ); // +поиск строки GPIB // dquote = GPIB_StrChr_rw( gstre, GPIB_CHAR_DOUBLEQUOTE_SIGN, stre ); // +поиск строки GPIB // // if(quote = ChooseLowestPtr(squote,dquote)) // -- возвращает наиближайший указатель (наименьший, если оба не NULL. Если один NULL, возвращает второй) // if( quote == ChooseLowestPtr( quote, semicolon ) ) // -- если на пути строка GPIB (которая может содержать ';') // gstre = GPIB_GetStringEnd_rw( quote, strl - SubPointers(quote, str) ); // -- ищем ее конец // else // gstre = NULL; // else // gstre = NULL; // // } // while( gstre != NULL ); // // ---------------------------------------------------------------------------------------- // // // нужно разделить строку на комманды, (разделитель ;) причем, учесть, что // // после каждой комманды могут быть данные и ТАБЛИЦЫ данных типа #NZZZ..ZBBBBBB...B (см GPIB) // // или GPIB строки, заключенные в кавычки ("") или (' '). // // Для этого нужно пропарсить таблицы, так как они могут содержать разделитель (;) // // а также строки GPIB, они тоже могут содержать все что угодно // // // ================================================================================================================= // // // // ---------- пропуск таблиц данных ----------------------------- // // datatable_found = FALSE; // if(datatable!=NULL && (semicolon==NULL || ((unsigned int)semicolon> (unsigned int)datatable))) // если сигнатура обнаружена и она раньше разделителя // { // if(IsNUMBER(*(datatable+1))) // -- если за # следует цифра N ( цифра определяет длинну числа следом за ней ) // { // datatable_found = TRUE; // -- таблица данных обнаружена // // -- если за # и цифройN следует N цифр, то это заголовок таблицы данных // for( int m=1 ; datatable_found && (m<=(HexCharToNumber(*(datatable+1)))) ; m++) // if( !IsNUMBER( *(datatable+1+m) ) ) // -- проверяем что все это цифры // datatable_found = FALSE; // -- выход из цикла (см заголовок for) // } // } // else // datatable_found = FALSE; // -- таблиа данных не обнаружена // // ------------------------------------------------------------- // // // if(datatable_found==FALSE) // -- если не обнаружена таблица или разделитель раньше таблицы // { // if(semicolon!=NULL) // { // *semicolon = 0x00; // -- делим комманду // cmde = semicolon; // } // else // cmde = stre; // -- конец сообщения // } // else // { // semicolon = NULL; // char * data; // datatablesize = 0; // datatable++; // -- пропускаем # //str++; //!#! #!# // // // int n = HexCharToNumber(*(datatable)); // +цифра N определяет количество цифр после #NZZZZZBBBBBBBBBBB // // +N - количество Z // // +Z - цифры составляют число, которое определяет длинну таблицы ( количетсво B ) // data = datatable + n + 1; // +устанавливаем указатель на начало таблицы // datatable++; // +уст указатель на начало числа ZZZZ // StrToInt( datatable, n, &n ); // +конвертиуем число записанное в ZZZZ в str в число в int в n // // // --- таблица данных начинается с datatable и длинна ее n // // datatable += n+1; // +прыгаем к концу таблицы данных !#! // cmde = datatable; // semicolon = GPIB_StrChr_rw( datatable, GPIB_CHAR_CMDSEPARATOR_SIGN, stre); // +ищем разделитель снова, но уже после таблицы данных // if(semicolon == datatable) datatable++; // +если он сразу после таблицы, проспускаем его, чтобы не выполнять пустую комманду // // datatable = data; // datatablesize = n; // } // // ================================================================================================================= // // if(datatable_found==TRUE) // if(datatablesize>0) // ; // // // while( IsWhiteChar( *str ) ) str++; // -- пропуск WHITE // // if( *str == GPIB_CHAR_MANDATORY_IEEE488_SIGN || (*str == GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN && (str++)) ) Search = root; // /* проверям, абсолютный ли путь задан // FAQ: если путь абс., он имеет двоеточие в начале. Если есть двоеточие, // то первое условие в if() выполнится и выполнится второе, // которое по сути просто сдвинет указатель str так, чтобы исключить двоеточие // поиск будет произведен в root, так как пусть абсолютный */ // // udi->usbtmcGpib.gpib_search = Search; // udi->usbtmcGpib.sgpib_current = str; // // // // if(NULL != (rc=parse( udi,str, FALSE, cmde))) // { // -- обработка одной составной комманды в строке // // ret_val++; // -- инкрементируем счетчик выполненных комманд // // } // else // { // // if( SubPointers( cmde, str ) > 0 ) // if( INT(cmde) - INT(str) > 0 ) // { char * tmpe = cmde; // if( IsEndOfLine(*tmpe) ) tmpe--; // while( IsWhiteChar(*tmpe) ) tmpe--; // if(usbtmc_RaiseError( udi, GPIB_ERROR_ID_EXE ,ERROR_USBTMC_INVALID_HEADER, "'", 1)) // if(usbtmc_RaiseError_CatDescription( udi, str , SubPointers( tmpe+1, str ) )) // strl подсчитывается в начале ф-ии. -1 -это пропуск 0x0A; алсо: (INT(tmpe+1) - INT(str)) ===> SubPointers( tmpe+1, str ) // usbtmc_RaiseError_CatDescription( udi, "'", 1 ); // // } // // rc= Search; // } // // // // if( semicolon != NULL ) { // -- если не NULL, значит есть еще не выполненные команды в строке // str = (++semicolon); // -- переход к следующей комманде в строке, исключаяя точку с запятой // if( *str != GPIB_CHAR_SCPI_SUBSYS_SEPARATOR_SIGN ) // -- если комманда не абсолютная и путь ее опущен // Search = rc; // -- указываем путь поиска на последний путь, где была выполнена комманда // } else break; // -- если NULL выходим, нет больше комманд в строке // // } // // return ret_val; // -- возвращаем количество распознанных комманд //} // =========================================== ОБРАБОТЧИКИ ====================================================== unsigned int GPIB_Default_Handler( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // 27/08/18 GPIB_RaiseStandartError( udi, ERROR_GPIB_UNCOMPLETE_COMMAND, NULL, errClass_Command // == invalid header detected ); /* GPIB_RaiseStandartError( udi, ERROR_GPIB_UNCOMPLETE_COMMAND, NULL, GPIB_ERROR_ID_COR | request ); */ return 0; } // ==================================================================================================== // GPIB_EnumParameters: // Processes the @pParamString with @length length and parses the command parameters. // The following SCPI types are supported: // - NR1, NR2, NR3 // - Mnemonic (character) // - Strings // - binary DataBlock // All the parameters are packed into the @pQueue // In case an error occurred, the function interrupts processing and return an error code. // Note: in case of error the @pQueue is already modified. // @pParamString - the source string // @length - the length of @pParamString // @pQueue - the queue to pack parameters in // @pEnd - (NOT IMPLEMENTED!) optional pointer to store the end of parsed string after parsing. Can be NULL. // If @pEnd isn't NULL, it will contain the pointer to the character after the lastest parsed character in @pParamString. // Return: error code (negative) or number of parsed parameters (positive) int GPIB_EnumParameters( const char * pParamString, size_t length, QUEUE * pQueue, const char ** pEnd ) { if( NULL == pParamString || 0 == length || NULL == pQueue ) return -1; if( NULL != pEnd ) { *pEnd = NULL; // not implemented } int rval = 0; int nsys = 0; // numeric system size_t count = 0; // amount of parameters enumerated eQuoteMode_t qMode; // quoting mode (single/double) eParameterType_t eParamType = eParTypeNone; // parameter type const char * pParamStart = NULL; // the parameter start pointer in @pParamString const char * end = NULL; BOOL bSeparator = FALSE; // flag: separator found while( length > 0 ) // parameter search cycle { bSeparator = FALSE; // clear flag: allow a separator character in this search cycle // --------------------------------------------------------------------- while( length > 0 ) // white characters skipping cycle { // check current character: is it a white character? if( IsWhiteChar( *pParamString ) ) { // yes. skip this character pParamString++; length--; // check the next character continue; } // check current character: is this a end-of-line character? if( IsEndOfLine( *pParamString ) ) { // yes. skip this character pParamString++; length--; // if the line ends and the length is still greater than zero: // it is an error condition if( length > 0 ) { // interrupt all procedures and exit rval = (-1); goto L_EnumParameters_EXIT; } // Okay, @length is 0. // The next "continue" will interrupt the main cycle. // But let's check the @bSeparator. // If @bSeparator is TRUE, it means a trailing separator found. if( bSeparator ) { // error: trailing separator found rval = (-2); goto L_EnumParameters_EXIT; } // exit the main cycle, because @length == 0 goto L_EnumParameters_EXIT; } // check if this character is an argument separator character (by default is ',') if( GPIB_CHAR_ARGSEPARATOR_SIGN == *pParamString ) { // Yes: it is an argument separator // check if the separator is allowed now // If @bSeparator is already TRUE then it means the separator is disallowed // Otherwise, the separator is allowed. if( ! bSeparator ) { bSeparator = TRUE; // set the flag: the separator is found in current cycle pParamString++; // skip the character length--; // check the next character continue; } else { // No: the separator is already found before. // Extra separator found: error // interrupt all procedures and exit rval = (-3); goto L_EnumParameters_EXIT; } } else { // No: it's neither a white character or separator character // interrupt the skipping cycle. break; } } // :while( length > 0 ) // --------------------------------------------------------------------- // White character are skipped. // An argument separator processed. // It is assumed that the next character is an argument. // check if the argument separator presents between arguments if( (count > 0) && (!bSeparator) ) { // In this point @bSeparator must be TRUE in order all the arguments // must be separated. // The only one exception: @count == 0, it means neither argument or // or separator found yet in the string. // interrupt all procedures and exit rval = (-4); goto L_EnumParameters_EXIT; } // --------------------------------------------------------------------- // Analyze the current character and check for the string type switch( *pParamString ) { // the quoted string in single quotes case GPIB_CHAR_SINGLEQUOTE_SIGN: qMode = eqmSingle; break; // the quoted string in double quotes case GPIB_CHAR_DOUBLEQUOTE_SIGN: qMode = eqmDouble; break; // not quoted argument default: qMode = eqmNone; } // // --------------------------------------------------------------------- // // Let's determine the parameter type // size_t nParamSize; // parameter size in [characters] // if the quoted string is found: if( IsQuote( *pParamString , qMode ) ) { // search for the end of quoted string end = GPIB_GetStringEnd( pParamString, length ); // check if the string is closed if( NULL == end ) { // error: unclosed quoted string // interrupt all procedures and exit rval = (-5); goto L_EnumParameters_EXIT; } // calculate the parameter size in characters nParamSize = (size_t)SubPointers( end, pParamString ); // set the parameter start pointer pParamStart = pParamString; // skip the parameter's body in the parent string. length -= nParamSize; pParamString += nParamSize; // And at last, set the parameter type to @eParamType. It is string. eParamType = eParTypeString; // modify the parameter value: "STR" -> STR // delete quotes: pParamStart++; nParamSize-=2; // stop analyzing and process the parameter goto L_EnumParameters_END; } // --------------------------------------------------------------------- // Here: parameter is not a string parameter for sure // Maybe it is a mnemonic, numeric or datablock parameter { // Firstly check for DataBlock format: // @dataBlockError will store the error code of @IsDataBlock() function int dataBlockCode = err_IsDataBlock_Success; // Check the datablock if( IsDataBlock( pParamString, length, &nParamSize, &dataBlockCode ) ) { // datablock detected. // Now @nParamSize is the size of whole datablock segment // set the parameter start pointer pParamStart = pParamString; // -------------------------------------------------------- // Note: @nParamSize is whole size of data block parameter, // including the signature and service fields. // -------------------------------------------------------- // skip the parameter's body in the parent string. pParamString += nParamSize; length -= nParamSize; // And at last, set the parameter type to @eParamType. It is datablock. eParamType = eParTypeDatablock; // modify the parameter value: // Set @pParamStart to the start of binary payload // Set @nParamSize to the binary payload size (@dataBlockCode) nParamSize = dataBlockCode; pParamStart = pParamString - nParamSize; // stop analyzing and process the parameter goto L_EnumParameters_END; } else { switch( dataBlockCode ) { // datablock not detected case err_IsDataBlock_NotFound: break; // datablock signature detected. // Maybe it is not datablock, // Maybe it is corrupted parameter case err_IsDataBlock_Invalid: case err_IsDataBlock_Trimmed: case err_IsDataBlock_Huge: #if 0 // hmmm. is it error? rval = (-6); goto L_EnumParameters_EXIT; #endif break; } } } // --------------------------------------------------------------------- // Here: parameter is neither a string parameter or datablock parameter // Maybe it is a mnemonic or numeric // Ok, search for the end of the parameter // search for the end of parameter // @GPIB_GetParameterEnd searches til the first white character or the end-of-line. end = GPIB_GetParameterEnd( pParamString, length ); // check if the end of the parameter is found if( NULL == end ) { // error: endless parameter // interrupt all procedures and exit rval = (-7); goto L_EnumParameters_EXIT; } { // calculate the parameter size in characters nParamSize = (size_t)SubPointers( end, pParamString ); // set the parameter start pointer pParamStart = pParamString; // skip the parameter's body in the parent string. length -= nParamSize; pParamString += nParamSize; } // Check for "MNEMONIC" parameter type if( IsCharacter( *pParamStart ) ) { // First character is an "alhpa-character": // So, the parameter will be considered as "MNEMONIC" // Validate the parameter format: if( ! GPIB_StrChkFormat( pParamStart, nParamSize, eSCM_MNEMONIC ) ) { // invalid parameter format: some invalid characters found // interrupt all procedures and exit rval = (-8); goto L_EnumParameters_EXIT; } // And at last, set the parameter type to @eParamType. It is MNEMONIC (character-parameter). eParamType = eParTypeChar; // stop analyzing and process the parameter goto L_EnumParameters_END; } // --------------------------------------------------------------------- // Here: parameter is numeric: NR1, NR2 or NR3 (SCPI types) // Check for NR1: nsys = 0; // numeric system // Try to determine the numeric system if( IsNumericSystem(pParamStart) ) { // NR1, numeric system specified // Numeric system detected: get the numeric system base nsys = GetNumericSystemBase( pParamStart ); switch( nsys ) { // unknown system case 0: rval = (-9); goto L_EnumParameters_EXIT; break; // Binary system case 2: if( GPIB_StrChkFormat( pParamStart,nParamSize,eSCM_BIN ) ) { // Invalid character for binary system rval = (-10); goto L_EnumParameters_EXIT; } break; // Octal system case 8: if( GPIB_StrChkFormat( pParamStart,nParamSize,eSCM_OCT ) ) { // Invalid character for octal system rval = (-10); goto L_EnumParameters_EXIT; } break; // Hexademical system case 16:if( GPIB_StrChkFormat( pParamStart,nParamSize,eSCM_HEX ) ) { // Invalid character for hexademical system rval = (-10); goto L_EnumParameters_EXIT; } break; } // And at last, set the parameter type to @eParamType. It is NR1 (numeric, integer) eParamType = eParTypeNR1; // stop analyzing and process the parameter goto L_EnumParameters_END; } // --------------------------------------------------------------------- // Here: parameter is numeric: NR1, NR2 or NR3 (SCPI types) // Check for NR1 if( GPIB_StrChkFormat( pParamStart,nParamSize,eSCM_DEC ) ) { eParamType = eParTypeNR1; // stop analyzing and process the parameter goto L_EnumParameters_END; } // Check for NR2 if( GPIB_StrChkFormat( pParamStart,nParamSize,eSCM_FLOAT ) ) { eParamType = eParTypeNR2; // stop analyzing and process the parameter goto L_EnumParameters_END; } // Check for NR3 if( GPIB_StrChkFormat( pParamStart,nParamSize,eSCM_EXP ) ) { eParamType = eParTypeNR2; // stop analyzing and process the parameter goto L_EnumParameters_END; } // --------------------------------------------------------------------- // No valid format detected // Here: invalid parameter format // Invalid character for binary system rval = (-11); goto L_EnumParameters_EXIT; // --------------------------------------------------------------------- L_EnumParameters_END: // Valid format detected: // @pParamStart - the beginning of parameter // @nParamSize - the size of parameter // @eParamType - the type of parameter // ------------------------------------------------------------------------- // Push the parameter into the parameters queue { BYTE pkdParamType = eParamType; // 1-byte packed parameter type // push the type if( !queue_add( pQueue, &pkdParamType, sizeof(pkdParamType) ) ) { // parameters queue overflow rval = (-12); goto L_EnumParameters_EXIT; } // push the string value if( !queue_cat( pQueue, pParamStart, nParamSize ) ) { // parameters queue overflow rval = (-13); goto L_EnumParameters_EXIT; } } // increment amount of parsed parameters count++; } rval = count; L_EnumParameters_EXIT: return rval; } // ==================================================================================== eChrz_t GPIB_GetChrzTableId( const char * pParamText, size_t nTextLen ) { eChrz_t ID = eCh_MAX; if( 0 == strncmp( pParamText, "FACT", nTextLen ) && 4 == nTextLen ) ID = eChFactory; else if( 0 == strncmp( pParamText, "FACTORY",nTextLen ) && 7 == nTextLen ) ID = eChFactory; else if( 0 == strncmp( pParamText, "USER1", nTextLen ) && 5 == nTextLen ) ID = eChUser1; else if( 0 == strncmp( pParamText, "USER2", nTextLen ) && 5 == nTextLen ) ID = eChUser2; else if( 0 == strncmp( pParamText, "USER3", nTextLen ) && 5 == nTextLen ) ID = eChUser3; return ID; } // ==================================================================================== ePortId_t GPIB_GetPortId( const char * pParamText, size_t nTextLen ) { ePortId_t ID = ePortId_MAX; if( 0 == strncmp( pParamText, "A", nTextLen ) && 1 == nTextLen ) ID = ePortId_A; else if( 0 == strncmp( pParamText, "B", nTextLen ) && 1 == nTextLen ) ID = ePortId_B; else if( 0 == strncmp( pParamText, "C", nTextLen ) && 1 == nTextLen ) ID = ePortId_C; else if( 0 == strncmp( pParamText, "D", nTextLen ) && 1 == nTextLen ) ID = ePortId_D; return ID; } // ==================================================================================== ePortComb_t GPIB_GetPortComb( const char * pParamText, size_t nTextLen ) { ePortComb_t ID = ePortComb_UNDEFINED; if( 0 == strncmp( pParamText, "A", nTextLen ) && 1 == nTextLen ) ID = ePortComb_A; else if( 0 == strncmp( pParamText, "B", nTextLen ) && 1 == nTextLen ) ID = ePortComb_B; else if( 0 == strncmp( pParamText, "C", nTextLen ) && 1 == nTextLen ) ID = ePortComb_C; else if( 0 == strncmp( pParamText, "D", nTextLen ) && 1 == nTextLen ) ID = ePortComb_D; else if( 0 == strncmp( pParamText, "AB", nTextLen ) && 2 == nTextLen ) ID = ePortComb_AB; else if( 0 == strncmp( pParamText, "AC", nTextLen ) && 2 == nTextLen ) ID = ePortComb_AC; else if( 0 == strncmp( pParamText, "AD", nTextLen ) && 2 == nTextLen ) ID = ePortComb_AD; else if( 0 == strncmp( pParamText, "BC", nTextLen ) && 2 == nTextLen ) ID = ePortComb_BC; else if( 0 == strncmp( pParamText, "BD", nTextLen ) && 2 == nTextLen ) ID = ePortComb_BD; else if( 0 == strncmp( pParamText, "CD", nTextLen ) && 2 == nTextLen ) ID = ePortComb_CD; else if( 0 == strncmp( pParamText, "CHEC",nTextLen) && 4 == nTextLen ) ID = ePortComb_CHECK; else if( 0 == strncmp( pParamText, "CHECK",nTextLen)&& 5 == nTextLen ) ID = ePortComb_CHECK; return ID; } // ==================================================================================== ePortStateId_t GPIB_GetPortStateId( const char * pParamText, size_t nTextLen ) { ePortStateId_t ID = ePortStateId_UNDEFINED; if( 4 == nTextLen && 0 == strncmp( pParamText, "SHOR", nTextLen ) ) ID = ePortStateId_Short; else if( 5 == nTextLen && 0 == strncmp( pParamText, "SHORT", nTextLen ) ) ID = ePortStateId_Short; else if( 4 == nTextLen && 0 == strncmp( pParamText, "OPEN", nTextLen ) ) ID = ePortStateId_Open; else if( 4 == nTextLen && 0 == strncmp( pParamText, "LOAD", nTextLen ) ) ID = ePortStateId_Load; else if( 5 == nTextLen && 0 == strncmp( pParamText, "OPEN2", nTextLen ) ) ID = ePortStateId_Open2; else if( 5 == nTextLen && 0 == strncmp( pParamText, "LOAD2", nTextLen ) ) ID = ePortStateId_Load2; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S11", nTextLen ) ) ID = ePortStateId_S11; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S12", nTextLen ) ) ID = ePortStateId_S12; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S13", nTextLen ) ) ID = ePortStateId_S13; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S14", nTextLen ) ) ID = ePortStateId_S14; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S21", nTextLen ) ) ID = ePortStateId_S21; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S22", nTextLen ) ) ID = ePortStateId_S22; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S23", nTextLen ) ) ID = ePortStateId_S23; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S24", nTextLen ) ) ID = ePortStateId_S24; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S31", nTextLen ) ) ID = ePortStateId_S31; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S32", nTextLen ) ) ID = ePortStateId_S32; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S33", nTextLen ) ) ID = ePortStateId_S33; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S34", nTextLen ) ) ID = ePortStateId_S34; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S41", nTextLen ) ) ID = ePortStateId_S41; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S42", nTextLen ) ) ID = ePortStateId_S42; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S43", nTextLen ) ) ID = ePortStateId_S43; else if( 3 == nTextLen && 0 == strncmp( pParamText, "S44", nTextLen ) ) ID = ePortStateId_S44; return ID; } // ==================================================================================== /* EPORT GPIB_GetPortID( char * sQueueParameter, unsigned int dwQueueParameterSize ) { EPORT port = ePORT_NONE; if(0==strncmp(sQueueParameter+1,"A",dwQueueParameterSize-1) && dwQueueParameterSize>1) port = ePORT_A; else if(0==strncmp(sQueueParameter+1,"B",dwQueueParameterSize-1) && dwQueueParameterSize>1) port = ePORT_B; else if(0==strncmp(sQueueParameter+1,"AB",dwQueueParameterSize-1) && dwQueueParameterSize>2)port = ePORT_AB; return port; } */ // ==================================================================================== /* ESTATE GPIB_GetKeystateID( char * sQueueParameter, unsigned int dwQueueParameterSize, BOOL ExpandFormat ) { ESTATE state = eSTATE_NONE; if(0==strncmp(sQueueParameter+1,"OPEN",dwQueueParameterSize-1) && dwQueueParameterSize>4) state = eSTATE_OPEN; else if(0==strncmp(sQueueParameter+1,"LOAD",dwQueueParameterSize-1) && dwQueueParameterSize>4) state = eSTATE_LOAD; else if(0==strncmp(sQueueParameter+1,"SHORT",dwQueueParameterSize-1) && dwQueueParameterSize>4) state = eSTATE_SHORT; //SHOR==SHORt else if(0==strncmp(sQueueParameter+1,"OPEN2",dwQueueParameterSize-1) && dwQueueParameterSize>5) state = eSTATE_OPEN2; else if(0==strncmp(sQueueParameter+1,"LOAD2",dwQueueParameterSize-1) && dwQueueParameterSize>5) state = eSTATE_LOAD2; else if(ExpandFormat == FALSE && 0==strncmp(sQueueParameter+1,"THRU",dwQueueParameterSize-1) && dwQueueParameterSize>4) state = eSTATE_THRU; else if(ExpandFormat == FALSE && 0==strncmp(sQueueParameter+1,"ATT",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_ATTEN; else if(ExpandFormat) if(0==strncmp(sQueueParameter+1,"T11",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_T11; else if(0==strncmp(sQueueParameter+1,"T12",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_T12; else if(0==strncmp(sQueueParameter+1,"T21",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_T21; else if(0==strncmp(sQueueParameter+1,"T22",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_T22; else if(0==strncmp(sQueueParameter+1,"A11",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_A11; else if(0==strncmp(sQueueParameter+1,"A12",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_A12; else if(0==strncmp(sQueueParameter+1,"A21",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_A21; else if(0==strncmp(sQueueParameter+1,"A22",dwQueueParameterSize-1) && dwQueueParameterSize>3) state = eSTATE_A22; else state = eSTATE_NONE; return state; } */ // ==================================================================================== unsigned int GPIB_RaiseStandartError( USB_DEVICE_INFO * udi, unsigned int errCode, // error code const char * pDescription, // error description GPIB_ErrorClass_t errClass // error class ) { const char * pStrCurrentCmd = udi->usbtmcGpib.sgpib_current; // search for the command header's end while( !(IsWhiteChar( *pStrCurrentCmd ) || IsEndOfLine( *pStrCurrentCmd )) ) { pStrCurrentCmd++; } size_t nCmdLength = SubPointers( pStrCurrentCmd, udi->usbtmcGpib.sgpib_current); pStrCurrentCmd = udi->usbtmcGpib.sgpib_current; switch( errCode ) { case ERROR_GPIB_BUFFER_OVERFLOW: { if( errClass_Autodetect == errClass ) errClass = errClass_Execution; //ERROR_USBTMC_BUFFER_OVERFLOW_IN if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_INTERNAL, " in '", 5 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "': ", 3 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; break; } } break; case ERROR_GPIB_DATA_NOT_FOUND: { if( errClass_Autodetect == errClass ) errClass = errClass_Execution; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_DATANOTFOUND, " in '", 5 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "': ", 3 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; break; } /* if(usbtmc_RaiseError( udi, ErrorIdetnificator, ERROR_USBTMC_DATANOTFOUND, "", 0 ) ) { if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; } } else errCode = 0;*/ } break; case ERROR_GPIB_THERMDATA_NOT_FOUND: { if( errClass_Autodetect == errClass ) errClass = errClass_Execution; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_NOTHERMCOMPDATA, " in '", 5 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "': ", 3 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; break; } /*if( !usbtmc_RaiseError( udi, ErrorIdetnificator, ERROR_USBTMC_NOTHERMCOMPDATA, pDescription, strlen(pDescription) ) ) { errCode = 0; }*/ } break; case ERROR_GPIB_UNCOMPLETE_COMMAND: { if( errClass_Autodetect == errClass ) errClass = errClass_Command; if(usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_INVALID_HEADER, "'", 1 )) { if( usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { if( !usbtmc_RaiseError_CatDescription( udi, "'", 1 ) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; } break; /* case ERROR_GPIB_PARAMETER_NOT_SUPPORTED: { if( errClass_Autodetect == errClass ) errClass = errClass_Execution; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_PARAMETER, " in '", 5 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "'", 1 ) ) { errCode = 0; break; } // if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) // { // errCode = 0; break; // } // if(usbtmc_RaiseError( udi,ErrorIdetnificator, ERROR_USBTMC_PARAMETER, "'", 1 )) // { // if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) // { // errCode = 0; // } // } // else // errCode = 0; } break; */ case ERROR_GPIB_TRIGGER_IGNORED: { if( errClass_Autodetect == errClass ) errClass = errClass_Command; if(usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_TRIGGERIGNORED, "'", 1 )) { if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "'", 1) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; } break; case ERROR_GPIB_REQUEST_ONLY_SUPPORT: { if( errClass_Autodetect == errClass ) errClass = errClass_Command; if(usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_REQUESTONLY, "'", 1 )) { if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "': request only supported", 25 ) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; } break; case ERROR_GPIB_ARRAY_CORRUPTED: { if( errClass_Autodetect == errClass ) errClass = errClass_Execution; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_ARRAY_CORRUPTED, "in '", 4 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "': ", 3 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; break; } /* if(usbtmc_RaiseError( udi,ErrorIdetnificator, ERROR_USBTMC_ARRAY_CORRUPTED, "'", 1 )) { if(usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) )) //if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "': invalid checksumm", 20 ) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; */ } break; /* case ERROR_GPIB_HEADER_CORRUPTED: { if(usbtmc_RaiseError( udi,ErrorIdetnificator, ERROR_USBTMC_HEADER_CORRUPTED, "'", 1 )) { if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "': header corrupted", 18 ) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; } break; */ case ERROR_GPIB_TOO_MANY_REQUESTS: { if( errClass_Autodetect == errClass ) errClass = errClass_Device; if(usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_TOOMANY_REQUESTS, "'", 1 )) { if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "')", 2) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; } break; case ERROR_GPIB_COMMAND_ONLY_SUPPORT: { if( errClass_Autodetect == errClass ) errClass = errClass_Command; if(usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_COMMANDONLY, "'", 1 )) { if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "': request is unexpected", 24) ) { errCode = 0; } } else errCode = 0; } else errCode = 0; } break; case ERROR_GPIB_INTERNAL: { if( errClass_Autodetect == errClass ) errClass = errClass_Device; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_INTERNAL, " at command '", 13 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "'", 1 ) ) { errCode = 0; break; } //usbtmc_RaiseError( udi,ErrorIdetnificator, ERROR_USBTMC_INTERNAL, ".", 1 ); } break; case ERROR_GPIB_INVALID_ENUM_PARAMETERS: { if( errClass_Autodetect == errClass ) errClass = errClass_Command; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_PARAMETER, "in '", 4 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, "': parsing failed", 17 ) ) { errCode = 0; break; } /* if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; break; } */ /* if(usbtmc_RaiseError( udi,ErrorIdetnificator, ERROR_USBTMC_EXECUTION, " at '", 5 )) { if(usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength)) { if( !usbtmc_RaiseError_CatDescription( udi, "'", 1) ) { errCode = 0; } } else errCode = 0; } else errCode = 0;*/ } break; default: { if( errClass_Autodetect == errClass ) errClass = errClass_Command; if( !usbtmc_RaiseError( udi, errClass, ERROR_USBTMC_PARAMETER, "in '", 4 ) ) { errCode = 0; break; } if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; break; } /* if( !usbtmc_RaiseError_CatDescription( udi, "'", 1 ) ) { errCode = 0; break; } */ /* if( !usbtmc_RaiseError_CatDescription( udi, pDescription, strlen(pDescription) ) ) { errCode = 0; break; } */ /* if(usbtmc_RaiseError( udi,ErrorIdetnificator, ERROR_USBTMC_PARAMETER, "in '", 4 )) { if( !usbtmc_RaiseError_CatDescription( udi, pStrCurrentCmd, nCmdLength ) ) { errCode = 0; // не удалось записать ошибку, значит и продолжать (идти во второй switch) не стоит } } else errCode = 0;*/ } } // ------------ 220 error --------------------------------------------------------- switch( errCode ) { case ERROR_GPIB_INVALID_PARAMETER_TYPE: // так как ошибка типа возникнет лишь тогда, когда get сможет достать параметр и его тип из очереди. А он него не достатнет, потому что зачастую ему не хватит места в буфере case ERROR_GPIB_INVALID_PARAMETER: { if( !usbtmc_RaiseError_CatDescription( udi, "': invalid parameter", 20 ) ) { errCode = 0; } } break; case ERROR_GPIB_WRONG_PARAMETERS_COUNT: { if( !usbtmc_RaiseError_CatDescription( udi, "': wrong parameters count", 25 ) ) { errCode = 0; } } break; /* case ERROR_GPIB_PARAMETER_NOT_SUPPORTED: { usbtmc_RaiseError_CatDescription( udi, "': parameter not supported", 26 ); } break; */ default:; } //---------------------- // error occurred while pushing the raised error into the queue if( errCode == 0 ) { usbtmc_ErrorQueue_RestoreCheckpoint( udi ); } //---------------------- return 0; } /* unsigned int CheckCompatibilePorts( ESTATE state, EPORT port ) { // проверка правильности указания портов и состояний вообще if( !( ( state == eSTATE_SHORT || state == eSTATE_LOAD || state == eSTATE_OPEN || state == eSTATE_LOAD2 || state == eSTATE_OPEN2 || state == eSTATE_T11 || state == eSTATE_T12 || state == eSTATE_T21 || state == eSTATE_T22 || state == eSTATE_A11 || state == eSTATE_A12 || state == eSTATE_A21 || state == eSTATE_A22 ) && ( port == ePORT_A || port == ePORT_B || port == ePORT_AB ) ) ) return FALSE; //--------------------------------------------------------------------------------------------------------------------------------------- // проверка правильности указания порта (A/B) для сосотояния SH/LD/OP/OP2/LD2 if( ( ( state == eSTATE_SHORT || state == eSTATE_LOAD || state == eSTATE_OPEN || state == eSTATE_LOAD2 || state == eSTATE_OPEN2 ) && ( port != ePORT_A && port != ePORT_B ) ) ) return FALSE; //--------------------------------------------------------------------------------------------------------------------------------------- // проверка правильности указания порта (AB) для сосотояния T11/T12/T21/T22/A11/A12/A21/A22 if( ( ( state == eSTATE_T11 || state == eSTATE_T12 || state == eSTATE_T21 || state == eSTATE_T22 || state == eSTATE_A11 || state == eSTATE_A12 || state == eSTATE_A21 || state == eSTATE_A22 ) && ( port != ePORT_AB ) ) ) return FALSE; return TRUE; } unsigned int CheckCompatibilePorts2( ESTATE state, EPORT port ) // using in Path:STATE { // проверка правильности указания портов и состояний вообще if( !( ( state == eSTATE_SHORT || state == eSTATE_LOAD || state == eSTATE_OPEN || state == eSTATE_LOAD2 || state == eSTATE_OPEN2 || state == eSTATE_THRU || state == eSTATE_ATTEN ) && ( port == ePORT_A || port == ePORT_B || port == ePORT_AB ) ) ) return FALSE; //--------------------------------------------------------------------------------------------------------------------------------------- // проверка правильности указания порта (A/B) для сосотояния SH/LD/OP/OP2/LD2 if( ( ( state == eSTATE_SHORT || state == eSTATE_LOAD || state == eSTATE_OPEN || state == eSTATE_LOAD2 || state == eSTATE_OPEN2 ) && ( port != ePORT_A && port != ePORT_B ) ) ) return FALSE; //--------------------------------------------------------------------------------------------------------------------------------------- // проверка правильности указания порта (AB) для сосотояния T11/T12/T21/T22/A11/A12/A21/A22 if( ( state == eSTATE_THRU || state == eSTATE_ATTEN ) && ( port != ePORT_AB ) ) return FALSE; return TRUE; } */ unsigned int GPIBInit( USB_DEVICE_INFO * udi ) { _ESE = 0x00; _SRE = 0x00; // Standard Event Status Register (ESR): bit Power On // 27/08/18 // Note: in this implementation this bit is disabled // GPIB_SET_PWN(); // GPIB_SET_OPC(); return 0; } #endif