nancy.liao
2025-04-15 4c11ea0639b923a171e72a47b8006734ba184b3e
同步修改前的原SCPI库
19个文件已修改
3个文件已添加
10个文件已删除
1807 ■■■■■ 已修改文件
CMakeLists.txt 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/common-cxx/scpi-def.cpp 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/common-cxx/scpi-def.h 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/common/scpi-def.c 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/common/scpi-def.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-CVI_w_GUI/.gitignore 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-CVI_w_GUI/TestLibSCPI_GUI.prj 676 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-CVI_w_GUI/TestLibscpi.uir 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-interactive-cxx/Makefile 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-interactive-cxx/main.cpp 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-interactive/Makefile 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-parser/Makefile 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-tcp-srq/Makefile 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-tcp/Makefile 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-tcp/main.c 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/test-vxi11/Makefile 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/ieee488.h 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/parser.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/scpi-def.h 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/types.h 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/units.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/error.c 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/fifo_private.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/ieee488.c 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/lexer.c 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/parser.c 91 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/scpi-def.c 424 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/scpi.g 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/test-interactive.cpp 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/units.c 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/utils.c 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/utils_private.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CMakeLists.txt
@@ -4,7 +4,15 @@
file(GLOB_RECURSE SRC_FILES
    libscpi/inc/*.h
    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})
@@ -12,6 +20,14 @@
    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})
@@ -26,19 +42,4 @@
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()
examples/common-cxx/scpi-def.cpp
@@ -338,6 +338,12 @@
    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?
 *
@@ -352,7 +358,10 @@
    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},
@@ -368,20 +377,15 @@
    {"*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},
examples/common-cxx/scpi-def.h
@@ -32,6 +32,18 @@
#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"
examples/common/scpi-def.c
@@ -407,7 +407,6 @@
    {.pattern = "TEST:TEXT", .callback = TEST_Text,},
    {.pattern = "TEST:ARBitrary?", .callback = TEST_ArbQ,},
    {.pattern = "TEST:CHANnellist", .callback = TEST_Chanlst,},
    SCPI_CMD_LIST_END
};
examples/common/scpi-def.h
@@ -36,6 +36,8 @@
#define SCPI_INPUT_BUFFER_LENGTH 256
#define SCPI_ERROR_QUEUE_SIZE 17
#define SCPI_IDN1 "MANUFACTURE"
#define SCPI_IDN2 "INSTR2013"
#define SCPI_IDN3 NULL
examples/test-CVI_w_GUI/.gitignore
File was deleted
examples/test-CVI_w_GUI/TestLibSCPI_GUI.prj
File was deleted
examples/test-CVI_w_GUI/TestLibscpi.uir
Binary files differ
examples/test-interactive-cxx/Makefile
File was deleted
examples/test-interactive-cxx/main.cpp
@@ -34,6 +34,9 @@
 *
 *
 */
//#include "../common-cxx/scpi-def.h"
 //这个版本测试用例提供了CPP版本的SICP库 其他的为C版本的库
#include <iostream>
#include "scpi/scpi.h"
#include "../common-cxx/scpi-def.h"
examples/test-interactive/Makefile
File was deleted
examples/test-parser/Makefile
File was deleted
examples/test-tcp-srq/Makefile
File was deleted
examples/test-tcp/Makefile
File was deleted
examples/test-tcp/main.c
@@ -179,6 +179,8 @@
/*
 *
 */
 //网络通信部分可以不使用标准C的socket通信,可以采用C++或者Qt的网络库进行传输
int main(int argc, char** argv) {
    (void) argc;
    (void) argv;
examples/test-vxi11/Makefile
File was deleted
libscpi/inc/scpi/ieee488.h
@@ -53,6 +53,8 @@
    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);
libscpi/inc/scpi/parser.h
@@ -40,6 +40,16 @@
#include <string.h>
#include "scpi/types.h"
/*这个类提供了接口实现 主要为  SCPI_Init 和  SCPI_Input
SCPI_Init为SCPI的初始化 提供了一个全局的context使用 用法固定
SCPI_Input为输入命令 其中内部包含了解析参数
接口函数的实现都在 parser.c文件内
*/
#ifdef __cplusplus
extern "C" {
libscpi/inc/scpi/scpi-def.h
New file
@@ -0,0 +1,65 @@
/*-
 * 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_ */
libscpi/inc/scpi/types.h
@@ -40,8 +40,7 @@
#include <stddef.h>
#include <stdint.h>
#include "scpi/config.h"
#include <scpi/config.h>
#if HAVE_STDBOOL
#include <stdbool.h>
#endif
@@ -422,23 +421,39 @@
    };
    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;
    };
libscpi/inc/scpi/units.h
@@ -49,7 +49,6 @@
    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
libscpi/src/error.c
@@ -36,11 +36,11 @@
#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)
libscpi/src/fifo_private.h
@@ -38,7 +38,7 @@
#ifndef SCPI_FIFO_H
#define    SCPI_FIFO_H
#include "scpi/types.h"
#include  <scpi/types.h>
#include "utils_private.h"
#ifdef    __cplusplus
libscpi/src/ieee488.c
@@ -38,8 +38,6 @@
#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] = {
@@ -280,7 +278,8 @@
 * @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);
@@ -422,3 +421,15 @@
    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;
}
libscpi/src/lexer.c
@@ -342,6 +342,8 @@
    }
    return token->len;
}
/* 7.6.1 <COMMAND PROGRAM HEADER> */
@@ -403,12 +405,23 @@
 * @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;
@@ -418,6 +431,8 @@
    } 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) {
@@ -430,7 +445,7 @@
            token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER;
        }
    }
    // 计算长度
    if (token->type != SCPI_TOKEN_UNKNOWN) {
        token->len = state->pos - token->ptr;
    } else {
libscpi/src/parser.c
@@ -123,23 +123,28 @@
 * 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) {
@@ -158,6 +163,7 @@
    }
    /* 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;
@@ -192,6 +198,15 @@
 * @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;
@@ -202,20 +217,25 @@
        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;
@@ -224,10 +244,11 @@
                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;
@@ -247,6 +268,7 @@
    }
    /* conditionally write new line */
    //解析完毕以后等待下一条指令的输入
    writeNewLine(context);
    return result;
@@ -257,7 +279,9 @@
 * @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
@@ -279,6 +303,7 @@
    context->interface = interface;
    context->units = units;
    context->idn[0] = idn1;
    context->idn[1] = idn2;
    context->idn[2] = idn3;
    context->idn[3] = idn4;
@@ -296,7 +321,9 @@
 * @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);
@@ -313,19 +340,32 @@
 * @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;
@@ -339,9 +379,10 @@
        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);
@@ -448,6 +489,7 @@
 */
size_t SCPI_ResultInt32(scpi_t * context, int32_t val) {
    return resultUInt32BaseSign(context, val, 10, TRUE);
}
/**
@@ -1435,25 +1477,36 @@
 * @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);
    }
@@ -1461,15 +1514,17 @@
    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) {
libscpi/src/scpi-def.c
New file
@@ -0,0 +1,424 @@
/*-
 * 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, &param1, FALSE)) {
        /* do something, if parameter not present */
    }
    /* read second paraeter if present */
    if (!SCPI_ParamNumber(context, scpi_special_numbers_def, &param2, FALSE)) {
        /* do something, if parameter not present */
    }
    SCPI_NumberToStr(context, scpi_special_numbers_def, &param1, bf, 15);
    fprintf(stderr, "\tP1=%s\r\n", bf);
    SCPI_NumberToStr(context, scpi_special_numbers_def, &param2, 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, &param1, FALSE)) {
        /* do something, if parameter not present */
    }
    /* read second paraeter if present */
    if (!SCPI_ParamNumber(context, scpi_special_numbers_def, &param2, FALSE)) {
        /* do something, if parameter not present */
    }
    SCPI_NumberToStr(context, scpi_special_numbers_def, &param1, bf, 15);
    fprintf(stderr, "\tP1=%s\r\n", bf);
    SCPI_NumberToStr(context, scpi_special_numbers_def, &param2, 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, &param1, TRUE)) {
        return SCPI_RES_ERR;
    }
    /* read second paraeter if present */
    if (!SCPI_ParamDouble(context, &param2, 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, &param1, 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, &param, 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), &copy_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;
libscpi/src/scpi.g
File was deleted
libscpi/src/test-interactive.cpp
New file
@@ -0,0 +1,111 @@
/*-
 * 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);
}
libscpi/src/units.c
@@ -42,6 +42,7 @@
#include "scpi/utils.h"
#include "scpi/error.h"
#include "lexer_private.h"
#include "scpi/types.h"
/*
@@ -63,6 +64,13 @@
/*
 * 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 */
@@ -273,6 +281,9 @@
/*
 * 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},
libscpi/src/utils.c
@@ -675,6 +675,8 @@
 *
 * 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;
@@ -687,6 +689,7 @@
        return TRUE;
    /* Common command or command root - nothing to do */
    // 当前命令是公共命令(*)或根命令(:)
    if (current->ptr[0] == '*' || current->ptr[0] == ':')
        return TRUE;
@@ -707,6 +710,7 @@
    current->ptr -= i;
    current->len += i;
    //复合命令组合
    memmove(current->ptr, prev->ptr, i);
    return TRUE;
}
@@ -754,7 +758,8 @@
#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;
    }
libscpi/src/utils_private.h
@@ -39,8 +39,8 @@
#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" {