#include "lpc176x.h" #include "usb_hardware.h" #include #include #include "options.h" #ifdef USBTMC // #endif в конце файла #include "utils.h" #include "gpib_parser.h" #include "usb_enumeration.h" #include "usbtmc.h" #include "utilits.h" #include "usb_options.h" //#include "spi.h" #include "i2_c.h" #include "common\buffer.h" #include #include "usb_application.h" #include "usb_proto.h" #include "acm_base.h" #include "acm_base_model.h" #define DBPOINTS_BUFFER_NUM 128 // @dbPointsBuffer - the temporary buffer for the points in the intermediate, double format static sACMChrzPoint_t dbPointsBuffer[ DBPOINTS_BUFFER_NUM ]; // ============================================================================================== // GPIB функции идентичны по строению. Вначале они получают указатель на выходной буфер данных, // куда собираются печатать ответ (pBulkData_DeviceOut) и размер этого буфера (MAX). // Далее, из очереди pQParameters в зависимости от функции извлекаются параметры в том виде, в каком // они были переданы от компьютера, за исключением того, что первым байтом каждого параметра является // его тип (eParTypeChar, eParTypeNR1, ...) - тип параметра может быть строковый, числовой, символьный и т.п. // К тому же, в зависимости от функции, проверяется количество переданных параметров, если оно не сов- // падает, функция генерирует ошибку и завершает работу. Параметры извлекаются по очереди, если не удалось // извлечь хотя бы один, функция генерирует ошибку и завершает работу. Далее, параметры обрабатываются // в зависимости от их типа и предполагаемого назначения (задается функцией), получаются конкретные // значения, например тип порта (ePORT_A, ePORT_B из "A" и "B"). Если значение параметра не корректно, // тоесть невозможно преобразовать порт C например, параметр объявляется ошибочным и функция ведет себя // аналогично, как и в случае с ошибкой получения параметра - то есть завершает работу, генерируя ошибку // Также она себя ведет, если значение параметра понято, обработано, но не применимо в данной ситуации, // например, невозможно установить состояние THRU для одного порта A. // // Если все эти условия не выполнились, функция приступает к генерации ответа, если она запросная // Если нет, выполняет какие-то дейтсвия. Если функция запросная, а вызвана как комманда, функция генерирует ошибку. // И наоборот, коммандные функции не могут вызываться как запрос. (Конечно, если функция Командно-запросная, ничего страшного) // // Функция GPIB ВСЕГДА возвращает количество записанных в буфер символов. // // Если функции недостаточно места в буфере, как например в случае с MEM:TABLE:DATA, она поступает так: // она сохраняет контекст выполнения (все необходимые ей данные, для того чтобы можно было начать выполнениеъ // с места остановки), регистриует себя в качестве обработчика события опустошения буфера. Затем функция // сбросит флаг EOM и завершит работу. Обработчик канала USB будет знать, что это сообщение не последнее, EOM сброшен. // Как только место в буфере освободится, обработчик канала USB (см в endpoints.c) вызовет функцию еще раз. // На этот раз, она будет знать, что вызвана по событю опустошения буфера и загрузит контекст выполнения, // подготовит часть данных, которая уместится в освободившееся место, и вновь, при необходимости, повторит // такую операцию с сохранением-загрузкой контекста. Как только функция обнаружит, что все данные переданы, // она не станет сбрасывать EOM, не станет сохранять контекст а просто завершится. // // Если при работе функции возникает ошибка, она передается в функцию RaiseStandartError, та в свою // очередь, зная код ошибки, запишет необходимые данные в очередь ошибок, включая необходимое описание // ошибки (если необходимо). При вызове SYST:ERR? эта ошибка приобретает сформатированный вид и выдается наружу. // // Некоторые команды, например MEM:TABLE:FREQ:STAR и MEM:TABLE:FREQ:STOP абсолютно идентичны по топологии // но различаются лишь в самом последнем звене - смещению данных в стуртуре заголовка, которые нужно // выдать в ответе. Чтобы не делать две одинаковые функции, отличающиеся только одним словом, сделаны т.н. // специальные функции. При инициализации GPIB дерева обычные команды регистрируют на себя по одной функции. // Специальные команды делят между собой одну единственную обслуживающую функцию. Эта функция идентифицирует // каждую команду и запрос по специальному полю FunctionID, которое помещается в очередь параметров функции pQParameters // перед вызовом и перед занесением в очередб параметров функции. Это поле задается для каждой команды // уникальным 32 разрядным числом при иницализации дерева команд GPIB. Функция обязательно должна знать, что // это поле нужно прочесть и использоватть. Для этого, перед получением параметров функции, она должна извлечь // FunctionID из очереди как обычный параметр. В зависимости от значения параметра FunctionID она должна // предпринимать различные действия: в одном случае выдавать Fmin, а в другом случае Fmax например. // Например, для :MEM:TABLE:FREQ:STAR;STOP;:MEM:TABLE:CONN;ADAP;ANAL;TIME;DATA ... существует всего одна // фунция MemTableFields(), зато она разбирает 11 различных FunctionID. // ============================================================================================== // ============================================================================================== // GPIB_Identification(...) // Назначенная комманда - *IDN? // Параметры комманды - отсутствуют // Возвращаемое значение - строка IDN // --------------------------------------------------------------------------------------------------------- // IDN string format: ",,,0" // - Planar (http://planar.chel.ru) or "Copper Mountain Technologies" // - Auto Calibration Module // - 0000-0000-0000 unsigned int GPIB_Identification ( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) // Обработчк *IDN? { BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; int MAX = udi->BulkRespondStatus.RespondBufferSize; size_t count; unsigned int err = 0; int i = 0+strlen(ACMClass->properties.manufacturerId); i+= 1+strlen(ACMClass->properties.modelName); i+= 1+strlen(ACMClass->properties.serialNumber); i+= 1+strlen(ACMClass->properties.firmwareId); if(!queue_getcount( pQParameters, &count )) err = ERROR_GPIB_INTERNAL; else if( count != 0) err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; else if( !request ) err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; else { if( MAX >= i ) { return snprintf( pBulkData_DeviceOut, MAX, "%s,%s,%s,%s", ACMClass->properties.manufacturerId, ACMClass->properties.modelName, ACMClass->properties.serialNumber, ACMClass->properties.firmwareId ); } else err = ERROR_GPIB_BUFFER_OVERFLOW; } // ------------------------------------------------------- if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } // ==================================================================================================== // GPIB_SystemVersion(...) - сервисная комманда, недокументирована // Назначенная комманда - SYSTem:VERSion? // Параметры комманды - любые // Возвращаемое значение - сообщение о номере версии парсера SCPI unsigned int GPIB_SystemVersion( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) // Обработчк system:info, system:info? { BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; int MAX = udi->BulkRespondStatus.RespondBufferSize; //-------------------------------------------------------- if( MAX >= 16) { s_memcpy( pBulkData_DeviceOut, "SCPI parser v1.3", 16 ); // ----- Copy respond data return (request==TRUE)?16:0; // -- respond length } else return 0; } // ============================================================================================== // GPIB_Clear(...) // Назначенная комманда - *CLS, очищает очередь ошибок и регисты STB и SRE // Параметры комманды - отсутствуют // Возвращаемое значение - отсутствует unsigned int GPIB_Clear( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) // Обработчк *CLS { QUEUE * pQueue = &udi->usbtmcGpib.StateMachine.qErrorQueue; size_t count = 0; unsigned int err = 0; //-------------------------------------------------------- if( !queue_getcount( pQParameters, &count ) ) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( request ) { err = ERROR_GPIB_COMMAND_ONLY_SUPPORT; } else { // Clear Event Status Register // Clear Status Register // Clear Error Queue udi->usbtmcGpib.StateMachine.STB = 0x00; udi->usbtmcGpib.StateMachine.ESR = 0x00; // - Error/Event Queue queue_clear( pQueue ); // Clear error queue GPIB_CLR_MAV(); // Clear Status Bit: message available GPIB_CLR_EAV(); // Clear Status Bit: event available } } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; // -- respond length } // ============================================================================================== // GPIB_Reset(...) // Назначенная комманда - *RST, сбрасывает состояние портов на LOAD/LOAD // Параметры комманды - отсутствуют // Возвращаемое значение - отсутствует unsigned int GPIB_Reset( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) // Обработчк *RST { QUEUE * pQueue = &udi->usbtmcGpib.StateMachine.qErrorQueue; size_t count = 0; unsigned int err = 0; //-------------------------------------------------------- if( !queue_getcount( pQParameters, &count ) ) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( request ) { err = ERROR_GPIB_COMMAND_ONLY_SUPPORT; } else { udi->EPBulkStatus.InPipe.dwLength = 0; // Clear bytes counters udi->EPBulkStatus.OutPipe.dwLength = 0; // - send counter udi->EPBulkStatus.shortpacket=FALSE; // - recv counter udi->EPBulkStatus.shortpacketsending=FALSE; // And clear also shortpacket signal flags //--------------- udi->BulkRespondStatus.INTransferInProgress=FALSE; // Clear signal variables udi->BulkRespondStatus.nBytesSent=0; // udi->BulkRespondStatus.INTransferTerminating=FALSE; // //--------------- //udi->usbtmcStatus.USBTMC_status = STATUS_SUCCESS; // usbtmcStatus do'nt depends from any bulk commands //udi->usbtmcStatus.USBTMC_InitiateRecieved = FALSE; // //--------------- queue_clear( pQueue ); // Clear error queue GPIB_CLR_EAV(); GPIB_CLR_MAV(); // No messages available //--------------- udi->BulkMessageStatus.bBulkHeaderRecieved=FALSE; // Clears Header flag udi->BulkMessageStatus.nBytesRecieved=0; // Clears bytes counter udi->BulkMessageStatus.OUTTransferInProgress=FALSE; // Clears signal variable //--------------- usb_lpc_cmd(CMD_EP_SELECT | USB_EP_PHY_ADDRESS_BULK_OUT ); // Clear EPOUT buffers usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); //--------------- usb_lpc_cmd(CMD_EP_SELECT | USB_EP_PHY_ADDRESS_BULK_IN ); // Clear EPIN buffers usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); usb_lpc_cmd(CMD_EP_CLEAR_BUFFER); //--------------- GPIB_DevDepInit( udi ); //--------------- --- переход в состояние, когда устройство ждет комманды } } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; // -- no bytes in respond } // ============================================================================================== // GPIB_SystemError(...) // Назначенная комманда - SYSTem:ERRor[:NEXT]? // Параметры комманды - отсутствуют // Возвращаемое значение - строка последней ошибки в очереди ошибок unsigned int GPIB_SystemError( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; //char * str = pQParameters->str; size_t count; unsigned int err = 0; int MAX = udi->BulkRespondStatus.RespondBufferSize; //-------------------------------------------------------- // request - если пришел запрос Enable? то request - 0x01 // Request and Command support if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request ) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { return usbtmc_GetErrorText( udi, pBulkData_DeviceOut, MAX ); } } } if( 0!= err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } // ============================================================================================== // GPIB_SystemErrorAll(...) // Назначенная комманда - SYSTem:ERRor:ALL? // Параметры комманды - отсутствуют // Возвращаемое значение - строка всех ошибок в очереди unsigned int GPIB_SystemErrorAll( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; int MAX = udi->BulkRespondStatus.RespondBufferSize; //-------------------------------------------------------- int a = 0; // Request ONLY if (request) { int c = 0; do{ if( a>0 ) { *(pBulkData_DeviceOut+a) = ','; a++; *(pBulkData_DeviceOut+a) = ' ';a++;} c = usbtmc_GetErrorText( udi, pBulkData_DeviceOut+a, MAX-a ); a+=c; }while( GPIB_GET_EAV() ); } return a; } // ============================================================================================== // GPIB_EventStatusEnable(...) // Назначенная комманда - ESE? // Параметры комманды - отсутствуют или значение регистра // Возвращаемое значение - значение регистра разрешения статусов событий (Event Status Enable Register) unsigned int GPIB_EventStatusEnable( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned size = 0, err = 0; unsigned int ESE; char NUMBER[11]={0,0,0,0,0,0,0,0,0,0,0x0A}; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != TernaryOperator(request, 0, 1)) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request && !queue_get( pQParameters, NUMBER, 10, &size )) { err = ERROR_GPIB_INVALID_PARAMETER; } else { if( !request && NUMBER[0] != eParTypeNR1 ) { err = ERROR_GPIB_INVALID_PARAMETER_TYPE; } else { if( !request && 0!=GPIB_ParseNumbers( NUMBER+1,USBTMC_PARSENUMBERS_TYPE_INT,1, (int*)&ESE )) { err = ERROR_GPIB_INVALID_PARAMETER; } else { if(request) { return snprintf(pBulkData_DeviceOut, MAX, "%d", udi->usbtmcGpib.StateMachine.ESE ); } else { udi->usbtmcGpib.StateMachine.ESE = ESE&0xff; USBTMC_StateMachine_Modified( &udi->usbtmcGpib.StateMachine ); } } } } } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } // ============================================================================================== // GPIB_OperationComplete(...) // Назначенная комманда - OPC? // Параметры комманды - отсутствуют // Возвращаемое значение - "1" unsigned int GPIB_OperationComplete( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned /*size = 0,*/ err = 0; // unsigned int ESE; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { GPIB_SET_OPC(); if(request) { return snprintf(pBulkData_DeviceOut, MAX, "%d", 1 ); } else { (void)0; } } } if( 0!=err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } // ============================================================================================== // GPIB_Wait(...) // Назначенная комманда - *WAI // Параметры комманды - отсутствуют // Возвращаемое значение - отсутствует unsigned int GPIB_Wait( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned /*size = 0,*/ err = 0; // unsigned int ESE; // int MAX = udi->BulkRespondStatus.RespondBufferSize; // BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if(!request) { (void)0; } else { (void)0; } } } if( 0!=err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } // ============================================================================================== // GPIB_Trigger(...) // Назначенная комманда - *TRG // Параметры комманды - отсутствуют // Возвращаемое значение - отсутствует unsigned int GPIB_Trigger( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned int err = 0; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request ) err = ERROR_GPIB_TRIGGER_IGNORED; else err = ERROR_GPIB_COMMAND_ONLY_SUPPORT; } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, "Trigger ignored", GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, "Trigger ignored", errClass_Autodetect ); } return 0; } // ============================================================================================== // GPIB_EventStatusRegister(...) // Назначенная комманда - *ESR? // Параметры комманды - отсутствуют // Возвращаемое значение - значение регистра статсуса событий unsigned int GPIB_EventStatusRegister( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned int err = 0; unsigned int rc = 0; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( !request) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { if( count != 0 ) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { rc = snprintf(pBulkData_DeviceOut, MAX, "%d", GPIB_GET_ESR() ); // IEEE 488.2, 11.5.1.2.2 Reading // The Standard Event Status Register is destructively read (that is, read and cleared) with the *ESR? common query, see 10.12. GPIB_CLR_ESR(); // 27/08/18 // --- replaced with: GPIB_SET_PWN() and GPIB_SET_OPC() ---- // udi->usbtmcGpib.StateMachine.ESR = 129; // USBTMC_StateMachine_Modified( &udi->usbtmcGpib.StateMachine ); // // // 27/08/18 // --- Note: in this implementation the PowerOn(7) and OperationComplete(0) bits are disabled // GPIB_SET_PWN(); // GPIB_SET_OPC(); } } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return rc; } // ============================================================================================== // GPIB_StatusRegister(...) // Назначенная комманда - *STB? // Параметры комманды - отсутствуют // Возвращаемое значение - значение регистра статсуса устройства unsigned int GPIB_StatusRegister( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned int err = 0; unsigned int rc = 0; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request ) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { rc = snprintf(pBulkData_DeviceOut, MAX, "%d", udi->usbtmcGpib.StateMachine.STB ); GPIB_CLR_RQS__(); // no state-machine state modify, clear ServiceRequestBit } } } if( 0!=err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return rc; } // ============================================================================================== // GPIB_StatusEnableRegister(...) // Назначенная комманда - *SRE? // Параметры комманды - отсутствуют или значение регистра // Возвращаемое значение - значение регистра разрешения статсуса устройства unsigned int GPIB_StatusEnableRegister( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count = 0; unsigned int err = 0; unsigned int rc = 0; unsigned int size = 0; BYTE SRE; char NUMBER[11]={0,0,0,0,0,0,0,0,0,0,0x0A}; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != ((request)?0:1) ) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request && !queue_get( pQParameters, NUMBER, 10, &size )) { err = ERROR_GPIB_INVALID_PARAMETER; } else { if( !request && NUMBER[0] != eParTypeNR1 ) { err = ERROR_GPIB_INVALID_PARAMETER_TYPE; } else { if( !request && 0!=GPIB_ParseNumbers( NUMBER+1,USBTMC_PARSENUMBERS_TYPE_INT,1, (int*)&SRE )) { err = ERROR_GPIB_INVALID_PARAMETER; } else { if(request) { rc = snprintf(pBulkData_DeviceOut, MAX, "%d", udi->usbtmcGpib.StateMachine.SRE ); } else { udi->usbtmcGpib.StateMachine.SRE = SRE&0xff; } } } } } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return rc; } // ============================================================================================== /* // GPIB_StatusOperationEvent(...) // Назначенная комманда - STATus:OPERation[:EVENt]? // Параметры комманды - отсутствуют // Возвращаемое значение - "0" unsigned int GPIB_StatusOperationEvent( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request равен 0x00 если комманда :STAT:OPER, а не :STAT:OPER? или :STAT:OPER:EVEN? // Request ONLY size_t count = 0; unsigned err = 0; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request ) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { return snprintf(pBulkData_DeviceOut, MAX, "%d", 0 ); } } } if( 0!= err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } */ /* // ============================================================================================== // GPIB_StatusOperationCondition(...) // Назначенная комманда - STATus:OPERation:CONDition? // Параметры комманды - отсутствуют // Возвращаемое значение - "0" unsigned int GPIB_StatusOperationCondition( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request - всегда 0x01 // Request ONLY return GPIB_StatusOperationEvent(udi, pQParameters, request); } */ /* // ============================================================================================== // GPIB_StatusOperationEnable(...) // Назначенная комманда - STATus:OPERation:ENABle? // Параметры комманды - отсутствуют // Возвращаемое значение - "0" unsigned int GPIB_StatusOperationEnable( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request - если пришел запрос Enable? то request - 0x01 // Request and Command support return GPIB_StatusQuestionableEnable(udi, pQParameters, request); } */ /* // ============================================================================================== // GPIB_StatusQuestionableEvent(...) // Назначенная комманда - STATus:QUEStionable[:EVENt]? // Параметры комманды - отсутствуют // Возвращаемое значение - "0" unsigned int GPIB_StatusQuestionableEvent( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request равен 0x00 если комманда :STAT:QUES, а не :STAT:QUES? или :STAT:QUES:EVEN? // Request ONLY return GPIB_StatusOperationEvent(udi, pQParameters, request); } */ /* // ============================================================================================== // GPIB_StatusQuestionableCondition(...) // Назначенная комманда - STATus:QUEStionable:CONDition? // Параметры комманды - отсутствуют // Возвращаемое значение - "0" unsigned int GPIB_StatusQuestionableCondition( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request равен 0x00 если комманда :STAT:QUES, а не :STAT:QUES? или :STAT:QUES:EVEN? // Request ONLY return GPIB_StatusOperationEvent(udi, pQParameters, request); } */ // ============================================================================================== // GPIB_StatusQuestionableEnable(...) // Назначенная комманда - STATus:QUEStionable:ENABle? // Параметры комманды - отсутствуют // Возвращаемое значение - "0" /* unsigned int GPIB_StatusQuestionableEnable( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request - если пришел запрос Enable? то request - 0x01 // Request and Command support size_t count = 0; unsigned err = 0; int MAX = udi->BulkRespondStatus.RespondBufferSize; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; // -------------------------------------------------- if(!queue_getcount( pQParameters, &count )) { err = ERROR_GPIB_INTERNAL; } else { if( count != ((request)?0:1) ) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request ) { (void)0; } else { return snprintf(pBulkData_DeviceOut, MAX, "%d", 0 ); } } } if( 0!=err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } */ /* // ============================================================================================== // GPIB_StatusPreset(...) // Назначенная комманда - *RST, STATus:PRESet // Параметры комманды - отсутствуют // Возвращаемое значение - отсутствует unsigned int GPIB_StatusPreset( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // request всегда 0x00 // Command support only return GPIB_Reset(udi, pQParameters, request); } */ // ============================================================================================== // GPIB_InterfaceSwitch(...) // Назначенная комманда - INTerface:SWitch? - переключение режима SCPI -> EZUSB // Параметры комманды - отсутствуют // Возвращаемое значение - строка результата операции unsigned int GPIB_InterfaceSwitch( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { unsigned int rc = 0; BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; int MAX = udi->BulkRespondStatus.RespondBufferSize; // ------------------------------------------------------- if( InterfaceSwitch( udi, USB_INTERFACE_CONT )==0x01 ) { if( request) { rc = snprintf( pBulkData_DeviceOut, MAX, "%s", "! The Interface will be switched at next connecting a USB cable!" ); } { SET_SYSTEM_CODE(CODE_REBOOT_ID, CODE_REBOOT ); // магическое число SET_SYSTEM_FLAG(FLAG_REBOOT); // флажок на перезагрузку DeviceBusy( 1 ); // device is busy by writing. } } else { if( request) { rc = snprintf( pBulkData_DeviceOut, MAX, "%s", "# There was SPI flash error. The Interface will not be switched!" ); } GPIB_RaiseStandartError( udi, ERROR_GPIB_INTERNAL, NULL, errClass_Autodetect ); } return rc; } // ============================================================================================== // GPIB_GetTemperature(...) // Назначенная комманда - MEASure:TEMPerature? // Параметры комманды - отсутствуют // Возвращаемое значение - значение температуры в градусах unsigned int GPIB_GetTemperature( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { BYTE * pBulkData_DeviceOut = (BYTE*)udi->usbtmcGpib.pData; int MAX = udi->BulkRespondStatus.RespondBufferSize; size_t count =0; int err = 0; // ------------------------------------------------- if(!queue_getcount( pQParameters, &count)) { err = ERROR_GPIB_INTERNAL; } else { if( count != 0 ) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !request ) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { return temperature_convert( pBulkData_DeviceOut, MAX, get_average_temperature() ); } } } if( 0 != err ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); } return 0; } // GPIB_SwitchCount(...) // Назначенная комманда - [SYSTem:]SWITch:COUNt? // Параметры комманды - НЕТ // Возвращаемое значение - общее количество состояний портов unsigned int GPIB_SwitchCount( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count; unsigned int err = 0; unsigned int rc = 0; //----------------------------------------------------------------------------------------- if(!queue_getcount(pQParameters, &count)) { err = ERROR_GPIB_INTERNAL; goto L_GPIB_SwitchList_EXIT; } if(!request) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_SwitchList_EXIT; } if( count != 0 ) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_SwitchList_EXIT; } { BYTE * pBuffer = (BYTE*)udi->usbtmcGpib.pData; int freeSpace = udi->BulkRespondStatus.RespondBufferSize; int32_t states = (int32_t)ACMClass->properties.allowedStatesCount; rc = GPIB_Integer2Str( states, pBuffer, freeSpace, Format_Int2Str_N ); } L_GPIB_SwitchList_EXIT: if( err != 0 ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_SwitchList(...) // Назначенная комманда - [SWITch:]LIST? // Параметры комманды - порт( A, B, AB ) // Возвращаемое значение - количество состояний порта unsigned int GPIB_SwitchList( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { size_t count; unsigned int err = 0; unsigned int rc = 0; //----------------------------------------------------------------------------------------- if(!queue_getcount(pQParameters, &count)) { err = ERROR_GPIB_INTERNAL; goto L_GPIB_SwitchList_EXIT; } if(!request) { err = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_SwitchList_EXIT; } if( count != 0 ) { err = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_SwitchList_EXIT; } { BYTE * pBuffer = (BYTE*)udi->usbtmcGpib.pData; int freeSpace = udi->BulkRespondStatus.RespondBufferSize; rc = ACMClass->methods.getKeyStateList( pBuffer, freeSpace ); } L_GPIB_SwitchList_EXIT: if( err != 0 ) { // 27/08/18 // GPIB_RaiseStandartError( udi, err, NULL, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, err, NULL, errClass_Autodetect ); rc = 0; } return rc; } //------------------------------------------------------------------------------ // __Util_CheckParamTableId: // Is used as a universal parameter checker for following functions: // * GPIB_MemoryTableTime // * GPIB_MemoryTableDate // etc. // All the functions listed above have the same "command prototype" - MEM:TABLE:CMD [FACTory|USER1|USER2|USER3] // This function checks the only parameter - characterization table id (factory/user1/user2/user3), // parses it and converts into the [eChrz_t]. // The function returns the error code. static unsigned int __Util_CheckParamTableId( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request, eChrz_t * pId ) { unsigned int errCode = 0; size_t rc = 0; char textBuffer[16]; eChrz_t id; // Characterization Table Id // check the requiest status if(!request ) { // error: command must be a request errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L__Util_CheckParamTableId_EXIT; } // Retrieve amount of parameters from the queue if( !queue_getcount(pQParameters, &rc) ) { // error: can't get parameters count errCode = ERROR_GPIB_INTERNAL; goto L__Util_CheckParamTableId_EXIT; } // Check parameters count else if( 1 < rc ) // only one OPTIONAL parameter allowed for this command { // error: wrong parameters count ( must be 0 or 1 ) errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L__Util_CheckParamTableId_EXIT; } if( 1 == rc ) // one parameter - table identifier (factory/user1/user2/user3) { // optional parameter is specified // retrieve the first parameter: table identifier (factory/user1/user2/user3) if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L__Util_CheckParamTableId_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L__Util_CheckParamTableId_EXIT; } // retrieve the parameter id = GPIB_GetChrzTableId( &textBuffer[1], rc - 1 ); if( eCh_MAX == id ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L__Util_CheckParamTableId_EXIT; } } else { // optional parameter is absent // table identifier omitted, "FACTory" is supposed id = eChFactory; } L__Util_CheckParamTableId_EXIT: if( 0 == errCode ) { if( NULL != pId ) { *pId = id; } } return errCode; } //------------------------------------------------------------------------------ // Descriptions for elements of [eChrz_t] static const char * const aChrzDesc[] = { "Factory characterization data", // eChFactory "USER1 characterization data", // eChUser1 "USER2 characterization data", // eChUser2 "USER3 characterization data", // eChUser3 NULL // eCh_MAX }; const char pcThermoDesc[] = "Thermocompensation data"; // Descriptions for elements of [ePortComb_t] static const char * const aPortComb[] = { "Port A" , // ePortComb_A "Port B" , // ePortComb_B "Port C" , // ePortComb_C "Port D" , // ePortComb_D "Thru AB" , // ePortComb_AB "Thru AC" , // ePortComb_AC "Thru AD" , // ePortComb_AD "Thru BC" , // ePortComb_BC "Thru BD" , // ePortComb_BD "Thru CD" , // ePortComb_CD "CHECK state" , // ePortComb_CHECK NULL // ePortComb_MAX }; /* // Descriptions for elements of [eChrz_t] static const char * aPortDesc[] = { "port A", // ePortId_A "port B", // ePortId_B "port C", // ePortId_C "port D", // ePortId_D NULL // eCh_MAX };*/ //------------------------------------------------------------------------------ // GPIB_MemoryTablePoints() // Prints amount of characterization points of the characterization table: factory or user size_t GPIB_MemoryTablePoints( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; size_t nPoints; if( 0 == errCode ) { nPoints = ACMClass->methods.xCharacterization.getPointsCount( id ); if( 0 != nPoints ) { rc = snprintf( (char*)pBuffer, freeSpace, "%d", nPoints ); if( 0 == rc || rc == freeSpace ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; } } else { errCode = ERROR_GPIB_DATA_NOT_FOUND; } } // L_GPIB_MemoryTablePoints_EXIT: if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } //------------------------------------------------------------------------------ // GPIB_MemoryTableDate() // Prints the characterization date size_t GPIB_MemoryTableDate( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getDate( id, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableTime() // Prints the characterization time size_t GPIB_MemoryTableTime( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getTime( id, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableTemp() // Prints the characterization temperature size_t GPIB_MemoryTableTemp( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); double temperature = 0; size_t rc = 0; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getChrzTemp( id, &temperature ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } else { rc = GPIB_Double2Str( temperature, (char*)pBuffer, freeSpace, Format_Double2Str_Ndot3 ); if( 0 == rc ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; } } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableFreqType() // Prints the type of the characterization frequency scale size_t GPIB_MemoryTableFreqType( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; if( 0 == errCode ) { eChrzScaleType_t scaleType; if( !ACMClass->methods.xCharacterization.getScaleType( id, &scaleType ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } else { if( eChScaleLinear == scaleType ) { rc = snprintf( (char*)pBuffer, freeSpace, "%s", "LIN" ); } else if( eChScaleSegment == scaleType ) { rc = snprintf( (char*)pBuffer, freeSpace, "%s", "SEGM" ); } else rc = 0; } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableFreqData() // Prints all the frequency points of the characterization frequency scale size_t GPIB_MemoryTableFreqData( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // 1 char * pBuffer = (char*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; // full amount of bytes returned size_t bytes = 0; // bytes returned unsigned int errCode = 0; // error identifier sEcalSegment_t segment; // scale segment data size_t iSeg = 0, nSeg = 0; // amount of segments size_t iPnt = 0, nPnt = 0; // amount of points eChrz_t id = eCh_MAX; // characterization id eChrzScaleType_t scaleType; // scale type // 2 // Check if the function context is saved and must be continued if( !udi->GPIBFunctionContext.bEnable ) { // no context found // check input parameters errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); if( 0 != errCode || eCh_MAX == id ) { goto L_GPIB_MemoryTableFreqData_EXIT; } // retrieve the scale type if( !ACMClass->methods.xCharacterization.getScaleType( id, &scaleType ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqData_EXIT; } if( eChScaleLinear == scaleType ) { // Linear scale nSeg = 1; iSeg = 0; iPnt = 0; } else { // Segment scale // read amount of segments nSeg = ACMClass->methods.xCharacterization.getScaleSegment( id, NULL, 0 ); iSeg = 0; iPnt = 0; if( 0 == nSeg ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqData_EXIT; } } } // 3 else { // load previous context /* */ if( queue_get( &udi->GPIBFunctionContext.Context, (char*)&id, sizeof(id), &bytes ) // load memory segment id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&nSeg , sizeof(nSeg), &bytes ) // load amount of segments && queue_get( &udi->GPIBFunctionContext.Context, (char*)&iSeg , sizeof(iSeg), &bytes ) // load segment index && queue_get( &udi->GPIBFunctionContext.Context, (char*)&nPnt , sizeof(nPnt), &bytes ) // load amount of points && queue_get( &udi->GPIBFunctionContext.Context, (char*)&iPnt , sizeof(iPnt), &bytes ) // load point index && queue_get( &udi->GPIBFunctionContext.Context, (char*)&scaleType , sizeof(scaleType), &bytes ) // load the scale type ) { // OK } else { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableFreqData_EXIT; } } rc = 0; // 4 // try to print frequencies list for( (void)iSeg; iSeg < nSeg; ++iSeg ) // for each segment { // For segment scale: load the segment data if( eChScaleSegment == scaleType ) { // retrieve the segment information if( 1 != ACMClass->methods.xCharacterization.getScaleSegment( id, &segment, iSeg ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqData_EXIT; } // load the points count nPnt = segment.Points; } if( eChScaleLinear == scaleType ) { // load the points count nPnt = ACMClass->methods.xCharacterization.getPointsCount( id ); // load start and stop frequencies if( !ACMClass->methods.xCharacterization.getStartFreq( id, &segment.Fstart ) || !ACMClass->methods.xCharacterization.getStopFreq( id, &segment.Fstop ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqData_EXIT; } // store @nPnt into the @segment to unify the access segment.Points = nPnt; } if( 0 == nPnt ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqData_EXIT; } for( (void)iPnt; iPnt < nPnt; ++iPnt ) // for each point { // One point has the following format: // , // where @i is the point number, // @nPnt - amount of points. // Total amount of numbers to be print: nPnt // One number has 16 symbols length plus 2 (comma and space) // So, 18 characters required to print one point. // To prevent overflowing by snprintf() with printing null-term, // it is required at lease 20 characters free if( freeSpace >= 20 ) { double dbl_freq_point = 0.0; if( segment.Points > 1 ) { // e.g. segment #1, (1.0e+5;2.0e+5,11 points) // START_FREQ=100000; STOP_FREQ=200000; N=11 // 100000, 110000, 120000, 130000, 140000 } 5 points // 150000, 160000, 170000, 180000, 190000, 20000 } 6 points // Total: 11 points on (1.0e+5;2.0e+5) // So, STEP is (STOP_FREQ - START_FREQ)/(N-1) = 10000 #define SegmentFreqStep( seg ) ((seg.Fstop - seg.Fstart) / (seg.Points - 1)) // calculate current frequency point (MAGNITUDE) // print the frequency point dbl_freq_point = segment.Fstart + SegmentFreqStep( segment ) * iPnt; /* bytes = GPIB_Double2Str( segment.Fstart + SegmentFreqStep( segment ) * iPnt, pBuffer, freeSpace, Format_Double2Str_Sci );*/ } else { dbl_freq_point = segment.Fstart; /* bytes = GPIB_Double2Str( segment.Fstart, pBuffer, freeSpace, Format_Double2Str_Sci );*/ } { // fix: 05/09/18 // round the value to [Hz] dbl_freq_point = round( dbl_freq_point ); // print rounded value bytes = GPIB_Double2Str( dbl_freq_point, pBuffer, freeSpace, Format_Double2Str_Sci ); } pBuffer += bytes; freeSpace -= bytes; rc += bytes; // print the delimeter bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; } else { // -------------------------------------------------------------------------- // Save context usbtmc_create_function_context( udi, (void*)GPIB_MemoryTableFreqData ); if( !queue_add( &udi->GPIBFunctionContext.Context, (char*)&id, sizeof(id) ) // Save memory segment id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&nSeg , sizeof(nSeg) ) // Save amount of segments || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&iSeg , sizeof(iSeg) ) // Save segment index || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&nPnt , sizeof(nPnt) ) // Save amount of points || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&iPnt , sizeof(iPnt) ) // Save point index || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&scaleType , sizeof(scaleType) ) // Save the scale type ) { udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableFreqData_EXIT; } udi->BulkRespondStatus.bIsLastTransfer = FALSE; errCode = 0; // -------------------------------------------------------------------------- goto L_GPIB_MemoryTableFreqData_EXIT; } /*for( const char * p = __Buffer; p != pBuffer; ++p ) { if( *p == '\0' ) { asm( "bkpt #0" ); } }*/ } // For the last point of last segment if( iSeg >= nSeg-1 ) if( iPnt >= nPnt ) { if( rc > 2 ) rc -= 2; // cut off the last comma separator and space udi->BulkRespondStatus.bIsLastTransfer = TRUE; } iPnt = 0; } // 5 L_GPIB_MemoryTableFreqData_EXIT: if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } udi->BulkRespondStatus.bIsLastTransfer = TRUE; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableFreqSegmData() // Prints the scale segments parameters of the characterization frequency scale size_t GPIB_MemoryTableFreqSegmData( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // 1 char * pBuffer = (char*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; // full amount of bytes returned size_t bytes = 0; // bytes returned size_t i, n = 0; // amount of segments eChrz_t id = eCh_MAX; // characterization id unsigned int errCode = 0; // error identifier sEcalSegment_t segment; // scale segment data eChrzScaleType_t scaleType; // scale type // 2 // Check if the function context is saved and must be continued if( !udi->GPIBFunctionContext.bEnable ) { // no context found // check input parameters errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); if( 0 != errCode || eCh_MAX == id ) { goto L_GPIB_MemoryTableFreqSegmData_EXIT; } // retrieve the scale type // check the conditions: the scale must be a Segment Type Scale if( !ACMClass->methods.xCharacterization.getScaleType( id, &scaleType ) || eChScaleSegment != scaleType) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqSegmData_EXIT; } // read amount of segments n = ACMClass->methods.xCharacterization.getScaleSegment( id, NULL, 0 ); i = 0; if( 0 == n ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqSegmData_EXIT; } // print amount of segements bytes = snprintf( pBuffer, freeSpace, "%d%s", n, ",\n" /* ",\r\n" */); if( 0 == bytes || bytes == freeSpace ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; goto L_GPIB_MemoryTableFreqSegmData_EXIT; } else { rc += bytes; freeSpace -= bytes; pBuffer += bytes; } } // 3 else { // load previous context /* */ if( queue_get( &udi->GPIBFunctionContext.Context, (char*)&id, sizeof(id),&bytes ) // load memory segment id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&n , sizeof(n), &bytes ) // load amount of segments && queue_get( &udi->GPIBFunctionContext.Context, (char*)&i , sizeof(i), &bytes ) // load segment number ) { // OK } else { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableFreqSegmData_EXIT; } } // 4 // try to print the segment list for( /*@i is loaded from context*/; i < n; ++i ) { // segment data format: // , , // e.g. // 1.0000000000e+5, 2.0000000000e+6, 13 // Minimum free space required to one segment: 36 + amount of chars in // Let it be 4. // Whole number of free bytes in the buffer: 40 // To prevent overflowing by snprintf() with printing null-term, // it is required at lease 44 characters free if( freeSpace >= 44 ) { if( 1 == ACMClass->methods.xCharacterization.getScaleSegment( id, &segment, i ) ) { // print the segment data bytes = GPIB_Double2Str( segment.Fstart, pBuffer, freeSpace, Format_Double2Str_Sci ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; bytes = GPIB_Double2Str( segment.Fstop, pBuffer, freeSpace, Format_Double2Str_Sci ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; bytes = snprintf( pBuffer, freeSpace, "%d%s", segment.Points, "\n"/*"\r\n"*/ ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; } else { errCode = ERROR_GPIB_DATA_NOT_FOUND; goto L_GPIB_MemoryTableFreqSegmData_EXIT; } } else { // -------------------------------------------------------------------------- // Save context usbtmc_create_function_context( udi, (void*)GPIB_MemoryTableFreqSegmData ); if( !queue_add( &udi->GPIBFunctionContext.Context, (char*)&id, sizeof(id) ) // Save memory segment id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&n , sizeof(n) ) // Save amount of segments || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&i , sizeof(i) ) // Save segment number ) { udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableFreqSegmData_EXIT; } udi->BulkRespondStatus.bIsLastTransfer = FALSE; errCode = 0; // -------------------------------------------------------------------------- break; } } // 5 L_GPIB_MemoryTableFreqSegmData_EXIT: if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } udi->BulkRespondStatus.bIsLastTransfer = TRUE; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableFreqStart() // Prints the start frequency of the characterization frequency scale size_t GPIB_MemoryTableFreqStart( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; double startFreq = 0.0f; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getStartFreq( id, &startFreq ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } else { rc = GPIB_Double2Str( startFreq, (char*)pBuffer, freeSpace, Format_Double2Str_Sci ); } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemoryTableFreqStop() // Prints the stop frequency of the characterization frequency scale size_t GPIB_MemoryTableFreqStop( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; double stopFreq = 0.0f; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getStopFreq( id, &stopFreq ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } else { rc = GPIB_Double2Str( stopFreq, (char*)pBuffer, freeSpace, Format_Double2Str_Sci ); } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTableAdapter() // size_t GPIB_MemoryTableAdapter( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; size_t nParams = 0; unsigned int errCode = 0; eChrz_t id = eCh_MAX; // by default ePortId_t pid; // Port ID char textBuffer[16]; // check the requiest status if(!request ) { // error: command must be a request errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_MemoryTableAdapter_EXIT; } // Retrieve amount of parameters from the queue if( !queue_getcount(pQParameters, &nParams) ) { // error: can't get parameters count errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableAdapter_EXIT; } // Check parameters count else if( 1 != nParams && 2 != nParams ) // this command must have 1 or 2 parameters { // error: wrong parameters count ( must be 1 ) errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_MemoryTableAdapter_EXIT; } // first parameter - port identifier (A/B/C/D) { // retrieve the first parameter: port identifier (A/B/C/D) if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableAdapter_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemoryTableAdapter_EXIT; } // retrieve the parameter pid = GPIB_GetPortId( &textBuffer[1], rc - 1 ); if( ePortId_MAX == pid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableAdapter_EXIT; } if( 2 == nParams ) { // retrieve second parameter: table identifier (factory/user1/user2/user3) if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableAdapter_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemoryTableAdapter_EXIT; } // retrieve the parameter id = GPIB_GetChrzTableId( &textBuffer[1], rc - 1 ); if( eCh_MAX == id ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableAdapter_EXIT; } } else { id = eChFactory; } } if( !ACMClass->methods.xCharacterization.getAdapterDesc( id, pid, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } L_GPIB_MemoryTableAdapter_EXIT: if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return 0; } // GPIB_MemTableConnector() // size_t GPIB_MemoryTableConnector( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; unsigned int errCode = 0; ePortId_t pid; // Port ID char textBuffer[16]; // check the requiest status if(!request ) { // error: command must be a request errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_MemoryTableAdapter_EXIT; } // Retrieve amount of parameters from the queue if( !queue_getcount(pQParameters, &rc) ) { // error: can't get parameters count errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableAdapter_EXIT; } // Check parameters count else if( 1 != rc ) // this command must have only one parameter { // error: wrong parameters count ( must be 1 ) errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_MemoryTableAdapter_EXIT; } // parameter - port identifier (A/B/C/D) { // retrieve the first parameter: port identifier (A/B/C/D) if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableAdapter_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemoryTableAdapter_EXIT; } // retrieve the parameter pid = GPIB_GetPortId( &textBuffer[1], rc - 1 ); if( ePortId_MAX == pid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableAdapter_EXIT; } } if( !ACMClass->methods.xCharacterization.getConnectorType( pid, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } L_GPIB_MemoryTableAdapter_EXIT: if( 0 != errCode ) { // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, aChrzDesc[ (size_t)eChFactory ], GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, aChrzDesc[ (size_t)eChFactory ], errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTableAnalyzer() // Prints the analyzer model of the characterization size_t GPIB_MemoryTableAnalyzer( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getAnalyzer( id, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTablePlace() // Prints the location where the characterization has been created size_t GPIB_MemoryTablePlace( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getPlace( id, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTableOperator() // Prints the operator's name who created the characterization size_t GPIB_MemoryTableOperator( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; eChrz_t id = eCh_MAX; unsigned int errCode = __Util_CheckParamTableId( udi, pQParameters, request, &id ); size_t rc = 0; if( 0 == errCode ) { if( !ACMClass->methods.xCharacterization.getOperator( id, (char*)pBuffer, freeSpace, &rc ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; } } if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != id ) { pDescription = aChrzDesc[ (size_t)id ]; } // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // ============================================================================================== // volatile size_t debug_call = 0; // GPIB_MemoryTableData() // MEM:TABLE:DATA? , , [MEMORY_SECTOR] // Prints the contents of the characterization table depending on the following parameters: // - port combination (A, B, or CD, or CHECK, etc) // - port state (Load, Short, Thru11=S11, Check12=S12, etc.) // - memory sector (Factory/USER1/USER2/USER3), OPTIONAL, by default = FACTORY size_t GPIB_MemoryTableData( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // 1 char * pBuffer = (char*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; // full amount of bytes returned unsigned int errCode = 0; // error identifier sACMGetPoints_t tableContext; // table context to store the data between calls eChrz_t msid = eCh_MAX; // characterization id, = memory sector id ePortComb_t pcid = ePortComb_UNDEFINED; // port combination id ePortStateId_t psid = ePortStateId_UNDEFINED; // port state id // debug_call++; // 2 // Check if the function context is saved and must be continued if( !udi->GPIBFunctionContext.bEnable ) { // no context found size_t nParam = 0; // amount of parameters if( !request ) { // error: request only supported errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_MemoryTableData_EXIT; } // Retrieve amount of parameters from the queue if( !queue_getcount(pQParameters, &nParam) ) { // error: can't get parameters count errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableData_EXIT; } // Check parameters count else if( 2 != nParam && 3 != nParam ) // this command must have 2 or 3 parameters { // error: wrong parameters count ( must be 2 or 3 ) errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_MemoryTableData_EXIT; } // parameter #1 - port combination (A/B/C/D/AB/AC/AD/BC/BD/CD/CHECK) { char textBuffer[16]; // retrieve the first parameter: port combination if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemoryTableData_EXIT; } // retrieve the parameter pcid = GPIB_GetPortComb( &textBuffer[1], rc - 1 ); if( ePortComb_UNDEFINED == pcid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } } // parameter #2 - port state (SHORT, OPEN, LOAD, LOAD2, OPEN2, S11, S12, ..., S44) { char textBuffer[16]; // retrieve the first parameter: port state if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemoryTableData_EXIT; } // retrieve the parameter psid = GPIB_GetPortStateId( &textBuffer[1], rc - 1 ); if( ePortStateId_UNDEFINED == psid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } } // parameter #3 - memory sector (FACTORY/USER1/USER2/USER3) if( 3 == nParam ) // if third parameter is not omitted { char textBuffer[16]; // retrieve the first parameter: memory sector if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemoryTableData_EXIT; } // retrieve the parameter msid = GPIB_GetChrzTableId( &textBuffer[1], rc - 1 ); if( eCh_MAX == msid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } } else { msid = eChFactory; } // Validate given parameters: port state and port combination if( ! ACMClass->methods.checkTableParams( pcid, psid ) ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemoryTableData_EXIT; } // initialize the table context @.out just for order tableContext.out.max = 0; // don't care tableContext.out.min = 0; // don't care tableContext.out.TableAddress = 0; // don't care tableContext.out.nPoints = 0; // don't care // initialize @.in to make the @.getPoints() call to load // the table header. // - set @.nCount to 0 to load the table header tableContext.in.nCount = 0; // must be 0 tableContext.in.nStartPoint = 0; // don't care tableContext.in.pDataArray = dbPointsBuffer; // must be initialized to pass internal checks // load table header and validate it // During this call the @tableContext.out will be initialized if( 1 != ACMClass->methods.xCharacterization.getPoints( msid, // memory sector pcid, // port combination psid, // port state &tableContext ) ) { errCode = ERROR_GPIB_DATA_NOT_FOUND; // failed switch( tableContext.svc.errCode ) { case ERR_ACMGETPOINTS_INVAL : errCode = ERROR_GPIB_INVALID_PARAMETER; break; case ERR_ACMGETPOINTS_INVTBL: errCode = ERROR_GPIB_ARRAY_CORRUPTED; break; case ERR_ACMGETPOINTS_INVHDR: errCode = ERROR_GPIB_DATA_NOT_FOUND; break; case ERR_ACMGETPOINTS_IO : errCode = ERROR_GPIB_INTERNAL; break; } goto L_GPIB_MemoryTableData_EXIT; } // ok, now @tableContext is initialized // Let's initialize the rest variables tableContext.in.nStartPoint = 0; // starting point = 0 tableContext.in.pDataArray = dbPointsBuffer; // initialize the temporary buffer tableContext.in.nCount = 0; // zero yet, see below } // 3 else { // load previous context size_t bytes; if( queue_get( &udi->GPIBFunctionContext.Context, (char*)&msid , sizeof(msid), &bytes ) // load memory segment id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&pcid , sizeof(pcid), &bytes ) // load port combination id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&psid , sizeof(psid), &bytes ) // load port state id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&tableContext , sizeof(tableContext), &bytes ) // load table context ) { // OK // Note: // @tableContext.out.nPoints is remembered, amount of points // @tableContext.in.nStartPoint is remembered, starting point (the next after the lastest processed) } else { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableData_EXIT; } } rc = 0; // 4 { size_t nPoints = tableContext.out.nPoints; // amount of points in the table size_t nStart = tableContext.in.nStartPoint; // starting point // do until all the points are processed while( nStart < nPoints ) { // specify the number of points to retrieve: @tableContext.in.nCount // Note: @tableContext.out.nPoints and @tableContext.in.nStartPoint are // already specified or remembered size_t nStepPoints = (nPoints - nStart); // check the points number for the limit if( nStepPoints >= DBPOINTS_BUFFER_NUM ) { tableContext.in.nCount = DBPOINTS_BUFFER_NUM; // (nPoints - nStart) } else { // not greater than it is required tableContext.in.nCount = nStepPoints; } // retrieve the points from the memory if( tableContext.in.nCount != ACMClass->methods.xCharacterization.getPoints( msid, // memory sector pcid, // port combination psid, // port state &tableContext ) ) { // error // Strange... The table is already validated. Maybe, it is I/O error issue. udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; // failed switch( tableContext.svc.errCode ) { case ERR_ACMGETPOINTS_INVAL : errCode = ERROR_GPIB_INVALID_PARAMETER; break; case ERR_ACMGETPOINTS_INVTBL: errCode = ERROR_GPIB_ARRAY_CORRUPTED; break; case ERR_ACMGETPOINTS_INVHDR: errCode = ERROR_GPIB_DATA_NOT_FOUND; break; case ERR_ACMGETPOINTS_IO : errCode = ERROR_GPIB_INTERNAL; break; } goto L_GPIB_MemoryTableData_EXIT; } // Ok, the double-points are loaded... // Let's convert it! // @iPoint - just counts amount of converted points at this step. for( size_t iPoint = 0; iPoint < tableContext.in.nCount; ++iPoint ) { // the point format is: // ,, // where and is a number in scientific format // with 10 fractional digits. Let's leave 2 digits for the exponent, // and one number takes 16 characters, plus the separator and the space. // So one point takes (16+2)*2 = 36 characters. To be in save we will // suppose the one point takes 48 characters. // e.g. // 1.0000000000e+5, 1.0000000000e+0, if( freeSpace >= 48 ) { size_t bytes = 0; // @dbPointsBuffer[iPoint] is one of points retrieved at this step. // Convert a magnitude bytes = GPIB_Double2Str( dbPointsBuffer[ iPoint ].magn, pBuffer, freeSpace, Format_Double2Str_Sci ); if( 0 == bytes ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; goto L_GPIB_MemoryTableData_EXIT; } pBuffer += bytes; freeSpace -= bytes; rc += bytes; // print the delimeter bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; // Convert a phase bytes = GPIB_Double2Str( dbPointsBuffer[ iPoint ].phase, pBuffer, freeSpace, Format_Double2Str_Sci ); if( 0 == bytes ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; goto L_GPIB_MemoryTableData_EXIT; } pBuffer += bytes; freeSpace -= bytes; rc += bytes; // print the delimeter bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; // move to the next point in the table nStart++; } else { // not enough free space in the text buffer (void)tableContext.out.nPoints; tableContext.in.nStartPoint = nStart; // modify the starting point for the next call // -------------------------------------------------------------------------- // Save context usbtmc_create_function_context( udi, (void*)GPIB_MemoryTableData ); if( !queue_add( &udi->GPIBFunctionContext.Context, (char*)&msid , sizeof(msid) ) // Save memory segment id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&pcid , sizeof(pcid) ) // Save port combination id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&psid , sizeof(psid) ) // Save port state id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&tableContext , sizeof(tableContext) ) // Save table context ) { udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemoryTableData_EXIT; } udi->BulkRespondStatus.bIsLastTransfer = FALSE; errCode = 0; // -------------------------------------------------------------------------- goto L_GPIB_MemoryTableData_EXIT; } } // for tableContext.in.nStartPoint = nStart; // modify the starting point } // while( nStart < nPoints ) // Ok, all the points are converted here due to // otherwise, the program jumps to L_GPIB_MemoryTableData_EXIT label // after saving context. if( rc > 2 ) { // cut off the last space and comma rc -= 2; } udi->BulkRespondStatus.bIsLastTransfer = TRUE; } // 5 L_GPIB_MemoryTableData_EXIT: if( 0 != errCode ) { const char * pDescription = NULL; if( eCh_MAX != msid ) { pDescription = aChrzDesc[ (size_t)msid ]; } if( ERROR_GPIB_ARRAY_CORRUPTED == errCode && ePortComb_MAX != pcid ) { pDescription = aPortComb[ ((pcid - ePortComb_MIN)%ePortComb_MAX) ]; } udi->BulkRespondStatus.bIsLastTransfer = TRUE; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // ============================================================================================== // ============================================================================================== // GPIB_SwitchState(...) // Назначенная комманда - [SYSTem:]SWITch:STATe, [SYSTem:]SWITch:STATe? // Параметры комманды - состояние (SALL, OALL, THBD, ...) или отстутствует (запрос) // Возвращаемое значение - строка имени состояния порта и количество байт unsigned int GPIB_SwitchState( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { union { char stateRaw[ 16 ]; struct { BYTE stateNameParamType; char stateName[ 15 ]; }; } = { .stateRaw = {0} }; unsigned int errCode = 0; size_t stateNameLength = 0; size_t count = 0; BYTE * pBuffer = NULL; int nFreeSpace = 0; size_t bytes = 0; eACMKeyState_t keyState; // ------------------------------------------------- pBuffer = (BYTE*)udi->usbtmcGpib.pData; nFreeSpace = udi->BulkRespondStatus.RespondBufferSize; // ------------------------------------------------- if(!queue_getcount(pQParameters, &count)) { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_SwitchState_EXIT; } if( TernaryOperator(request,0,1) != count ) { errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_SwitchState_EXIT; } if( !request ) // == (count==1) { if( !queue_get( pQParameters, stateRaw, sizeof(stateRaw), &stateNameLength ) ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_SwitchState_EXIT; } if( stateNameLength < 2 || eParTypeChar != stateNameParamType ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_SwitchState_EXIT; } stateNameLength--; // decrease parameter length by 1 byte - 1 byte for parameter type keyState = ACMClass->methods.getKeyStateByName( stateName, stateNameLength ); if( eKeyState_Undefined == keyState ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_SwitchState_EXIT; } // ------------------------------------------------- if( ! ACMClass->methods.checkStateAvailable( keyState ) ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_SwitchState_EXIT; } /* bytes = ACMClass->methods.getKeyStateName( keyState, pBuffer, nFreeSpace ); if( (0 == bytes) && ( bytes > nFreeSpace ) ) { err = ERROR_GPIB_INTERNAL; goto L_GPIB_SwitchState_EXIT; } */ if( ! ACMClass->methods.setKeyStateCommon( keyState ) ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_SwitchState_EXIT; } } else { keyState = ACMClass->methods.getKeyStateCommon(); bytes = ACMClass->methods.getKeyStateName( keyState, pBuffer, nFreeSpace ); if( (0 == bytes) && ( bytes > nFreeSpace ) ) { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_SwitchState_EXIT; } } // ------------------------------------------------- L_GPIB_SwitchState_EXIT: if( 0 != errCode ) { // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, NULL, errClass_Autodetect ); bytes = 0; } return bytes; } void GPIB_DevDepInit( USB_DEVICE_INFO * udi ) { //InitKeyState(); //SETKEY_LOADB(udi->CommandStatus.key_stat); //SETKEY_LOADA(udi->CommandStatus.key_stat); //usbapp_SET_KEY_STAT(&udi->CommandStatus); /* ACMClass is uninitialized yet! */ } // GPIB_MemTableTherCorrFreqStart() // Prints the start frequency of the thermocompensation data array size_t GPIB_MemTableTherCorrFreqStart( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; double startFreq = 0.0f; unsigned int errCode = 0; size_t count = 0; if( !request ) { errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { if( !queue_getcount( pQParameters, &count) ) { errCode = ERROR_GPIB_INTERNAL; } else { if( 0 != count ) { errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !ACMClass->methods.xThermo.getStartFreq( &startFreq ) ) { errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; } else { rc = GPIB_Double2Str( startFreq, (char*)pBuffer, freeSpace, Format_Double2Str_Sci ); } } } } if( 0 != errCode ) { const char * pDescription = pcThermoDesc; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTableTherCorrFreqStop() // Prints the stop frequency of the thermocompensation data array size_t GPIB_MemTableTherCorrFreqStop( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; double stopFreq = 0.0f; unsigned int errCode = 0; size_t count = 0; if( !request ) { errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { if( !queue_getcount( pQParameters, &count) ) { errCode = ERROR_GPIB_INTERNAL; } else { if( 0 != count ) { errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { if( !ACMClass->methods.xThermo.getStopFreq( &stopFreq ) ) { errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; } else { rc = GPIB_Double2Str( stopFreq, (char*)pBuffer, freeSpace, Format_Double2Str_Sci ); } } } } if( 0 != errCode ) { const char * pDescription = pcThermoDesc; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } size_t GPIB_MemTableTherCorrPoints( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { uint8_t * pBuffer = (uint8_t*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; size_t nPoints = 0; unsigned int errCode = 0; size_t count = 0; if( !request ) { errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; } else { if( !queue_getcount( pQParameters, &count) ) { errCode = ERROR_GPIB_INTERNAL; } else { if( 0 != count ) { errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; } else { nPoints = ACMClass->methods.xThermo.getPointsCount(); if( 0 == nPoints ) { errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; } else { rc = snprintf( (char*)pBuffer, freeSpace, "%d", nPoints ); } } } } if( 0 != errCode ) { const char * pDescription = pcThermoDesc; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTableTherCorrMagniture() // MEM:TABLE:THER:CORR:MAGN? , // Prints the contents of the characterization table depending on the following parameters: // - port combination (A, B, or CD, or CHECK, etc) // - port state (Load, Short, Thru11=S11, Check12=S12, etc.) size_t GPIB_MemTableTherCorrMagniture( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // 1 char * pBuffer = (char*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; // full amount of bytes returned unsigned int errCode = 0; // error identifier sACMGetPoints_t tableContext; // table context to store the data between calls ePortComb_t pcid = ePortComb_UNDEFINED; // port combination id ePortStateId_t psid = ePortStateId_UNDEFINED; // port state id // 2 // Check if the function context is saved and must be continued if( !udi->GPIBFunctionContext.bEnable ) { // no context found size_t nParam = 0; // amount of parameters if( !request ) { errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // Retrieve amount of parameters from the queue if( !queue_getcount(pQParameters, &nParam) ) { // error: can't get parameters count errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // Check parameters count else if( 2 != nParam ) // this command must have 2 parameters { // error: wrong parameters count ( must be 2 ) errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // parameter #1 - port combination (A/B/C/D/AB/AC/AD/BC/BD/CD/CHECK) { char textBuffer[16]; // retrieve the first parameter: port combination if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // retrieve the parameter pcid = GPIB_GetPortComb( &textBuffer[1], rc - 1 ); if( ePortComb_UNDEFINED == pcid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } } // parameter #2 - port state (SHORT, OPEN, LOAD, LOAD2, OPEN2, S11, S12, ..., S44) { char textBuffer[16]; // retrieve the first parameter: port state if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // retrieve the parameter psid = GPIB_GetPortStateId( &textBuffer[1], rc - 1 ); if( ePortStateId_UNDEFINED == psid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } } // Validate given parameters: port state and port combination if( ! ACMClass->methods.checkTableParams( pcid, psid ) ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // initialize the table context @.out just for order tableContext.out.max = 0; // don't care tableContext.out.min = 0; // don't care tableContext.out.TableAddress = 0; // don't care tableContext.out.nPoints = 0; // don't care // initialize @.in to make the @.getPoints() call to load // the table header. // - set @.nCount to 0 to load the table header tableContext.in.nCount = 0; // must be 0 tableContext.in.nStartPoint = 0; // don't care tableContext.in.pDataArray = dbPointsBuffer; // must be initialized to pass internal checks // load table header and validate it // During this call the @tableContext.out will be initialized if( 1 != ACMClass->methods.xThermo.getPointsMagn( pcid, // port combination psid, // port state &tableContext ) ) { // failed errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; switch( tableContext.svc.errCode ) { case ERR_ACMGETPOINTS_INVAL : errCode = ERROR_GPIB_INVALID_PARAMETER; break; case ERR_ACMGETPOINTS_INVTBL: errCode = ERROR_GPIB_ARRAY_CORRUPTED; break; case ERR_ACMGETPOINTS_INVHDR: errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; break; case ERR_ACMGETPOINTS_IO : errCode = ERROR_GPIB_INTERNAL; break; } goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // ok, now @tableContext is initialized // Let's initialize the rest variables tableContext.in.nStartPoint = 0; // starting point = 0 tableContext.in.pDataArray = dbPointsBuffer; // initialize the temporary buffer tableContext.in.nCount = 0; // zero yet, see below } // 3 else { // load previous context size_t bytes; if( queue_get( &udi->GPIBFunctionContext.Context, (char*)&pcid , sizeof(pcid), &bytes ) // load port combination id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&psid , sizeof(psid), &bytes ) // load port state id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&tableContext , sizeof(tableContext), &bytes ) // load table context ) { // OK // Note: // @tableContext.out.nPoints is remembered, amount of points // @tableContext.in.nStartPoint is remembered, starting point (the next after the lastest processed) } else { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } } rc = 0; // 4 { size_t nPoints = tableContext.out.nPoints; // amount of points in the table size_t nStart = tableContext.in.nStartPoint; // starting point // do until all the points are processed while( nStart < nPoints ) { // specify the number of points to retrieve: @tableContext.in.nCount // Note: @tableContext.out.nPoints and @tableContext.in.nStartPoint are // already specified or remembered size_t nStepPoints = (nPoints - nStart); // check the points number for the limit if( nStepPoints >= DBPOINTS_BUFFER_NUM ) { tableContext.in.nCount = DBPOINTS_BUFFER_NUM; // (nPoints - nStart) } else { // not greater than it is required tableContext.in.nCount = nStepPoints; } // retrieve the points from the memory if( tableContext.in.nCount != ACMClass->methods.xThermo.getPointsMagn( pcid, // port combination psid, // port state &tableContext ) ) { // error // Strange... The table is already validated. Maybe, it is I/O error issue. udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; switch( tableContext.svc.errCode ) { case ERR_ACMGETPOINTS_INVAL : errCode = ERROR_GPIB_INVALID_PARAMETER; break; case ERR_ACMGETPOINTS_INVTBL: errCode = ERROR_GPIB_ARRAY_CORRUPTED; break; case ERR_ACMGETPOINTS_INVHDR: errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; break; case ERR_ACMGETPOINTS_IO : errCode = ERROR_GPIB_INTERNAL; break; } goto L_GPIB_MemTableTherCorrMagniture_EXIT; } // Ok, the double-points are loaded... // Let's convert it! // @iPoint - just counts amount of converted points at this step. for( size_t iPoint = 0; iPoint < tableContext.in.nCount; ++iPoint ) { // the point format is: // , // where is a number in scientific format // with 10 fractional digits. Let's leave 2 digits for the exponent, // and one number takes 16 characters, plus the separator and the space. // So one point takes (16+2) = 18 characters. To be in save we will // suppose the one point takes 24 characters. // e.g. // 1.0000000000e+5, if( freeSpace >= 24 ) { size_t bytes = 0; // @dbPointsBuffer[iPoint] is one of points retrieved at this step. // Convert a magnitude bytes = GPIB_Double2Str( dbPointsBuffer[ iPoint ].magn, pBuffer, freeSpace, Format_Double2Str_Sci ); if( 0 == bytes ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } pBuffer += bytes; freeSpace -= bytes; rc += bytes; // print the delimeter bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; // move to the next point in the table nStart++; } else { // not enough free space in the text buffer (void)tableContext.out.nPoints; tableContext.in.nStartPoint = nStart; // modify the starting point for the next call // -------------------------------------------------------------------------- // Save context usbtmc_create_function_context( udi, (void*)GPIB_MemTableTherCorrMagniture ); if( !queue_add( &udi->GPIBFunctionContext.Context, (char*)&pcid , sizeof(pcid) ) // Save port combination id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&psid , sizeof(psid) ) // Save port state id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&tableContext , sizeof(tableContext) ) // Save table context ) { udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemTableTherCorrMagniture_EXIT; } udi->BulkRespondStatus.bIsLastTransfer = FALSE; errCode = 0; // -------------------------------------------------------------------------- goto L_GPIB_MemTableTherCorrMagniture_EXIT; } } // for tableContext.in.nStartPoint = nStart; // modify the starting point } // while( nStart < nPoints ) // Ok, all the points are converted here due to // otherwise, the program jumps to L_GPIB_MemTableTherCorrMagniture_EXIT label // after saving context. if( rc > 2 ) { // cut off the last space and comma rc -= 2; } } // 5 L_GPIB_MemTableTherCorrMagniture_EXIT: if( 0 != errCode ) { const char * pDescription = pcThermoDesc; if( ERROR_GPIB_ARRAY_CORRUPTED == errCode && ePortComb_MAX != pcid ) { pDescription = aPortComb[ ((pcid - ePortComb_MIN)%ePortComb_MAX) ]; } udi->BulkRespondStatus.bIsLastTransfer = TRUE; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } // GPIB_MemTableTherCorrPhase() // MEM:TABLE:THER:CORR:PHAS? , // Prints the contents of the characterization table depending on the following parameters: // - port combination (A, B, or CD, or CHECK, etc) // - port state (Load, Short, Thru11=S11, Check12=S12, etc.) size_t GPIB_MemTableTherCorrPhase( USB_DEVICE_INFO * udi, QUEUE * pQParameters, BOOL request ) { // 1 char * pBuffer = (char*)udi->usbtmcGpib.pData; size_t freeSpace = udi->BulkRespondStatus.RespondBufferSize; size_t rc = 0; // full amount of bytes returned unsigned int errCode = 0; // error identifier sACMGetPoints_t tableContext; // table context to store the data between calls ePortComb_t pcid = ePortComb_UNDEFINED; // port combination id ePortStateId_t psid = ePortStateId_UNDEFINED; // port state id // 2 // Check if the function context is saved and must be continued if( !udi->GPIBFunctionContext.bEnable ) { // no context found size_t nParam = 0; // amount of parameters if( !request ) { errCode = ERROR_GPIB_REQUEST_ONLY_SUPPORT; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // Retrieve amount of parameters from the queue if( !queue_getcount(pQParameters, &nParam) ) { // error: can't get parameters count errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // Check parameters count else if( 2 != nParam ) // this command must have 2 parameters { // error: wrong parameters count ( must be 2 ) errCode = ERROR_GPIB_WRONG_PARAMETERS_COUNT; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // parameter #1 - port combination (A/B/C/D/AB/AC/AD/BC/BD/CD/CHECK) { char textBuffer[16]; // retrieve the first parameter: port combination if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // retrieve the parameter pcid = GPIB_GetPortComb( &textBuffer[1], rc - 1 ); if( ePortComb_UNDEFINED == pcid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrPhase_EXIT; } } // parameter #2 - port state (SHORT, OPEN, LOAD, LOAD2, OPEN2, S11, S12, ..., S44) { char textBuffer[16]; // retrieve the first parameter: port state if( !queue_get( pQParameters, (BYTE*)textBuffer, sizeof(textBuffer), &rc )) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // check the parameter type else if( eParTypeChar != textBuffer[0] ) { errCode = ERROR_GPIB_INVALID_PARAMETER_TYPE; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // retrieve the parameter psid = GPIB_GetPortStateId( &textBuffer[1], rc - 1 ); if( ePortStateId_UNDEFINED == psid ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrPhase_EXIT; } } // Validate given parameters: port state and port combination if( ! ACMClass->methods.checkTableParams( pcid, psid ) ) { errCode = ERROR_GPIB_INVALID_PARAMETER; goto L_GPIB_MemTableTherCorrPhase_EXIT; } // initialize the table context @.out just for order tableContext.out.max = 0; // don't care tableContext.out.min = 0; // don't care tableContext.out.TableAddress = 0; // don't care tableContext.out.nPoints = 0; // don't care // initialize @.in to make the @.getPoints() call to load // the table header. // - set @.nCount to 0 to load the table header tableContext.in.nCount = 0; // must be 0 tableContext.in.nStartPoint = 0; // don't care tableContext.in.pDataArray = dbPointsBuffer; // must be initialized to pass internal checks // load table header and validate it // During this call the @tableContext.out will be initialized if( 1 != ACMClass->methods.xThermo.getPointsPhase( pcid, // port combination psid, // port state &tableContext ) ) { // failed errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; switch( tableContext.svc.errCode ) { case ERR_ACMGETPOINTS_INVAL : errCode = ERROR_GPIB_INVALID_PARAMETER; break; case ERR_ACMGETPOINTS_INVTBL: errCode = ERROR_GPIB_ARRAY_CORRUPTED; break; case ERR_ACMGETPOINTS_INVHDR: errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; break; case ERR_ACMGETPOINTS_IO : errCode = ERROR_GPIB_INTERNAL; break; } goto L_GPIB_MemTableTherCorrPhase_EXIT; } // ok, now @tableContext is initialized // Let's initialize the rest variables tableContext.in.nStartPoint = 0; // starting point = 0 tableContext.in.pDataArray = dbPointsBuffer; // initialize the temporary buffer tableContext.in.nCount = 0; // zero yet, see below } // 3 else { // load previous context size_t bytes; if( queue_get( &udi->GPIBFunctionContext.Context, (char*)&pcid , sizeof(pcid), &bytes ) // load port combination id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&psid , sizeof(psid), &bytes ) // load port state id && queue_get( &udi->GPIBFunctionContext.Context, (char*)&tableContext , sizeof(tableContext), &bytes ) // load table context ) { // OK // Note: // @tableContext.out.nPoints is remembered, amount of points // @tableContext.in.nStartPoint is remembered, starting point (the next after the lastest processed) } else { errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemTableTherCorrPhase_EXIT; } } rc = 0; // 4 { size_t nPoints = tableContext.out.nPoints; // amount of points in the table size_t nStart = tableContext.in.nStartPoint; // starting point // do until all the points are processed while( nStart < nPoints ) { // specify the number of points to retrieve: @tableContext.in.nCount // Note: @tableContext.out.nPoints and @tableContext.in.nStartPoint are // already specified or remembered size_t nStepPoints = (nPoints - nStart); // check the points number for the limit if( nStepPoints >= DBPOINTS_BUFFER_NUM ) { tableContext.in.nCount = DBPOINTS_BUFFER_NUM; // (nPoints - nStart) } else { // not greater than it is required tableContext.in.nCount = nStepPoints; } // retrieve the points from the memory if( tableContext.in.nCount != ACMClass->methods.xThermo.getPointsPhase( pcid, // port combination psid, // port state &tableContext ) ) { // error // Strange... The table is already validated. Maybe, it is I/O error issue. udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; switch( tableContext.svc.errCode ) { case ERR_ACMGETPOINTS_INVAL : errCode = ERROR_GPIB_INVALID_PARAMETER; break; case ERR_ACMGETPOINTS_INVTBL: errCode = ERROR_GPIB_ARRAY_CORRUPTED; break; case ERR_ACMGETPOINTS_INVHDR: errCode = ERROR_GPIB_THERMDATA_NOT_FOUND; break; case ERR_ACMGETPOINTS_IO : errCode = ERROR_GPIB_INTERNAL; break; } goto L_GPIB_MemTableTherCorrPhase_EXIT; } // Ok, the double-points are loaded... // Let's convert it! // @iPoint - just counts amount of converted points at this step. for( size_t iPoint = 0; iPoint < tableContext.in.nCount; ++iPoint ) { // the point format is: // , // where is a number in scientific format // with 10 fractional digits. Let's leave 2 digits for the exponent, // and one number takes 16 characters, plus the separator and the space. // So one point takes (16+2) = 18 characters. To be in save we will // suppose the one point takes 24 characters. // e.g. // 1.0000000000e+5, if( freeSpace >= 24 ) { size_t bytes = 0; // @dbPointsBuffer[iPoint] is one of points retrieved at this step. // Convert a phase bytes = GPIB_Double2Str( dbPointsBuffer[ iPoint ].phase, pBuffer, freeSpace, Format_Double2Str_Sci ); if( 0 == bytes ) { errCode = ERROR_GPIB_BUFFER_OVERFLOW; goto L_GPIB_MemTableTherCorrPhase_EXIT; } pBuffer += bytes; freeSpace -= bytes; rc += bytes; // print the delimeter bytes = snprintf( pBuffer, freeSpace, "%s", ", " ); pBuffer += bytes; freeSpace -= bytes; rc += bytes; // move to the next point in the table nStart++; } else { // not enough free space in the text buffer (void)tableContext.out.nPoints; tableContext.in.nStartPoint = nStart; // modify the starting point for the next call // -------------------------------------------------------------------------- // Save context usbtmc_create_function_context( udi, (void*)GPIB_MemTableTherCorrPhase ); if( !queue_add( &udi->GPIBFunctionContext.Context, (char*)&pcid , sizeof(pcid) ) // Save port combination id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&psid , sizeof(psid) ) // Save port state id || !queue_add( &udi->GPIBFunctionContext.Context, (char*)&tableContext , sizeof(tableContext) ) // Save table context ) { udi->GPIBFunctionContext.LastFunction = NULL; errCode = ERROR_GPIB_INTERNAL; goto L_GPIB_MemTableTherCorrPhase_EXIT; } udi->BulkRespondStatus.bIsLastTransfer = FALSE; errCode = 0; // -------------------------------------------------------------------------- goto L_GPIB_MemTableTherCorrPhase_EXIT; } } // for tableContext.in.nStartPoint = nStart; // modify the starting point } // while( nStart < nPoints ) // Ok, all the points are converted here due to // otherwise, the program jumps to L_GPIB_MemTableTherCorrMagniture_EXIT label // after saving context. if( rc > 2 ) { // cut off the last space and comma rc -= 2; } } // 5 L_GPIB_MemTableTherCorrPhase_EXIT: if( 0 != errCode ) { const char * pDescription = pcThermoDesc; if( ERROR_GPIB_ARRAY_CORRUPTED == errCode && ePortComb_MAX != pcid ) { pDescription = aPortComb[ ((pcid - ePortComb_MIN)%ePortComb_MAX) ]; } udi->BulkRespondStatus.bIsLastTransfer = TRUE; // 27/08/18 // GPIB_RaiseStandartError( udi, errCode, pDescription, GPIB_ERROR_ID_COR | request ); GPIB_RaiseStandartError( udi, errCode, pDescription, errClass_Autodetect ); rc = 0; } return rc; } #endif