19个文件已修改
3个文件已添加
10个文件已删除
| | |
| | | |
| | | file(GLOB_RECURSE SRC_FILES |
| | | libscpi/inc/*.h |
| | | libscpi/src/*.c |
| | | libscpi/src/*.c |
| | | libscpi/src/*.h |
| | | libscpi/src/*.cpp |
| | | ) |
| | | |
| | | |
| | | |
| | | find_package(QT NAMES Qt6 Qt5 REQUIRED) |
| | | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core) |
| | | set_source_files_properties(" libscpi/src/test-interactive.cpp" PROPERTIES HEADER_FILE_ONLY TRUE) |
| | | |
| | | add_library(scpi_static STATIC ${SRC_FILES}) |
| | | |
| | |
| | | PUBLIC |
| | | "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/libscpi/inc>" |
| | | ) |
| | | |
| | | target_link_libraries(scpi_static PRIVATE Qt::Core) |
| | | |
| | | # if(MSVC) |
| | | # target_compile_options(scpi_static PRIVATE /TP) |
| | | # endif() |
| | | |
| | | project(scpi_static LANGUAGES CXX) |
| | | |
| | | # add_library(scpi SHARED ${SRC_FILES}) |
| | | |
| | |
| | | file(GLOB_RECURSE TEST_FILES |
| | | libscpi/test/*.c |
| | | ) |
| | | foreach(test_file IN LISTS TEST_FILES) |
| | | cmake_path(GET test_file FILENAME test_name) |
| | | |
| | | add_executable(${test_name} ${test_file}) |
| | | |
| | | target_link_libraries(${test_name} |
| | | PRIVATE |
| | | scpi_static |
| | | unofficial::cunit::cunit |
| | | ) |
| | | |
| | | add_test( |
| | | NAME "${test_name}" |
| | | COMMAND ${test_name} |
| | | ) |
| | | endforeach() |
| | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | scpi_result_t SCPI_NanCy(scpi_t * context) |
| | | { |
| | | fprintf(stdout, "SCPI_NanCy: SCPI_NanCy\r\n"); |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | /** |
| | | * Reimplement IEEE488.2 *TST? |
| | | * |
| | |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | /* |
| | | scpi_commands提供了所有的scpi命令以及命令的回调函数和处理 |
| | | 后续如果需要添加自定义的指令集则在此处添加 |
| | | */ |
| | | const scpi_command_t scpi_commands[] = { |
| | | /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */ |
| | | {"*CLS", SCPI_CoreCls, 0}, |
| | |
| | | {"*STB?", SCPI_CoreStbQ, 0}, |
| | | {"*TST?", My_CoreTstQ, 0}, |
| | | {"*WAI", SCPI_CoreWai, 0}, |
| | | //用来测试 |
| | | {"*NanCy", SCPI_NanCy, 0}, |
| | | |
| | | /* Required SCPI commands (SCPI std V1999.0 4.2.1) */ |
| | | {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, 0}, |
| | | {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, 0}, |
| | | {"SYSTem:VERSion?", SCPI_SystemVersionQ, 0}, |
| | | |
| | | //{"STATus:OPERation?", scpi_stub_callback, 0}, |
| | | //{"STATus:OPERation:EVENt?", scpi_stub_callback, 0}, |
| | | //{"STATus:OPERation:CONDition?", scpi_stub_callback, 0}, |
| | | //{"STATus:OPERation:ENABle", scpi_stub_callback, 0}, |
| | | //{"STATus:OPERation:ENABle?", scpi_stub_callback, 0}, |
| | | |
| | | {"STATus:QUEStionable[:EVENt]?", SCPI_StatusQuestionableEventQ, 0}, |
| | | //{"STATus:QUEStionable:CONDition?", scpi_stub_callback, 0}, |
| | | {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable, 0}, |
| | | {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ, 0}, |
| | | |
| | |
| | | |
| | | #include "scpi/scpi.h" |
| | | |
| | | |
| | | /* |
| | | SCPI_IDN1 |
| | | SCPI_IDN2 |
| | | SCPI_IDN3 |
| | | SCPI_IDN4 |
| | | 这几个参数是用来注册时表示信息 |
| | | 对应*IDN? 查询命令的返回内容(设备标识查询命令) |
| | | 具体内容为(制造商,型号,序列号,固件版本) |
| | | 如果使用CPP版本的话使用scpi-def.h 和scpi-def.cpp |
| | | 这个提供了CPP版本的支持,.c的版本为旧标准版版本 |
| | | */ |
| | | #define SCPI_INPUT_BUFFER_LENGTH 256 |
| | | #define SCPI_ERROR_QUEUE_SIZE 17 |
| | | #define SCPI_IDN1 "MANUFACTURE" |
| | |
| | | {.pattern = "TEST:TEXT", .callback = TEST_Text,}, |
| | | {.pattern = "TEST:ARBitrary?", .callback = TEST_ArbQ,}, |
| | | {.pattern = "TEST:CHANnellist", .callback = TEST_Chanlst,}, |
| | | |
| | | SCPI_CMD_LIST_END |
| | | }; |
| | | |
| | |
| | | |
| | | #define SCPI_INPUT_BUFFER_LENGTH 256 |
| | | #define SCPI_ERROR_QUEUE_SIZE 17 |
| | | |
| | | |
| | | #define SCPI_IDN1 "MANUFACTURE" |
| | | #define SCPI_IDN2 "INSTR2013" |
| | | #define SCPI_IDN3 NULL |
| | |
| | | * |
| | | * |
| | | */ |
| | | |
| | | //#include "../common-cxx/scpi-def.h" |
| | | //这个版本测试用例提供了CPP版本的SICP库 其他的为C版本的库 |
| | | #include <iostream> |
| | | #include "scpi/scpi.h" |
| | | #include "../common-cxx/scpi-def.h" |
| | |
| | | /* |
| | | * |
| | | */ |
| | | |
| | | //网络通信部分可以不使用标准C的socket通信,可以采用C++或者Qt的网络库进行传输 |
| | | int main(int argc, char** argv) { |
| | | (void) argc; |
| | | (void) argv; |
| | |
| | | scpi_result_t SCPI_CoreOpcQ(scpi_t * context); |
| | | scpi_result_t SCPI_CoreRst(scpi_t * context); |
| | | scpi_result_t SCPI_CoreSre(scpi_t * context); |
| | | scpi_result_t SCPI_NanCy(scpi_t * context); |
| | | scpi_result_t SCPICount(scpi_t * context); |
| | | scpi_result_t SCPI_CoreSreQ(scpi_t * context); |
| | | scpi_result_t SCPI_CoreStbQ(scpi_t * context); |
| | | scpi_result_t SCPI_CoreTstQ(scpi_t * context); |
| | |
| | | |
| | | #include <string.h> |
| | | #include "scpi/types.h" |
| | | |
| | | /*这个类提供了接口实现 主要为 SCPI_Init 和 SCPI_Input |
| | | |
| | | SCPI_Init为SCPI的初始化 提供了一个全局的context使用 用法固定 |
| | | |
| | | SCPI_Input为输入命令 其中内部包含了解析参数 |
| | | |
| | | 接口函数的实现都在 parser.c文件内 |
| | | */ |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
New file |
| | |
| | | /*- |
| | | * BSD 2-Clause License |
| | | * |
| | | * Copyright (c) 2012-2018, Jan Breuer |
| | | * All rights reserved. |
| | | * |
| | | * Redistribution and use in source and binary forms, with or without |
| | | * modification, are permitted provided that the following conditions are met: |
| | | * |
| | | * * Redistributions of source code must retain the above copyright notice, this |
| | | * list of conditions and the following disclaimer. |
| | | * |
| | | * * Redistributions in binary form must reproduce the above copyright notice, |
| | | * this list of conditions and the following disclaimer in the documentation |
| | | * and/or other materials provided with the distribution. |
| | | * |
| | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| | | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| | | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| | | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| | | */ |
| | | |
| | | #ifndef __SCPI_DEF_H_ |
| | | #define __SCPI_DEF_H_ |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "scpi/scpi.h" |
| | | |
| | | #define SCPI_INPUT_BUFFER_LENGTH 256 |
| | | #define SCPI_ERROR_QUEUE_SIZE 17 |
| | | |
| | | |
| | | #define SCPI_IDN1 "MANUFACTURE" |
| | | #define SCPI_IDN2 "INSTR2013" |
| | | #define SCPI_IDN3 NULL |
| | | #define SCPI_IDN4 "01-02" |
| | | |
| | | extern const scpi_command_t scpi_commands[]; |
| | | extern scpi_interface_t scpi_interface; |
| | | extern char scpi_input_buffer[]; |
| | | extern scpi_error_t scpi_error_queue_data[]; |
| | | extern scpi_t scpi_context; |
| | | |
| | | size_t SCPI_Write(scpi_t * context, const char * data, size_t len); |
| | | int SCPI_Error(scpi_t * context, int_fast16_t err); |
| | | scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val); |
| | | scpi_result_t SCPI_Reset(scpi_t * context); |
| | | scpi_result_t SCPI_Flush(scpi_t * context); |
| | | |
| | | |
| | | scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | #endif /* __SCPI_DEF_H_ */ |
| | | |
| | |
| | | |
| | | #include <stddef.h> |
| | | #include <stdint.h> |
| | | #include "scpi/config.h" |
| | | |
| | | #include <scpi/config.h> |
| | | #if HAVE_STDBOOL |
| | | #include <stdbool.h> |
| | | #endif |
| | |
| | | }; |
| | | |
| | | struct _scpi_t { |
| | | //命令表的指针 |
| | | const scpi_command_t * cmdlist; |
| | | //输入的数据 |
| | | scpi_buffer_t buffer; |
| | | //解析命令的参数列表 |
| | | scpi_param_list_t param_list; |
| | | //SCPI的硬件接口,刷新 重置 写入 报错 |
| | | scpi_interface_t * interface; |
| | | //输出数据的个数 |
| | | int_fast16_t output_count; |
| | | //输入数据的个数 用于检验参数是否合法 |
| | | int_fast16_t input_count; |
| | | //是否为第一个输出项 |
| | | scpi_bool_t first_output; |
| | | //命令是否出错 |
| | | scpi_bool_t cmd_error; |
| | | //错误信息队列 |
| | | scpi_fifo_t error_queue; |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE |
| | | //详细错误信息 |
| | | scpi_error_info_heap_t error_info_heap; |
| | | #endif |
| | | //SCPI寄存器 |
| | | scpi_reg_val_t registers[SCPI_REG_COUNT]; |
| | | //单位表的指针 |
| | | const scpi_unit_def_t * units; |
| | | |
| | | void * user_context; |
| | | //解析器的状态 |
| | | scpi_parser_state_t parser_state; |
| | | //*IDN?查询的响应字段 |
| | | const char * idn[4]; |
| | | //剩余待传输的字节 |
| | | size_t arbitrary_remaining; |
| | | }; |
| | | |
| | |
| | | |
| | | scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory); |
| | | |
| | | scpi_bool_t SCPI_ParamTranslateNumberVal(scpi_t * context, scpi_parameter_t * parameter); |
| | | size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len); |
| | | |
| | | #ifdef __cplusplus |
| | |
| | | |
| | | #include <stdint.h> |
| | | |
| | | #include "scpi/parser.h" |
| | | #include "scpi/ieee488.h" |
| | | #include "scpi/error.h" |
| | | #include <scpi/parser.h> |
| | | #include <scpi/ieee488.h> |
| | | #include <scpi/error.h> |
| | | #include "fifo_private.h" |
| | | #include "scpi/constants.h" |
| | | #include <scpi/constants.h> |
| | | |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION |
| | | #define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (e)->device_dependent_info = (i); } while(0) |
| | |
| | | #ifndef SCPI_FIFO_H |
| | | #define SCPI_FIFO_H |
| | | |
| | | #include "scpi/types.h" |
| | | #include "utils_private.h" |
| | | #include <scpi/types.h> |
| | | #include "utils_private.h" |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | |
| | | #include "scpi/parser.h" |
| | | #include "scpi/ieee488.h" |
| | | #include "scpi/error.h" |
| | | #include "scpi/constants.h" |
| | | |
| | | #include <stdio.h> |
| | | |
| | | static const scpi_reg_info_t scpi_reg_details[SCPI_REG_COUNT] = { |
| | |
| | | * @param context |
| | | * @return |
| | | */ |
| | | scpi_result_t SCPI_CoreEse(scpi_t * context) { |
| | | scpi_result_t SCPI_CoreEse(scpi_t * context) |
| | | { |
| | | int32_t new_ESE; |
| | | if (SCPI_ParamInt32(context, &new_ESE, TRUE)) { |
| | | SCPI_RegSet(context, SCPI_REG_ESE, (scpi_reg_val_t) new_ESE); |
| | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | scpi_result_t SCPI_NanCy(scpi_t * context) |
| | | { |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | scpi_result_t SCPICount(scpi_t * context) |
| | | { |
| | | return SCPI_RES_OK; |
| | | |
| | | |
| | | } |
| | | |
| | |
| | | token->type = SCPI_TOKEN_UNKNOWN; |
| | | } |
| | | |
| | | return token->len; |
| | | return token->len; |
| | | |
| | | |
| | | } |
| | | |
| | | /* 7.6.1 <COMMAND PROGRAM HEADER> */ |
| | |
| | | * @param token |
| | | * @return |
| | | */ |
| | | |
| | | /*识别和分类SCPI命令头 |
| | | 公共命令头 以*识别 如 *IDN? |
| | | 复合命令头 以:识别 如 SYSTem:ERRor? |
| | | 命令查询 以?识别 |
| | | 普通命令:MEAS:VOLT |
| | | 查询命令:MEAS:VOLT? |
| | | */ |
| | | int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) { |
| | | |
| | | // 记录起始位置 并且初始化类型 |
| | | int res; |
| | | token->ptr = state->pos; |
| | | token->type = SCPI_TOKEN_UNKNOWN; |
| | | |
| | | res = skipCommonProgramHeader(state); |
| | | // 解析到公共命令头后检查查询符 |
| | | if (res >= SKIP_OK) { |
| | | if (skipChr(state, '?') >= SKIP_OK) { |
| | | token->type = SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER; |
| | |
| | | } else if (res <= SKIP_INCOMPLETE) { |
| | | token->type = SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER; |
| | | } else if (res == SKIP_NONE) { |
| | | |
| | | // 解析到复合命令后检查查询符 |
| | | res = skipCompoundProgramHeader(state); |
| | | |
| | | if (res >= SKIP_OK) { |
| | |
| | | token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER; |
| | | } |
| | | } |
| | | |
| | | // 计算长度 |
| | | if (token->type != SCPI_TOKEN_UNKNOWN) { |
| | | token->len = state->pos - token->ptr; |
| | | } else { |
| | |
| | | * Process command |
| | | * @param context |
| | | */ |
| | | |
| | | //负命令回调的执行、参数处理和错误管理 |
| | | static scpi_bool_t processCommand(scpi_t * context) { |
| | | const scpi_command_t * cmd = context->param_list.cmd; |
| | | lex_state_t * state = &context->param_list.lex_state; |
| | | scpi_bool_t result = TRUE; |
| | | // 先检测是否为查询命令(以?结尾) |
| | | scpi_bool_t is_query = context->param_list.cmd_raw.data[context->param_list.cmd_raw.length - 1] == '?'; |
| | | |
| | | /* conditionally write ; */ |
| | | //输出分隔符 |
| | | if(!context->first_output && is_query) { |
| | | writeData(context, ";", 1); |
| | | } |
| | | |
| | | //重置context上下文状态 |
| | | context->cmd_error = FALSE; |
| | | context->output_count = 0; |
| | | context->input_count = 0; |
| | | context->arbitrary_remaining = 0; |
| | | |
| | | /* if callback exists - call command callback */ |
| | | //命令回调执行 scpi_commands[]查找这里面的命令类型 |
| | | if (cmd->callback != NULL) { |
| | | if ((cmd->callback(context) != SCPI_RES_OK)) { |
| | | if (!context->cmd_error) { |
| | |
| | | } |
| | | |
| | | /* set error if command callback did not read all parameters */ |
| | | //检查参数完整性 |
| | | if (state->pos < (state->buffer + state->len) && !context->cmd_error) { |
| | | SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED); |
| | | result = FALSE; |
| | |
| | | * @param len - command line length |
| | | * @return FALSE if there was some error during evaluation of commands |
| | | */ |
| | | |
| | | /* |
| | | 指令解析函数 |
| | | 解析流程: |
| | | 1.先检查命令头是否合法,检查公共命令 或者复合命令 以及普通命令或者查询命令 |
| | | 2.命令合法后组合复合命令 如* :: ? 三种类型 |
| | | 3.通过完整的命令查找 是否有相对应的类型 |
| | | |
| | | */ |
| | | scpi_bool_t SCPI_Parse(scpi_t * context, char * data, int len) { |
| | | scpi_bool_t result = TRUE; |
| | | scpi_parser_state_t * state; |
| | |
| | | return FALSE; |
| | | } |
| | | |
| | | //初始化context的解析器状态 |
| | | state = &context->parser_state; |
| | | context->output_count = 0; |
| | | context->first_output = TRUE; |
| | | |
| | | while (1) { |
| | | |
| | | //初步的检查命令是否合法 |
| | | r = scpiParser_detectProgramMessageUnit(state, data, len); |
| | | |
| | | if (state->programHeader.type == SCPI_TOKEN_INVALID) { |
| | | SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER); |
| | | result = FALSE; |
| | | } else if (state->programHeader.len > 0) { |
| | | |
| | | } |
| | | else if (state->programHeader.len > 0) |
| | | { |
| | | //命令有效开始处理 |
| | | composeCompoundCommand(&cmd_prev, &state->programHeader); |
| | | |
| | | //查找命令后并且设置解析状态并且执行命令 |
| | | if (findCommandHeader(context, state->programHeader.ptr, state->programHeader.len)) { |
| | | |
| | | context->param_list.lex_state.buffer = state->programData.ptr; |
| | |
| | | context->param_list.cmd_raw.data = state->programHeader.ptr; |
| | | context->param_list.cmd_raw.position = 0; |
| | | context->param_list.cmd_raw.length = state->programHeader.len; |
| | | |
| | | //命令查找 |
| | | result &= processCommand(context); |
| | | cmd_prev = state->programHeader; |
| | | } else { |
| | | //如果命令没有定义则抛出错误 |
| | | /* place undefined header with error */ |
| | | /* calculate length of errorenous header and trim \r\n */ |
| | | size_t r2 = r; |
| | |
| | | } |
| | | |
| | | /* conditionally write new line */ |
| | | //解析完毕以后等待下一条指令的输入 |
| | | writeNewLine(context); |
| | | |
| | | return result; |
| | |
| | | * @param context |
| | | * @param commands |
| | | * @param interface |
| | | * @param units |
| | | * @param unitsfind_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets) |
| | | set(project_link_libraries Qt::Widgets) |
| | | |
| | | * @param idn1 |
| | | * @param idn2 |
| | | * @param idn3 |
| | |
| | | context->interface = interface; |
| | | context->units = units; |
| | | context->idn[0] = idn1; |
| | | |
| | | context->idn[1] = idn2; |
| | | context->idn[2] = idn3; |
| | | context->idn[3] = idn4; |
| | |
| | | * @param data |
| | | * @param len |
| | | * @return |
| | | */ |
| | | */find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets) |
| | | set(project_link_libraries Qt::Widgets) |
| | | |
| | | void SCPI_InitHeap(scpi_t * context, |
| | | char * error_info_heap, size_t error_info_heap_length) { |
| | | scpiheap_init(&context->error_info_heap, error_info_heap, error_info_heap_length); |
| | |
| | | * @param len - length of data |
| | | * @return |
| | | */ |
| | | |
| | | /* |
| | | 输入处理函数,输入数据并且处理完整的SCPI命令 |
| | | context:上下文的context |
| | | data:输入的数据 |
| | | len:输入数据的长度 |
| | | */ |
| | | scpi_bool_t SCPI_Input(scpi_t * context, const char * data, int len) { |
| | | scpi_bool_t result = TRUE; |
| | | scpi_bool_t result = FALSE; |
| | | size_t totcmdlen = 0; |
| | | int cmdlen = 0; |
| | | |
| | | //当长度为0时 解析当前的数据 并且清空context的buff标记位 |
| | | if (len == 0) { |
| | | context->buffer.data[context->buffer.position] = 0; |
| | | //SCPI_Parse 解析完成后会返回状态 |
| | | result = SCPI_Parse(context, context->buffer.data, context->buffer.position); |
| | | context->buffer.position = 0; |
| | | } else { |
| | | /* |
| | | 如果长度溢出则指令无效 |
| | | 正常情况下会将输入的指令传给context内 |
| | | */ |
| | | int buffer_free; |
| | | |
| | | buffer_free = context->buffer.length - context->buffer.position; |
| | | |
| | | if (len > (buffer_free - 1)) { |
| | | /* Input buffer overrun - invalidate buffer */ |
| | | context->buffer.position = 0; |
| | |
| | | |
| | | |
| | | while (1) { |
| | | //初步检查命令是否合法 |
| | | cmdlen = scpiParser_detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen); |
| | | totcmdlen += cmdlen; |
| | | |
| | | //如果命令合法则将命令解析,同时删除context内的已经处理完成的命令 |
| | | if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) { |
| | | result = SCPI_Parse(context, context->buffer.data, totcmdlen); |
| | | memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen); |
| | |
| | | */ |
| | | size_t SCPI_ResultInt32(scpi_t * context, int32_t val) { |
| | | return resultUInt32BaseSign(context, val, 10, TRUE); |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param len |
| | | * @return |
| | | */ |
| | | //识别完整的SCPI命令 |
| | | int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) { |
| | | lex_state_t lex_state; |
| | | scpi_token_t tmp; |
| | | int result = 0; |
| | | |
| | | // 初始化词法分析 |
| | | lex_state.buffer = lex_state.pos = buffer; |
| | | lex_state.len = len; |
| | | // 重置参数计数器 |
| | | state->numberOfParameters = 0; |
| | | |
| | | /* ignore whitespace at the begginig */ |
| | | //预处理 跳过空白字符 |
| | | scpiLex_WhiteSpace(&lex_state, &tmp); |
| | | |
| | | if (scpiLex_ProgramHeader(&lex_state, &state->programHeader) >= 0) { |
| | | if (scpiLex_WhiteSpace(&lex_state, &tmp) > 0) { |
| | | //找到命令头后解析所有命令 |
| | | if (scpiLex_ProgramHeader(&lex_state, &state->programHeader) >= 0) |
| | | { |
| | | if (scpiLex_WhiteSpace(&lex_state, &tmp) > 0) |
| | | { |
| | | scpiParser_parseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters); |
| | | } else { |
| | | } |
| | | else |
| | | { |
| | | //无效命令标记 |
| | | invalidateToken(&state->programData, lex_state.pos); |
| | | } |
| | | } else { |
| | | } |
| | | else |
| | | { |
| | | //处理解析失败的命令头 |
| | | invalidateToken(&state->programHeader, lex_state.buffer); |
| | | invalidateToken(&state->programData, lex_state.buffer); |
| | | } |
| | |
| | | if (result == 0) result = scpiLex_NewLine(&lex_state, &tmp); |
| | | if (result == 0) result = scpiLex_Semicolon(&lex_state, &tmp); |
| | | |
| | | //无效字符处理 |
| | | if (!scpiLex_IsEos(&lex_state) && (result == 0)) { |
| | | // 跳过无效字符 |
| | | lex_state.pos++; |
| | | |
| | | //标记位命令头解析失败 |
| | | state->programHeader.len = 1; |
| | | state->programHeader.type = SCPI_TOKEN_INVALID; |
| | | |
| | | invalidateToken(&state->programData, lex_state.buffer); |
| | | } |
| | | |
| | | //设置终止符 |
| | | if (SCPI_TOKEN_SEMICOLON == tmp.type) { |
| | | state->termination = SCPI_MESSAGE_TERMINATION_SEMICOLON; |
| | | } else if (SCPI_TOKEN_NL == tmp.type) { |
New file |
| | |
| | | /*- |
| | | * BSD 2-Clause License |
| | | * |
| | | * Copyright (c) 2012-2018, Jan Breuer |
| | | * All rights reserved. |
| | | * |
| | | * Redistribution and use in source and binary forms, with or without |
| | | * modification, are permitted provided that the following conditions are met: |
| | | * |
| | | * * Redistributions of source code must retain the above copyright notice, this |
| | | * list of conditions and the following disclaimer. |
| | | * |
| | | * * Redistributions in binary form must reproduce the above copyright notice, |
| | | * this list of conditions and the following disclaimer in the documentation |
| | | * and/or other materials provided with the distribution. |
| | | * |
| | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| | | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| | | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| | | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| | | */ |
| | | |
| | | /** |
| | | * @file scpi-def.c |
| | | * @date Thu Nov 15 10:58:45 UTC 2012 |
| | | * |
| | | * @brief SCPI parser test |
| | | * |
| | | * |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include "scpi/scpi.h" |
| | | #include "scpi/scpi-def.h" |
| | | |
| | | static scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) { |
| | | scpi_number_t param1, param2; |
| | | char bf[15]; |
| | | fprintf(stderr, "meas:volt:dc\r\n"); /* debug command name */ |
| | | |
| | | /* read first parameter if present */ |
| | | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m1, FALSE)) { |
| | | /* do something, if parameter not present */ |
| | | } |
| | | |
| | | /* read second paraeter if present */ |
| | | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m2, FALSE)) { |
| | | /* do something, if parameter not present */ |
| | | } |
| | | |
| | | |
| | | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m1, bf, 15); |
| | | fprintf(stderr, "\tP1=%s\r\n", bf); |
| | | |
| | | |
| | | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m2, bf, 15); |
| | | fprintf(stderr, "\tP2=%s\r\n", bf); |
| | | |
| | | SCPI_ResultDouble(context, 0); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | static scpi_result_t DMM_MeasureVoltageAcQ(scpi_t * context) { |
| | | scpi_number_t param1, param2; |
| | | char bf[15]; |
| | | fprintf(stderr, "meas:volt:ac\r\n"); /* debug command name */ |
| | | |
| | | /* read first parameter if present */ |
| | | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m1, FALSE)) { |
| | | /* do something, if parameter not present */ |
| | | } |
| | | |
| | | /* read second paraeter if present */ |
| | | if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m2, FALSE)) { |
| | | /* do something, if parameter not present */ |
| | | } |
| | | |
| | | |
| | | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m1, bf, 15); |
| | | fprintf(stderr, "\tP1=%s\r\n", bf); |
| | | |
| | | |
| | | SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m2, bf, 15); |
| | | fprintf(stderr, "\tP2=%s\r\n", bf); |
| | | |
| | | SCPI_ResultDouble(context, 0); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | static scpi_result_t DMM_ConfigureVoltageDc(scpi_t * context) { |
| | | double param1, param2; |
| | | fprintf(stderr, "conf:volt:dc\r\n"); /* debug command name */ |
| | | |
| | | /* read first parameter if present */ |
| | | if (!SCPI_ParamDouble(context, ¶m1, TRUE)) { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | |
| | | /* read second paraeter if present */ |
| | | if (!SCPI_ParamDouble(context, ¶m2, FALSE)) { |
| | | /* do something, if parameter not present */ |
| | | } |
| | | |
| | | fprintf(stderr, "\tP1=%lf\r\n", param1); |
| | | fprintf(stderr, "\tP2=%lf\r\n", param2); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | static scpi_result_t TEST_Bool(scpi_t * context) { |
| | | scpi_bool_t param1; |
| | | fprintf(stderr, "TEST:BOOL\r\n"); /* debug command name */ |
| | | |
| | | /* read first parameter if present */ |
| | | if (!SCPI_ParamBool(context, ¶m1, TRUE)) { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | |
| | | fprintf(stderr, "\tP1=%d\r\n", param1); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | scpi_choice_def_t trigger_source[] = { |
| | | {"BUS", 5}, |
| | | {"IMMediate", 6}, |
| | | {"EXTernal", 7}, |
| | | SCPI_CHOICE_LIST_END /* termination of option list */ |
| | | }; |
| | | |
| | | static scpi_result_t TEST_ChoiceQ(scpi_t * context) { |
| | | |
| | | int32_t param; |
| | | const char * name; |
| | | |
| | | if (!SCPI_ParamChoice(context, trigger_source, ¶m, TRUE)) { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | |
| | | SCPI_ChoiceToName(trigger_source, param, &name); |
| | | fprintf(stderr, "\tP1=%s (%ld)\r\n", name, (long int) param); |
| | | |
| | | SCPI_ResultInt32(context, param); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | static scpi_result_t TEST_Numbers(scpi_t * context) { |
| | | int32_t numbers[2]; |
| | | |
| | | SCPI_CommandNumbers(context, numbers, 2, 1); |
| | | |
| | | fprintf(stderr, "TEST numbers %d %d\r\n", numbers[0], numbers[1]); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | static scpi_result_t TEST_Text(scpi_t * context) { |
| | | char buffer[100]; |
| | | size_t copy_len; |
| | | |
| | | if (!SCPI_ParamCopyText(context, buffer, sizeof (buffer), ©_len, FALSE)) { |
| | | buffer[0] = '\0'; |
| | | } |
| | | |
| | | fprintf(stderr, "TEXT: ***%s***\r\n", buffer); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | static scpi_result_t TEST_ArbQ(scpi_t * context) { |
| | | const char * data; |
| | | size_t len; |
| | | |
| | | if (SCPI_ParamArbitraryBlock(context, &data, &len, FALSE)) { |
| | | SCPI_ResultArbitraryBlock(context, data, len); |
| | | } |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | struct _scpi_channel_value_t { |
| | | int32_t row; |
| | | int32_t col; |
| | | }; |
| | | typedef struct _scpi_channel_value_t scpi_channel_value_t; |
| | | |
| | | /** |
| | | * @brief |
| | | * parses lists |
| | | * channel numbers > 0. |
| | | * no checks yet. |
| | | * valid: (@1), (@3!1:1!3), ... |
| | | * (@1!1:3!2) would be 1!1, 1!2, 2!1, 2!2, 3!1, 3!2. |
| | | * (@3!1:1!3) would be 3!1, 3!2, 3!3, 2!1, 2!2, 2!3, ... 1!3. |
| | | * |
| | | * @param channel_list channel list, compare to SCPI99 Vol 1 Ch. 8.3.2 |
| | | */ |
| | | static scpi_result_t TEST_Chanlst(scpi_t *context) { |
| | | scpi_parameter_t channel_list_param; |
| | | #define MAXROW 2 /* maximum number of rows */ |
| | | #define MAXCOL 6 /* maximum number of columns */ |
| | | #define MAXDIM 2 /* maximum number of dimensions */ |
| | | scpi_channel_value_t array[MAXROW * MAXCOL]; /* array which holds values in order (2D) */ |
| | | size_t chanlst_idx; /* index for channel list */ |
| | | size_t arr_idx = 0; /* index for array */ |
| | | size_t n, m = 1; /* counters for row (n) and columns (m) */ |
| | | |
| | | /* get channel list */ |
| | | if (SCPI_Parameter(context, &channel_list_param, TRUE)) { |
| | | scpi_expr_result_t res; |
| | | scpi_bool_t is_range; |
| | | int32_t values_from[MAXDIM]; |
| | | int32_t values_to[MAXDIM]; |
| | | size_t dimensions; |
| | | |
| | | bool for_stop_row = FALSE; /* true if iteration for rows has to stop */ |
| | | bool for_stop_col = FALSE; /* true if iteration for columns has to stop */ |
| | | int32_t dir_row = 1; /* direction of counter for rows, +/-1 */ |
| | | int32_t dir_col = 1; /* direction of counter for columns, +/-1 */ |
| | | |
| | | /* the next statement is valid usage and it gets only real number of dimensions for the first item (index 0) */ |
| | | if (!SCPI_ExprChannelListEntry(context, &channel_list_param, 0, &is_range, NULL, NULL, 0, &dimensions)) { |
| | | chanlst_idx = 0; /* call first index */ |
| | | arr_idx = 0; /* set arr_idx to 0 */ |
| | | do { /* if valid, iterate over channel_list_param index while res == valid (do-while cause we have to do it once) */ |
| | | res = SCPI_ExprChannelListEntry(context, &channel_list_param, chanlst_idx, &is_range, values_from, values_to, 4, &dimensions); |
| | | if (is_range == FALSE) { /* still can have multiple dimensions */ |
| | | if (dimensions == 1) { |
| | | /* here we have our values |
| | | * row == values_from[0] |
| | | * col == 0 (fixed number) |
| | | * call a function or something */ |
| | | array[arr_idx].row = values_from[0]; |
| | | array[arr_idx].col = 0; |
| | | } else if (dimensions == 2) { |
| | | /* here we have our values |
| | | * row == values_fom[0] |
| | | * col == values_from[1] |
| | | * call a function or something */ |
| | | array[arr_idx].row = values_from[0]; |
| | | array[arr_idx].col = values_from[1]; |
| | | } else { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | arr_idx++; /* inkrement array where we want to save our values to, not neccessary otherwise */ |
| | | if (arr_idx >= MAXROW * MAXCOL) { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | } else if (is_range == TRUE) { |
| | | if (values_from[0] > values_to[0]) { |
| | | dir_row = -1; /* we have to decrement from values_from */ |
| | | } else { /* if (values_from[0] < values_to[0]) */ |
| | | dir_row = +1; /* default, we increment from values_from */ |
| | | } |
| | | |
| | | /* iterating over rows, do it once -> set for_stop_row = false |
| | | * needed if there is channel list index isn't at end yet */ |
| | | for_stop_row = FALSE; |
| | | for (n = values_from[0]; for_stop_row == FALSE; n += dir_row) { |
| | | /* usual case for ranges, 2 dimensions */ |
| | | if (dimensions == 2) { |
| | | if (values_from[1] > values_to[1]) { |
| | | dir_col = -1; |
| | | } else if (values_from[1] < values_to[1]) { |
| | | dir_col = +1; |
| | | } |
| | | /* iterating over columns, do it at least once -> set for_stop_col = false |
| | | * needed if there is channel list index isn't at end yet */ |
| | | for_stop_col = FALSE; |
| | | for (m = values_from[1]; for_stop_col == FALSE; m += dir_col) { |
| | | /* here we have our values |
| | | * row == n |
| | | * col == m |
| | | * call a function or something */ |
| | | array[arr_idx].row = n; |
| | | array[arr_idx].col = m; |
| | | arr_idx++; |
| | | if (arr_idx >= MAXROW * MAXCOL) { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | if (m == (size_t)values_to[1]) { |
| | | /* endpoint reached, stop column for-loop */ |
| | | for_stop_col = TRUE; |
| | | } |
| | | } |
| | | /* special case for range, example: (@2!1) */ |
| | | } else if (dimensions == 1) { |
| | | /* here we have values |
| | | * row == n |
| | | * col == 0 (fixed number) |
| | | * call function or sth. */ |
| | | array[arr_idx].row = n; |
| | | array[arr_idx].col = 0; |
| | | arr_idx++; |
| | | if (arr_idx >= MAXROW * MAXCOL) { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | } |
| | | if (n == (size_t)values_to[0]) { |
| | | /* endpoint reached, stop row for-loop */ |
| | | for_stop_row = TRUE; |
| | | } |
| | | } |
| | | |
| | | |
| | | } else { |
| | | return SCPI_RES_ERR; |
| | | } |
| | | /* increase index */ |
| | | chanlst_idx++; |
| | | } while (SCPI_EXPR_OK == SCPI_ExprChannelListEntry(context, &channel_list_param, chanlst_idx, &is_range, values_from, values_to, 4, &dimensions)); |
| | | /* while checks, whether incremented index is valid */ |
| | | } |
| | | /* do something at the end if needed */ |
| | | /* array[arr_idx].row = 0; */ |
| | | /* array[arr_idx].col = 0; */ |
| | | } |
| | | |
| | | { |
| | | size_t i; |
| | | fprintf(stderr, "TEST_Chanlst: "); |
| | | for (i = 0; i< arr_idx; i++) { |
| | | fprintf(stderr, "%d!%d, ", array[i].row, array[i].col); |
| | | } |
| | | fprintf(stderr, "\r\n"); |
| | | } |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | /** |
| | | * Reimplement IEEE488.2 *TST? |
| | | * |
| | | * Result should be 0 if everything is ok |
| | | * Result should be 1 if something goes wrong |
| | | * |
| | | * Return SCPI_RES_OK |
| | | */ |
| | | static scpi_result_t My_CoreTstQ(scpi_t * context) { |
| | | |
| | | SCPI_ResultInt32(context, 0); |
| | | |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | const scpi_command_t scpi_commands[] = { |
| | | /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */ |
| | | { .pattern = "*CLS", .callback = SCPI_CoreCls,}, |
| | | { .pattern = "*ESE", .callback = SCPI_CoreEse,}, |
| | | { .pattern = "*ESE?", .callback = SCPI_CoreEseQ,}, |
| | | { .pattern = "*ESR?", .callback = SCPI_CoreEsrQ,}, |
| | | { .pattern = "*IDN?", .callback = SCPI_CoreIdnQ,}, |
| | | { .pattern = "*OPC", .callback = SCPI_CoreOpc,}, |
| | | { .pattern = "*OPC?", .callback = SCPI_CoreOpcQ,}, |
| | | { .pattern = "*RST", .callback = SCPI_CoreRst,}, |
| | | { .pattern = "*SRE", .callback = SCPI_CoreSre,}, |
| | | { .pattern = "*SRE?", .callback = SCPI_CoreSreQ,}, |
| | | { .pattern = "*STB?", .callback = SCPI_CoreStbQ,}, |
| | | { .pattern = "*TST?", .callback = My_CoreTstQ,}, |
| | | { .pattern = "*WAI", .callback = SCPI_CoreWai,}, |
| | | |
| | | /* Required SCPI commands (SCPI std V1999.0 4.2.1) */ |
| | | {.pattern = "SYSTem:ERRor[:NEXT]?", .callback = SCPI_SystemErrorNextQ,}, |
| | | {.pattern = "SYSTem:ERRor:COUNt?", .callback = SCPI_SystemErrorCountQ,}, |
| | | {.pattern = "SYSTem:VERSion?", .callback = SCPI_SystemVersionQ,}, |
| | | |
| | | /* {.pattern = "STATus:OPERation?", .callback = scpi_stub_callback,}, */ |
| | | /* {.pattern = "STATus:OPERation:EVENt?", .callback = scpi_stub_callback,}, */ |
| | | /* {.pattern = "STATus:OPERation:CONDition?", .callback = scpi_stub_callback,}, */ |
| | | /* {.pattern = "STATus:OPERation:ENABle", .callback = scpi_stub_callback,}, */ |
| | | /* {.pattern = "STATus:OPERation:ENABle?", .callback = scpi_stub_callback,}, */ |
| | | |
| | | {.pattern = "STATus:QUEStionable[:EVENt]?", .callback = SCPI_StatusQuestionableEventQ,}, |
| | | /* {.pattern = "STATus:QUEStionable:CONDition?", .callback = scpi_stub_callback,}, */ |
| | | {.pattern = "STATus:QUEStionable:ENABle", .callback = SCPI_StatusQuestionableEnable,}, |
| | | {.pattern = "STATus:QUEStionable:ENABle?", .callback = SCPI_StatusQuestionableEnableQ,}, |
| | | |
| | | {.pattern = "STATus:PRESet", .callback = SCPI_StatusPreset,}, |
| | | |
| | | /* DMM */ |
| | | {.pattern = "MEASure:VOLTage:DC?", .callback = DMM_MeasureVoltageDcQ,}, |
| | | {.pattern = "CONFigure:VOLTage:DC", .callback = DMM_ConfigureVoltageDc,}, |
| | | {.pattern = "MEASure:VOLTage:DC:RATio?", .callback = SCPI_StubQ,}, |
| | | {.pattern = "MEASure:VOLTage:AC?", .callback = DMM_MeasureVoltageAcQ,}, |
| | | {.pattern = "MEASure:CURRent:DC?", .callback = SCPI_StubQ,}, |
| | | {.pattern = "MEASure:CURRent:AC?", .callback = SCPI_StubQ,}, |
| | | {.pattern = "MEASure:RESistance?", .callback = SCPI_StubQ,}, |
| | | {.pattern = "MEASure:FRESistance?", .callback = SCPI_StubQ,}, |
| | | {.pattern = "MEASure:FREQuency?", .callback = SCPI_StubQ,}, |
| | | {.pattern = "MEASure:PERiod?", .callback = SCPI_StubQ,}, |
| | | |
| | | {.pattern = "SYSTem:COMMunication:TCPIP:CONTROL?", .callback = SCPI_SystemCommTcpipControlQ,}, |
| | | |
| | | {.pattern = "TEST:BOOL", .callback = TEST_Bool,}, |
| | | {.pattern = "TEST:CHOice?", .callback = TEST_ChoiceQ,}, |
| | | {.pattern = "TEST#:NUMbers#", .callback = TEST_Numbers,}, |
| | | {.pattern = "TEST:TEXT", .callback = TEST_Text,}, |
| | | {.pattern = "TEST:ARBitrary?", .callback = TEST_ArbQ,}, |
| | | {.pattern = "TEST:CHANnellist", .callback = TEST_Chanlst,}, |
| | | SCPI_CMD_LIST_END |
| | | }; |
| | | |
| | | scpi_interface_t scpi_interface = { |
| | | .error = SCPI_Error, |
| | | .write = SCPI_Write, |
| | | .control = SCPI_Control, |
| | | .flush = SCPI_Flush, |
| | | .reset = SCPI_Reset, |
| | | }; |
| | | |
| | | char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH]; |
| | | scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE]; |
| | | |
| | | scpi_t scpi_context; |
New file |
| | |
| | | /*- |
| | | * BSD 2-Clause License |
| | | * |
| | | * Copyright (c) 2012-2018, Jan Breuer |
| | | * All rights reserved. |
| | | * |
| | | * Redistribution and use in source and binary forms, with or without |
| | | * modification, are permitted provided that the following conditions are met: |
| | | * |
| | | * * Redistributions of source code must retain the above copyright notice, this |
| | | * list of conditions and the following disclaimer. |
| | | * |
| | | * * Redistributions in binary form must reproduce the above copyright notice, |
| | | * this list of conditions and the following disclaimer in the documentation |
| | | * and/or other materials provided with the distribution. |
| | | * |
| | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| | | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| | | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| | | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| | | */ |
| | | |
| | | /** |
| | | * @file main.c |
| | | * @date Thu Nov 15 10:58:45 UTC 2012 |
| | | * |
| | | * @brief SCPI parser test |
| | | * |
| | | * |
| | | */ |
| | | |
| | | //这个版本测试用例提供了CPP版本的SICP库 其他的为C版本的库 |
| | | #include <iostream> |
| | | #include "scpi/scpi.h" |
| | | #include "scpi/scpi-def.h" |
| | | |
| | | size_t SCPI_Write(scpi_t * context, const char * data, size_t len) { |
| | | (void) context; |
| | | std::cout.write(data, len); |
| | | return len; |
| | | } |
| | | |
| | | scpi_result_t SCPI_Flush(scpi_t * context) { |
| | | (void) context; |
| | | std::cout << std::flush; |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | int SCPI_Error(scpi_t * context, int_fast16_t err) { |
| | | (void) context; |
| | | std::cerr << "**ERROR: " << err << ", \"" << SCPI_ErrorTranslate(err) << "\"" << std::endl; |
| | | return 0; |
| | | } |
| | | |
| | | scpi_result_t SCPI_Control(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) { |
| | | (void) context; |
| | | |
| | | if (SCPI_CTRL_SRQ == ctrl) { |
| | | std::cerr << "**SRQ: 0x" << std::hex << val << "(" << std::dec << val << ")" << std::endl; |
| | | } else { |
| | | std::cerr << "**CTRL: " << std::hex << ctrl << ": 0x" << std::hex << val << "(" << std::dec << val << ")" << std::endl; |
| | | } |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | scpi_result_t SCPI_Reset(scpi_t * context) { |
| | | (void) context; |
| | | |
| | | std::cerr << "**Reset" << std::endl; |
| | | return SCPI_RES_OK; |
| | | } |
| | | |
| | | scpi_result_t SCPI_SystemCommTcpipControlQ(scpi_t * context) { |
| | | (void) context; |
| | | |
| | | return SCPI_RES_ERR; |
| | | } |
| | | |
| | | /* |
| | | * |
| | | */ |
| | | |
| | | int t_main(int argc, char** argv) { |
| | | (void) argc; |
| | | (void) argv; |
| | | |
| | | // SCPI_Init(&scpi_context, |
| | | // myscpi_commands, |
| | | // &scpi_interface, |
| | | // scpi_units_def, |
| | | // SCPI_IDN1, SCPI_IDN2, SCPI_IDN3, SCPI_IDN4, |
| | | // scpi_input_buffer, SCPI_INPUT_BUFFER_LENGTH, |
| | | // scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE); |
| | | |
| | | // std::cerr << "SCPI Interactive demo" << std::endl; |
| | | |
| | | // while (1) { |
| | | // char ch = std::cin.get(); |
| | | // SCPI_Input(&scpi_context, &ch, 1); |
| | | // } |
| | | |
| | | |
| | | return (EXIT_SUCCESS); |
| | | } |
| | | |
| | |
| | | #include "scpi/utils.h" |
| | | #include "scpi/error.h" |
| | | #include "lexer_private.h" |
| | | #include "scpi/types.h" |
| | | |
| | | |
| | | /* |
| | |
| | | /* |
| | | * units definition IEEE 488.2-1992 tab 7-1 |
| | | */ |
| | | |
| | | |
| | | /* |
| | | scpi_units_def 是单位定义表 提供单位转换 |
| | | 拓展单位在此处添加 |
| | | */ |
| | | |
| | | const scpi_unit_def_t scpi_units_def[] = { |
| | | #if USE_UNITS_PARTICLES |
| | | /* Absorbet dose */ |
| | |
| | | /* |
| | | * Special number values definition |
| | | */ |
| | | |
| | | |
| | | //特殊数值定义 |
| | | const scpi_choice_def_t scpi_special_numbers_def[] = { |
| | | {/* name */ "MINimum", /* type */ SCPI_NUM_MIN}, |
| | | {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX}, |
| | |
| | | * |
| | | * prev and current should be in the same memory buffer |
| | | */ |
| | | |
| | | //组合复合SCPI命令 |
| | | scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) { |
| | | size_t i; |
| | | |
| | |
| | | return TRUE; |
| | | |
| | | /* Common command or command root - nothing to do */ |
| | | // 当前命令是公共命令(*)或根命令(:) |
| | | if (current->ptr[0] == '*' || current->ptr[0] == ':') |
| | | return TRUE; |
| | | |
| | |
| | | |
| | | current->ptr -= i; |
| | | current->len += i; |
| | | //复合命令组合 |
| | | memmove(current->ptr, prev->ptr, i); |
| | | return TRUE; |
| | | } |
| | |
| | | #if USE_MEMORY_ALLOCATION_FREE && !HAVE_STRNDUP |
| | | char *OUR_strndup(const char *s, size_t n) { |
| | | size_t len = SCPIDEFINE_strnlen(s, n); |
| | | char * result = malloc(len + 1); |
| | | //msvc下需要强转 |
| | | char * result =(char*) malloc(len + 1); |
| | | if (!result) { |
| | | return NULL; |
| | | } |
| | |
| | | #define SCPI_UTILS_PRIVATE_H |
| | | |
| | | #include <stdint.h> |
| | | #include "scpi/config.h" |
| | | #include "scpi/types.h" |
| | | #include<scpi/config.h> |
| | | #include<scpi/types.h> |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |