Browse Source

V.1
1、添加完成了部分的示波器控制功能,但是目前还无法打开示波器读取数据

Apple 5 tháng trước cách đây
commit
24e3586f74

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+External

+ 163 - 0
CMakeLists.txt

@@ -0,0 +1,163 @@
+cmake_minimum_required(VERSION 3.12)
+
+
+project(OSC_Software VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+
+
+#=========================================================
+#********************  指定Qt安装路径 ********************
+#=========================================================
+# option(QT_5.12.12 "使用Qt5.12.12" OFF)
+
+# if(QT_5.12.12)
+#     if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+#         set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.12/5.12.12/mingw73_64")
+#     elseif(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+#         set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.12/5.12.12/msvc2017_64/bin")
+#     endif()
+# endif()
+
+#=========================================================
+#*************  设置可执行文件的名称和输出位置 *************
+#=========================================================
+
+
+
+
+#设置可执行文件和库位置,可能是qt tools的bug,选择32位依旧是64位编译器
+if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+    message(STATUS "Using Linux System")
+    if(CMAKE_BUILD_TYPE MATCHES Debug)
+        set(exec_out_path ${CMAKE_SOURCE_DIR}/../bin_Debug)
+        set(BUILD_LIB_PATH ${CMAKE_SOURCE_DIR}/../bin_Debug)
+    elseif(CMAKE_BUILD_TYPE MATCHES Release)
+        set(exec_out_path ${CMAKE_SOURCE_DIR}/../bin_Release)
+        set(BUILD_LIB_PATH ${CMAKE_SOURCE_DIR}/../bin_Release)
+    endif()
+elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
+    message(STATUS "Using Windows System")
+    if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+        message(STATUS "Using Compiler : ${CMAKE_CXX_COMPILER_ID}")
+        #设置日志库的位置,判断32位和64位,CMAKE_CL_64已经被废弃
+        if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+            message(STATUS "Using 64bit Compiler")
+            #设置可执行文件输出位置
+            set(exec_out_path ${CMAKE_SOURCE_DIR}/../../bin_GNU_64)
+            #设置库生成位置
+            set(BUILD_LIB_PATH ${CMAKE_SOURCE_DIR}/../../bin_GNU_64)
+        elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
+            message(STATUS "Using 32bit Compiler")
+            #设置可执行文件输出位置
+            set(exec_out_path ${CMAKE_SOURCE_DIR}/../../bin_GNU_32)
+            #设置库生成位置
+            set(BUILD_LIB_PATH ${CMAKE_SOURCE_DIR}/../../bin_GNU_32)
+        endif()
+        if(CMAKE_BUILD_TYPE MATCHES Debug)
+            message(STATUS "编译类型:${CMAKE_BUILD_TYPE}")
+        else()
+            message(STATUS "编译类型:${CMAKE_BUILD_TYPE}")
+        endif()
+    elseif(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+        #不支持MSVC
+        # message(FATAL_ERROR "MSVC is not supported")
+        #设置可执行文件输出位置
+        set(exec_out_path ${CMAKE_SOURCE_DIR}/../bin_MSVC)
+        #设置库生成位置
+        set(BUILD_LIB_PATH ${CMAKE_SOURCE_DIR}/../bin_MSVC)
+    endif()
+endif()
+
+#设置库和可执行文件的输出位置
+set(EXECUTABLE_OUTPUT_PATH ${exec_out_path})
+set(LIBRARY_OUTPUT_PATH ${exec_out_path})
+
+#指定库的位置,方便寻找
+link_directories(${BUILD_LIB_PATH})
+
+#=======================================================
+#***************    启用一些模块和选项    ***************
+#=======================================================
+
+#设置MSVC的一些编译属性
+if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+    #设置MSVC使用UTF-8
+    # add_compile_options(
+    #   "$<$<CXX_COMPILER_ID:MSVC>:/source-charset:utf-8>"
+    #   "$<$<CXX_COMPILER_ID:MSVC>:/execution-charset:utf-8>"
+    # )
+    #消除MSVC对SPDLOG的兼容性警告
+    add_compile_definitions("_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING")
+endif()
+
+#添加一些gcc的编译属性
+if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+#    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
+#    #添加编译参数,这个参数会应用到全局,C和C++都会生效
+#    add_compile_options(-Wall -O2)
+endif()
+
+
+#定义一些宏
+if(CMAKE_BUILD_TYPE MATCHES Debug)
+    add_compile_definitions(C_DEBUG)
+elseif(CMAKE_BUILD_TYPE MATCHES Release)
+    add_compile_definitions(C_RELEASE)
+endif()
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    option(ENABLE_SPDLOG_STATIC_LIB "使用SPDLOG静态库" OFF)
+elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
+
+endif()
+
+#需要定义这个宏,才会使用编译好的动态库
+add_compile_definitions(SPDLOG_COMPILED_LIB)
+
+#给spdlog添加宏定义,使其支持%#等源文件相关的标志,其实就是设置日志级别
+add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE)
+
+#=========================================================
+#*******************  搜索库添加库 ***********************
+#=========================================================
+
+find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
+# find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
+
+find_package(Qt5 COMPONENTS
+    Widgets
+    Core
+    Network
+    Sql
+    REQUIRED
+)
+
+#包含外部通用库
+include(${CMAKE_SOURCE_DIR}/External/Libraries/Libraries.cmake)
+
+
+#=========================================================
+#*****************  添加头文件和源文件 ********************
+#=========================================================
+
+#包含源文件
+file(GLOB GLOBAL_SRC
+)
+
+
+#=========================================================
+#*******************  生成可执行文件 *********************
+#=========================================================
+
+
+add_subdirectory(EyeMap)
+
+
+

+ 98 - 0
Common/LHLog/LHLogInit.cpp

@@ -0,0 +1,98 @@
+#include "LHLogInit.h"
+
+#include "spdlog/spdlog.h"
+#include "spdlog/sinks/stdout_color_sinks.h"
+#include "LHLog_file_sink.h"
+
+
+#include <string>
+#include <QApplication>
+
+
+/* 初始化spdlog,输入的是模组名称,可以为空
+ * lhQLog是一个全局函数,在库LHQLog中定义
+ * 这里获取可执行文件文件夹的路径,使用的是C++17新引入的特性
+ * GCC9会在标准库中,GCC8.3需要手动链接库stdc++fs才可以使用
+ */
+
+void initLog(QString ModuleName, CLHQLogApi& lhQLog)
+{
+
+    try 
+    {
+        /* 创建一个文件sink,每天一个,00:00创建新的 */
+        // auto sink_file = std::make_shared<spdlog::sinks::daily_file_sink_mt>("FlowChartLog/log.txt",0,0);
+        /* 自定义的sink */
+        // std::filesystem::path execPath = std::filesystem::current_path();
+        std::string execPath = QApplication::applicationDirPath().toStdString();
+    #if defined(Q_OS_WIN32)
+        #if C_DEBUG
+            std::string libName = execPath + "/LHQLogd.dll";
+        #elif C_RELEASE
+            std::string libName = execPath + "/LHQLog.dll";
+        #endif
+    #elif defined(Q_OS_LINUX)
+        std::string libName = execPath + "/libLHQLog.so";
+    #endif
+        
+        /* 给默认记录器用的sink */
+        auto sink_default = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
+        /* 创建一个控制台sink */
+        auto sink_consolse = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
+        /* 创建写入文件的sink */
+        auto sink_LHLog = std::make_shared<spdlog::sinks::LHLog_file_sink_mt>(&lhQLog, QString(libName.c_str()), ModuleName);
+ 
+        /* 修改输出格式 */
+        #if C_DEBUG
+            sink_consolse->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n] [%s %#] %v %$");
+            // sink_file->set_pattern("[%Y-%m-%d %H:%M:%S:%e] [%^%n%$] [%^%l%$] %s %#: %v");
+            sink_LHLog->set_pattern("%v");
+            sink_default->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e:%e] [%l] [%s %#] %v %$");
+        #elif C_RELEASE
+            sink_consolse->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n] %v %$");
+            // sink_file->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n]: %v %$");
+            sink_LHLog->set_pattern("%v");
+            sink_default->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] %v %$");
+        #endif
+
+        /* 日志输出方向,终端和文件 */
+        std::vector<spdlog::sink_ptr> sinks;
+        sinks.push_back(sink_consolse);
+        // sinks.push_back(sink_file);
+        sinks.push_back(sink_LHLog);
+
+        /* 设置默认日志记录器,设置成自定义的sink */
+        spdlog::default_logger()->sinks().clear();
+        spdlog::default_logger()->sinks().push_back(sink_default);
+        spdlog::default_logger()->sinks().push_back(sink_LHLog);
+
+        /* 创建一个标准输出 */
+        auto logger_main = std::make_shared<spdlog::logger>("main",begin(sinks),end(sinks));
+        /* 创建一个WebAPI logger */
+        auto logger_WebAPI = std::make_shared<spdlog::logger>("WebAPI",begin(sinks),end(sinks));
+
+
+        /* 注册到注册表 */
+        spdlog::register_logger(logger_main);
+        spdlog::register_logger(logger_WebAPI);
+
+        /* 设置spdlog输出级别,默认的估计不输出debug这个级别
+         * 这是默认的设置,可以在外面单数设置输出方式
+         * release模式下不输出console的日志输出
+         * */
+#if  defined (C_DEBUG)
+        spdlog::set_level(spdlog::level::trace);
+        spdlog::flush_on(spdlog::level::trace);
+#elif defined(C_RELEASE)
+        spdlog::set_level(spdlog::level::info);             /* 只输出info以上的输出 */
+        spdlog::flush_on(spdlog::level::info);              /* 设置刷新等级 */
+        sink_consolse->set_level(spdlog::level::info);       /* 控制台不输出 */
+        sink_default->set_level(spdlog::level::info);        /* 默认sink也不输出 */
+#endif
+
+//    SPDLOG_LOGGER_DEBUG(logger_main,"******* 有行号且debug也能输出 *******");
+    }
+    catch (const spdlog::spdlog_ex& ex) {
+        qDebug() << "Log initialization failed: " << ex.what() ;
+    }
+}

+ 11 - 0
Common/LHLog/LHLogInit.h

@@ -0,0 +1,11 @@
+#ifndef LHLOGINIT_H
+#define LHLOGINIT_H
+
+class QString;
+class CLHQLogApi;
+
+void initLog(QString ModuleName, CLHQLogApi& lhQLog);
+
+
+
+#endif /* LHLOGINIT_H */

+ 67 - 0
Common/Logs/loginit.cpp

@@ -0,0 +1,67 @@
+#include "loginit.h"
+
+#include "spdlog/spdlog.h"
+#include "spdlog/sinks/stdout_color_sinks.h"
+#include "spdlog/sinks/daily_file_sink.h"
+
+// #include "fmt/base.h"
+
+/* 初始化spdlog */
+void init_log()
+{
+    try 
+    {
+        /* 给默认记录器用的sink */
+        auto sink_default = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
+        /* 创建一个控制台sink */
+        auto sink_consolse = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
+        /* 创建一个文件sink,每天一个,00:00创建新的 */
+        auto sink_file = std::make_shared<spdlog::sinks::daily_file_sink_mt>("log/EyeMap.txt", 0, 0);
+        /* 修改输出格式 */
+        #if C_DEBUG
+            sink_default->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%s %#] %v %$");
+            sink_consolse->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n] [%s %#] %v%$");
+            sink_file->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n] [%s %#] %v %$");
+        #elif C_RELEASE
+            sink_default->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] %v %$");
+            sink_consolse->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n] %v %$");
+            sink_file->set_pattern("%^[%Y-%m-%d %H:%M:%S:%e] [%l] [%n] %v %$");
+        #endif
+
+        /* 设置默认日志记录器,设置成自定义的sink */
+        spdlog::default_logger()->sinks().clear();
+        spdlog::default_logger()->sinks().push_back(sink_default);
+        /* 创建sink数组 */
+        std::vector<spdlog::sink_ptr> sinks;
+        sinks.push_back(sink_consolse);
+        sinks.push_back(sink_file);
+
+        /* 创建一个标准输出 */
+        auto logger_main = std::make_shared<spdlog::logger>("main",begin(sinks),end(sinks));
+        /* 创建一个OSC输出Logger */
+        auto logger_OSC = std::make_shared<spdlog::logger>("OSC",begin(sinks),end(sinks));
+        /* 创建一个OscData输出Logger */
+        auto logger_OscData = std::make_shared<spdlog::logger>("OscData",begin(sinks),end(sinks));
+
+        /* 注册到注册表 */
+        spdlog::register_logger(logger_main);
+        spdlog::register_logger(logger_OSC);
+        spdlog::register_logger(logger_OscData);
+
+        /* 设置spdlog输出级别,默认的估计不输出debug这个级别 */
+#ifdef C_DEBUG
+        spdlog::set_level(spdlog::level::trace);
+        spdlog::flush_on(spdlog::level::trace);
+#elif C_RELEASE
+        spdlog::set_level(spdlog::level::info);
+        spdlog::flush_on(spdlog::level::info);
+#endif
+
+
+
+    //    SPDLOG_LOGGER_DEBUG(logger_main,"******* 有行号且debug也能输出 *******");
+    }  catch (const spdlog::spdlog_ex& ex) {
+        fmt::print("Log initialization failed: %s\n", ex.what());
+    }
+}
+

+ 8 - 0
Common/Logs/loginit.h

@@ -0,0 +1,8 @@
+
+
+#ifndef LOGINIT_H
+#define LOGINIT_H
+
+void init_log();
+
+#endif /* LOGINIT_H */

+ 54 - 0
EyeMap/CMakeLists.txt

@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 3.12)
+
+#设置可执行文件名称
+set(execName1 EyeMap)
+
+#包含源文件
+file(GLOB LOCAL_SRC
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
+
+    ${CMAKE_SOURCE_DIR}/External/common/Thread/*.cpp
+    ${CMAKE_SOURCE_DIR}/External/common/ThreadPool/*.cpp
+    ${CMAKE_SOURCE_DIR}/Common/Logs/*.cpp
+
+    ${CMAKE_SOURCE_DIR}/USBInterFace/*.cpp
+    
+    # ${LHQLog_SOURCE_DIRS}/*.cpp
+)
+
+#生成可执行程序
+add_executable(${execName1} ${LOCAL_SRC})
+
+
+#添加头文件
+target_include_directories(${execName1} PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_SOURCE_DIR}/External/common
+    ${CMAKE_SOURCE_DIR}/Common/Logs
+
+    ${CMAKE_SOURCE_DIR}/USBInterFace
+    ${CMAKE_SOURCE_DIR}/GlobalInfo
+
+    # ${LHQLog_INCLUDE_DIRS}
+)
+#链接Qt库
+target_link_libraries(${execName1} PRIVATE
+    Qt5::Widgets
+    Qt5::Core
+    Qt5::Network
+    Qt5::Sql
+)
+#链接外部库
+target_link_libraries(${execName1} PRIVATE
+    fmt::fmt
+    spdlog::spdlog
+)
+
+#连接stdc++fs库,如果编译器版本低于GCC9.0,则需要连接这个库
+#GCC9.0以上包含进了标准库
+# if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+#     if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
+#         target_link_libraries(${execName1} PRIVATE stdc++fs)
+#     endif()
+# endif()

+ 189 - 0
EyeMap/OscData.cpp

@@ -0,0 +1,189 @@
+#include "OscData.h"
+#include <QApplication>
+#include "ThreadPool/ThreadPool.h"
+
+
+OscData::OscData()
+{
+    m_logger = spdlog::get("OscData");
+    if(m_logger == nullptr)
+    {
+        SPDLOG_ERROR("获取 OSC logger 失败");
+        return;
+    }
+    m_usbInterface = std::make_shared<USBInterface>();
+    if(!m_usbInterface->loadLib(QApplication::applicationDirPath()))
+    {
+        return;
+    }
+    /* 分配缓冲区内存 */
+    m_buffer = new unsigned char[BUFFER_SIZE];
+}
+
+
+OscData::~OscData()
+{
+    if(m_buffer != nullptr)
+    {
+        delete[] m_buffer;
+        m_buffer = nullptr;
+    }
+}
+
+/* 打开示波器 */
+bool OscData::openOSC()
+{
+    /* 指定示波器设备型号,OSCA02是6 */
+    m_usbInterface->specifyDevId(6);
+    auto ret = m_usbInterface->devOpen();
+    if(ret != 0)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "打开示波器失败!");
+        return false;
+    }
+    /* 设置缓冲区大小 */
+    m_usbInterface->setInfo(BUFFER_SIZE);
+    /* 获取缓冲区首指针 */
+    m_buffer = m_usbInterface->bufferWR(-1);
+    if(m_buffer == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "获取缓冲区指针失败!");
+        return false;
+    }
+
+    return true;
+}
+
+/* 关闭示波器 */
+void OscData::closeOSC()
+{
+    if(m_runCapture)
+    {
+        stopCapture();
+    }
+    while (m_isRunCapture)
+    {
+        std::this_thread::sleep_for(std::chrono::milliseconds(5));
+    }
+    if(m_usbInterface != nullptr)
+    {
+        m_usbInterface->devClose();
+    }
+}
+
+/* 开始采集数据 */
+bool OscData::startCapture()
+{
+    if(m_buffer == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "缓冲区指针为空!");
+        return false;
+    }
+    /* 启动子线程 */
+    m_runCapture = true;
+    CPPTP.add_task(&OscData::threadCaptureData, this);
+    return true;
+}
+
+/* 停止采集数据 */
+void OscData::stopCapture()
+{
+    m_runCapture = false;
+}
+
+/* 设置示波器的采样率 */
+void OscData::setSampleRate(OscSampleRate rate)
+{
+    if(m_usbInterface == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "USBInterface指针为空!");
+        return;
+    }
+    m_ctrlByte0 &= 0xf0;
+    if(rate == OscSampleRate::SR_49KHZ)
+    {
+        m_ctrlByte0 |= 0x0e;
+    }
+    else if(rate == OscSampleRate::SR_96KHZ)
+    {
+        m_ctrlByte0 |= 0x04;
+    }
+    else if(rate == OscSampleRate::SR_781KHZ)
+    {
+        m_ctrlByte0 |= 0x0c;
+    }
+    else if(rate == OscSampleRate::SR_12_5MHZ)
+    {
+        m_ctrlByte0 |= 0x08;
+    }
+    else if(rate == OscSampleRate::SR_100MHZ)
+    {
+        m_ctrlByte0 |= 0x00;
+    }
+    else
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "采样率设置错误!");
+        return;
+    }
+    m_usbInterface->usbCtrlTrans(0x94, m_ctrlByte0);
+}
+
+/**
+ * @brief 将示波器两个通道合并为一个通道
+ *        将AB两个通道的资源全部给A,B通道失效,A通道的采样率和带宽翻倍
+ * @param merge 是否合并
+ */
+void OscData::setChannelMerge(bool merge)
+{
+    if(m_usbInterface == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "USBInterface指针为空!");
+        return;
+    }
+    if(merge)
+    {
+        m_ctrlByte1 |= 0x80;
+    }else {
+        m_ctrlByte1 &= 0x7f;
+    }
+    m_usbInterface->usbCtrlTrans(0x24, m_ctrlByte1);
+}
+
+
+/**
+ * @brief 采集数据,这个是子线程 
+ * 
+ */
+void OscData::threadCaptureData()
+{
+    SPDLOG_LOGGER_INFO(m_logger, "开始采集数据线程");
+    m_isRunCapture = true;
+    uint64_t count = 0;
+    while(m_runCapture)
+    {
+        /* 开始采集数据 */
+        m_usbInterface->usbCtrlTransSimple(0x33);
+        /* 查询数据是否采集完成(应该是填充满128KB的SRAM) */
+        while(m_usbInterface->usbCtrlTransSimple(0x50) != 0x33)
+        {
+            std::this_thread::sleep_for(std::chrono::microseconds(10));
+        }
+        /* 将数据从示波器的SRAM中拷贝到电脑内存中,1次传输完成,设置超时时间1ms */
+        m_usbInterface->readBulkData(BUFFER_SIZE, 1, 1, m_devBuffer);
+        /* 等待传输完成 */
+        auto ret = m_usbInterface->eventCheck(100);
+        if(ret == 0x555)
+        {
+            SPDLOG_LOGGER_ERROR(m_logger, "数据传输超时!");
+            continue;
+        }
+        /* 取出数据 */
+        std::memcpy(m_buffer, m_devBuffer, BUFFER_SIZE);
+        /* 清空缓冲区 */
+        m_usbInterface->resetPipe();
+        SPDLOG_LOGGER_DEBUG(m_logger, "第 {} 次采集数据完成", count++);
+    }
+    m_isRunCapture = false;
+}
+
+

+ 53 - 0
EyeMap/OscData.h

@@ -0,0 +1,53 @@
+#ifndef _OSCDATA_H_
+#define _OSCDATA_H_
+
+#include <QObject>
+#include "USBInterFace.h"
+#include "spdlog/spdlog.h"
+#include "GlobalInfo.h"
+
+class OscData : public QObject
+{
+    Q_OBJECT
+
+const uint32_t BUFFER_SIZE = 1024 * 128;    /* 缓冲区大小,OSCA02的缓冲区应该是128KB的SRAM */
+
+public:
+    OscData();
+    ~OscData();
+
+    /* 打开示波器 */
+    bool openOSC();
+    /* 关闭示波器 */
+    void closeOSC();
+    /* 开始采集数据 */
+    bool startCapture();
+    /* 停止采集数据 */
+    void stopCapture();
+
+    /***** 设置示波器的功能命令 *****/
+    /* 设置示波器的采样率 */
+    void setSampleRate(OscSampleRate rate);
+    /* 将示波器两个通道合并为一个通道 */
+    void setChannelMerge(bool merge);
+    /* 设置通道A输入量程 */
+    void setChannelARange(unsigned char range);
+
+private:
+    /* 采集数据,这个是子线程 */
+    void threadCaptureData();
+
+private:
+    std::shared_ptr<spdlog::logger> m_logger = nullptr;
+    std::shared_ptr<USBInterface> m_usbInterface = nullptr;
+    bool m_runCapture = false;                  /* 采集数据的线程标志 */
+    bool m_isRunCapture = false;                /* 采集数据的线程运行标志,这个标志位作为线程运行的标志 */
+    unsigned char* m_devBuffer = nullptr;       /* 设备缓冲区指针,拷贝数据用的 */
+    unsigned char* m_buffer = nullptr;          /* 缓冲区指针,用于存储拷贝出来的数据 */
+    unsigned char m_ctrlByte0 = 0;              /* 控制字节0 */
+    unsigned char m_ctrlByte1 = 0;              /* 控制字节1 */
+};
+
+
+
+#endif /* _OSCDATA_H_ */

+ 33 - 0
EyeMap/eyemap.cpp

@@ -0,0 +1,33 @@
+#include "eyemap.h"
+#include "ui_eyemap.h"
+#include <QApplication>
+
+EyeMap::EyeMap(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::EyeMap)
+{
+    ui->setupUi(this);
+    m_logger = spdlog::get("OSC");
+    if(m_logger == nullptr)
+    {
+        SPDLOG_ERROR("获取 OSC logger 失败");
+        return;
+    }
+
+    SPDLOG_LOGGER_INFO(m_logger, "EyeMap 初始化成功");
+    if(m_oscData.openOSC())
+    {
+        SPDLOG_LOGGER_INFO(m_logger, "打开示波器成功");
+    } else {
+        SPDLOG_LOGGER_ERROR(m_logger, "打开示波器失败");
+        return;
+    }
+    
+    m_oscData.startCapture();
+}
+
+EyeMap::~EyeMap()
+{
+    delete ui;
+}
+

+ 30 - 0
EyeMap/eyemap.h

@@ -0,0 +1,30 @@
+#ifndef EYEMAP_H
+#define EYEMAP_H
+
+#include <QWidget>
+#include <memory>
+
+#include "spdlog/spdlog.h"
+
+#include "OscData.h"
+
+namespace Ui {
+class EyeMap;
+}
+
+class EyeMap : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit EyeMap(QWidget *parent = nullptr);
+    ~EyeMap();
+
+
+private:
+    Ui::EyeMap *ui;
+    std::shared_ptr<spdlog::logger> m_logger = nullptr;
+    OscData m_oscData;
+};
+
+#endif // EYEMAP_H

+ 19 - 0
EyeMap/eyemap.ui

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EyeMap</class>
+ <widget class="QWidget" name="EyeMap">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1024</width>
+    <height>776</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 28 - 0
EyeMap/main.cpp

@@ -0,0 +1,28 @@
+
+#include "spdlog/spdlog.h"
+#include "logs/loginit.h"
+#include <QApplication>
+#include "eyemap.h"
+
+
+int main(int argc, char* argv[])
+{
+    QApplication app(argc, argv);
+    /* 初始化日志库 */
+    init_log();
+    auto logger = spdlog::get("main");
+    if(logger == nullptr)
+    {
+        SPDLOG_ERROR("main logger is nullptr");
+        return -1;
+    }
+    SPDLOG_LOGGER_INFO(logger, "★  ★  ★   Oscilloscope   ★  ★  ★");
+
+    EyeMap w;
+    w.show();
+
+    return app.exec();
+}
+
+
+

+ 27 - 0
GlobalInfo/GlobalInfo.h

@@ -0,0 +1,27 @@
+#ifndef GLOBALINFO_H
+#define GLOBALINFO_H
+
+/* 示波器采样率,目前就只要这些 */
+enum class OscSampleRate
+{
+    SR_49KHZ = 0,
+    SR_96KHZ,
+    SR_781KHZ,
+    SR_12_5MHZ,
+    SR_100MHZ,
+};
+
+/* 示波器通道的输入量程 */
+enum class OscChannelRange
+{
+    CR_100MV = 0,
+    CR_250MV,
+    CR_500MV,
+    CR_1V,
+    CR_2V5,
+    CR_5V,
+    CR_8V,
+};
+
+
+#endif /* GLOBALINFO_H */

+ 283 - 0
USBInterFace/USBInterFace.cpp

@@ -0,0 +1,283 @@
+#include "USBInterFace.h"
+#include "spdlog/spdlog.h"
+
+
+USBInterface::USBInterface()
+{
+
+}
+
+/**
+ * @brief 加载动态库
+ * 
+ * @param libPath 动态库所在的文件夹
+ * @return true 
+ * @return false 
+ */
+bool USBInterface::loadLib(const QString& libPath)
+{
+    if(libPath.isEmpty())
+    {
+        return false;
+    }
+    QString libName = libPath + "/USBInterFace.dll";
+    
+    if(m_lib.isLoaded())
+    {
+        m_lib.unload();
+    }
+    m_lib.setFileName(libName);
+    if(!m_lib.load())
+    {
+        SPDLOG_ERROR("加载 {} 失败,错误信息:{}",libName.toStdString(), m_lib.errorString().toStdString());
+        return false;
+    }
+
+    /* 获取函数 */
+    m_specifyDevID = reinterpret_cast<SpecifyDevIdx>(m_lib.resolve("SpecifyDevIdx"));
+    m_devOpen = reinterpret_cast<DeviceOpen>(m_lib.resolve("DeviceOpen"));
+    m_devOpenWithID = reinterpret_cast<DeviceOpenWithID>(m_lib.resolve("DeviceOpenWithID"));
+    m_devClose = reinterpret_cast<DeviceClose>(m_lib.resolve("DeviceClose"));
+    m_usbCtrlTransSimple = reinterpret_cast<USBCtrlTransSimple>(m_lib.resolve("USBCtrlTransSimple"));
+    m_usbCtrlTrans = reinterpret_cast<USBCtrlTrans>(m_lib.resolve("USBCtrlTrans"));
+    m_bufferWR = reinterpret_cast<BufferWR>(m_lib.resolve("GetBuffer4Wr"));
+    m_setInfo = reinterpret_cast<SetInfo>(m_lib.resolve("SetInfo"));
+    m_clearBuffer = reinterpret_cast<ClearBuffer>(m_lib.resolve("CLearBuffer"));
+    m_resetPipe = reinterpret_cast<ResetPipe>(m_lib.resolve("ResetPipe"));
+    m_aiReadBulkData = reinterpret_cast<AiReadBulkData>(m_lib.resolve("AiReadBulkData"));
+    m_eventCheck = reinterpret_cast<EventCheck>(m_lib.resolve("EventCheck"));
+
+    if(m_specifyDevID == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 SpecifyDevIdx 失败");
+        return false;
+    }
+    if(m_devOpen == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 DeviceOpen 失败");
+        return false;
+    }
+    if(m_devOpenWithID == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 DeviceOpenWithID 失败");
+        return false;
+    }
+    if(m_devClose == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 DeviceClose 失败");
+        return false;
+    }
+    if(m_usbCtrlTransSimple == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 USBCtrlTransSimple 失败");
+        return false;
+    }
+    if(m_usbCtrlTrans == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 USBCtrlTrans 失败");
+        return false;
+    }
+    if(m_bufferWR == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 bufferWR 失败");
+        return false;
+    }
+    if(m_setInfo == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 SetInfo 失败");
+        return false;
+    }
+    if(m_clearBuffer == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 ClearBuffer 失败");
+        return false;
+    }
+    if(m_resetPipe == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 ResetPipe 失败");
+        return false;
+    }
+    if(m_aiReadBulkData == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 AiReadBulkData 失败");
+        return false;
+    }
+    if(m_eventCheck == nullptr)
+    {
+        SPDLOG_ERROR("加载USBInterFace库函数 EventCheck 失败");
+        return false;
+    }
+
+
+    return true;
+}
+
+/**
+ * @brief 指定设备编号
+            OSCA02 6
+            OSC482 6
+ * 
+ * @param idx 
+ */
+void USBInterface::specifyDevId(int idx)
+{
+    if(m_specifyDevID == nullptr)
+    {
+        return;
+    }
+    m_specifyDevID(idx);
+}
+
+/**
+ * @brief 打开设备,调用该函数之前需要先设置设备编号
+ * 
+ * @return unsigned long 
+ */
+unsigned long USBInterface::devOpen()
+{
+    if(m_devOpen == nullptr)
+    {
+        return 0;
+    }
+    return m_devOpen();
+}
+
+/* 打开设备 */
+unsigned long USBInterface::devOpenWithID(int ID)
+{
+    if(m_devOpenWithID == nullptr)
+    {
+        return 0;
+    }
+    return m_devOpenWithID(ID);
+}
+
+/* 关闭设备 */
+unsigned long USBInterface::devClose()
+{
+    if(m_devClose == nullptr)
+    {
+        return 0;
+    }
+    return m_devClose();
+}
+
+/* 开始采集数据命令 */
+unsigned long USBInterface::usbCtrlTransSimple(unsigned long Request)
+{
+    if(m_usbCtrlTransSimple == nullptr)
+    {
+        return 0;
+    }
+    return m_usbCtrlTransSimple(Request);
+}
+
+/**
+ * @brief 示波器控制函数,设置示波器相关的参数
+ * 
+ * @param Request 命令码,不同的命令码代表不同的指令
+ * @param Value 命令码的参数
+ * @param outBufSize 未使用,固定传1
+ * @return unsigned char 如果是需要从示波器获取数据的命令,这个就是示波器返回的数据
+ */ 
+unsigned char USBInterface::usbCtrlTrans(unsigned char Request, unsigned short Value)
+{
+    if(m_usbCtrlTrans == nullptr)
+    {
+        return 0;
+    }
+    return m_usbCtrlTrans(Request, Value, 1);
+}
+
+/**
+ * @brief 获取缓冲区指针
+ * 
+ * @param index 双通道的型号,固定传-1
+ * @return unsigned char*
+ */
+unsigned char* USBInterface::bufferWR(int index)
+{
+    if(m_bufferWR == nullptr)
+    {
+        return nullptr;
+    }
+    return m_bufferWR(index);
+}
+
+/**
+ * @brief 设置缓冲区的大小,固定的参数直接默认传入了
+ * 
+ * @param dataNumPerPixar 固定参数传1
+ * @param CurrentFreq 固定参数传0
+ * @param ChannelMask 固定参数传0x11
+ * @param ZrroUniInt 固定参数传0
+ * @param bufferoffset 固定参数传0
+ * @param HWbufferSize 实际缓冲区的大小,这个缓冲区是AB字交替存储,所以实际大小是偶数,且不能超过缓冲区总大小20MB字节
+ */
+void USBInterface::setInfo(unsigned int  HWbufferSize)
+{
+    if(m_setInfo == nullptr)
+    {
+        return;
+    }
+    m_setInfo(1, 0, 0x11, 0, 0, HWbufferSize);
+}
+
+/* 目前不知道清空什么 */
+unsigned long USBInterface::clearBuffer(unsigned char objA , unsigned char objB, unsigned int Num)
+{
+    if(m_clearBuffer == nullptr)
+    {
+        return 0;
+    }
+    return m_clearBuffer(objA, objB, Num);
+}
+
+/* 清空缓冲区遗留的数据 */
+void USBInterface::resetPipe()
+{
+    if(m_resetPipe == nullptr)
+    {
+        return;
+    }
+    m_resetPipe();
+}
+
+/**
+ * @brief 将数据从示波器的SRAM拷贝到内存中,这个函数调用完成后会立刻返回,可以等待足够长的时间(也没说多长时间)或者
+ *        使用EventCheck函数阻塞住,直到传输完成
+ * 
+ * @param SampleCount 拷贝多少字节的电压数据,不能超过SetInfo设置的缓冲区大小
+ * @param EventNum 将SampleCount分多少次传输完成,一般设置成1即可,既1次传输完成
+ * @param TimeOut 超时时间,单位ms
+ * @param Buffer 数据缓冲区的指针,可以使用GetBuffer4Wr获取的指针
+ * @param Flag 固定传0
+ * @param First_PacketNum 固定传0
+ */
+void USBInterface::readBulkData(unsigned long SampleCount, unsigned int EventNum, unsigned long TimeOut, unsigned char* Buffer)
+{
+    if(m_aiReadBulkData == nullptr)
+    {
+        return;
+    }
+    m_aiReadBulkData(SampleCount, EventNum, TimeOut, Buffer, 0, 0);
+}
+
+/**
+ * @brief 阻塞等待数据拷贝完成,这个函数在readBulkData函数调用后使用
+ * 
+ * @param Timeout 超时时间,单位ms
+ * @return unsigned long 返回0x555,表示超时了,但是事件没有完成
+ *         返回大于等于0,表示事件完成了,如果设置的是1次事件,返回的是0
+ *         如果设置的是2次事件,第一次返回0,第二次返回1
+ */
+unsigned long USBInterface::eventCheck(long Timeout)
+{
+    if(m_eventCheck == nullptr)
+    {
+        return 0;
+    }
+    return m_eventCheck(Timeout);
+}
+
+

+ 87 - 0
USBInterFace/USBInterFace.h

@@ -0,0 +1,87 @@
+#ifndef _USBINTERFACE_H_
+#define _USBINTERFACE_H_
+
+#include <QString>
+#include <functional>
+#include <QLibrary>
+
+class USBInterface
+{
+
+/* 定义函数指针 */
+
+/* 设置产品编号,OSCA02是6 */
+using SpecifyDevIdx = void(*)(int idx);
+/* 打开设备,调用前需要先设置产品编号 */
+using DeviceOpen = unsigned long(*)();
+/* 打开指定ID的设备 */
+using DeviceOpenWithID = unsigned long(*)(int ID);
+/* 关闭设备 */
+using DeviceClose = unsigned long(*)();
+/* 开始采集数据,传入0x33开始采集 */
+using USBCtrlTransSimple = unsigned long(*)(unsigned long Request);
+/* 示波器控制 */
+using USBCtrlTrans = unsigned char(*)(unsigned char Request, unsigned short Value, unsigned long outBufSize);
+/* 读取数据 */
+using BufferWR = unsigned char*(*)(int index);
+/* 设置缓冲区大小 */
+using SetInfo = void(*)(double dataNumPerPixar, double CurrentFreq, unsigned char ChannelMask, int ZrroUniInt, unsigned int  bufferoffset, unsigned int  HWbufferSize);
+/* 不知道清空什么 */
+using ClearBuffer = unsigned long(*)(unsigned char objA , unsigned char objB, unsigned int Num);
+/* 清空缓冲区遗留的数据 */
+using ResetPipe = void(*)();
+/* 将数据从示波器的SRAM拷贝到PC内存中 */
+using AiReadBulkData = void(*)(unsigned long SampleCount, unsigned int EventNum, unsigned long TimeOut, unsigned char* Buffer, unsigned char Flag, unsigned int First_PacketNum);
+/* 阻塞等待数据拷贝完成 */
+using EventCheck = unsigned long(*)(long Timeout);
+
+
+public:
+    USBInterface();
+    /* 加载动态库 */
+    bool loadLib(const QString& libPath);
+    /* 指定设备编号 */
+    void specifyDevId(int idx);
+    /* 打开设备 */
+    unsigned long devOpen();
+    /* 打开设备,这个函数用于多个示波器级联时使用的,替代devOpen函数 */
+    unsigned long devOpenWithID(int ID);
+    /* 关闭设备 */
+    unsigned long devClose();
+    /* 开始采集数据命令 */
+    unsigned long usbCtrlTransSimple(unsigned long Request);
+    /* 示波器控制命令 */
+    unsigned char usbCtrlTrans(unsigned char Request, unsigned short Value);
+    /* 获取缓冲区指针 */
+    unsigned char* bufferWR(int index);
+    /* 设置缓冲区的大小 */
+    void setInfo( unsigned int  HWbufferSize);
+    /* 目前不知道清空什么 */
+    unsigned long clearBuffer(unsigned char objA , unsigned char objB, unsigned int Num);
+    /* 清空缓冲区遗留的数据 */
+    void resetPipe();
+    /* 将数据从示波器的SRAM拷贝到内存中 */
+    void readBulkData(unsigned long SampleCount, unsigned int EventNum, unsigned long TimeOut, unsigned char* Buffer);
+    /* 阻塞等待数据拷贝完成 */
+    unsigned long eventCheck(long Timeout);
+
+private:
+    QLibrary m_lib;
+
+    SpecifyDevIdx m_specifyDevID = nullptr;
+    DeviceOpen m_devOpen = nullptr;
+    DeviceOpenWithID m_devOpenWithID = nullptr;
+    DeviceClose m_devClose = nullptr;
+    USBCtrlTransSimple m_usbCtrlTransSimple = nullptr;
+    USBCtrlTrans m_usbCtrlTrans = nullptr;
+    BufferWR m_bufferWR = nullptr;
+    SetInfo m_setInfo = nullptr;
+    ClearBuffer m_clearBuffer = nullptr;
+    ResetPipe m_resetPipe = nullptr;
+    AiReadBulkData m_aiReadBulkData = nullptr;
+    EventCheck m_eventCheck = nullptr;
+};
+
+
+
+#endif /* USBINTERFACE_H_ */