当前位置: 首页 > news >正文

CSerialPort教程4.3.x (2) - CSerialPort源码简介

CSerialPort教程4.3.x (2) - CSerialPort源码简介

前言

CSerialPort项目是一个基于C/C++的轻量级开源跨平台串口类库,可以轻松实现跨平台多操作系统的串口读写,同时还支持C#, Java, Python, Node.js等。

CSerialPort项目的开源协议自 V3.0.0.171216 版本后采用GNU Lesser General Public License v3.0

为了让开发者更好的使用CSerialPort进行开发,特编写基于4.3.x版本的CSerialPort教程系列。

CSerialPort项目地址:

  • https://github.com/itas109/CSerialPort
  • https://gitee.com/itas109/CSerialPort

本文对CSerialPort 4.3.0版本源码进行简介。

1. CSerialPort源码目录结构

CSerialPort # root
+--- .clang-format # code format 代码规范
├── bindings # 第三方语言接口
│   ├── c # c interface c接口
│   ├── csharp # csharp interface c#接口
│   ├── java # java interface java接口
│   ├── javascript # javascript interface javascript接口
│   └── python # python interface python接口
├── CHANGELOG.md # change log 修改日志
├── cmake # cross compile 交叉编译
├── CMakeLists.txt
├── doc # document 文档
├── examples # example 示例程序
│   ├── CommMFC # CSerialPort MFC Demo MFC程序示例
│   ├── CommNoGui # CSerialPort No Gui Demo 无界面程序示例
│   ├── CommQT # CSerialPort QT Demo QT程序示例
│   ├── CommTui # CSerialPort tui Demo 文本界面程序示例
│   ├── CommWXWidgets # CSerialPort wxwidgets Demo wxwidgets界面程序示例
├── include # headers 头文件
│   └── CSerialPort
│       ├── ibuffer.hpp # lightweight cross-platform buffer library 轻量级跨平台缓冲区类
│       ├── ithread.hpp # lightweight cross-platform thread library 轻量级跨平台线程类
│       ├── itimer.hpp # lightweight cross-platform timer library 轻量级跨平台定时器类
│       ├── iutils.hpp # lightweight cross-platform utils library 轻量级跨平台工具类
│       ├── SerialPortBase.h # CSerialPort Base class 串口基类
│       ├── SerialPort_global.h # Global difine of CSerialPort 串口全局定义 
│       ├── SerialPort.h # lightweight cross-platform serial port library 轻量级跨平台串口类库
│       ├── SerialPortInfoBase.h # CSerialPortInfo Base class 串口信息辅助类基类
│       ├── SerialPortInfo.h # CSerialPortInfo class 串口信息辅助类
│       ├── SerialPortInfoUnixBase.h # CSerialPortInfo unix class unix串口信息辅助类基类
│       ├── SerialPortInfoWinBase.h # CSerialPortInfo windows class windows串口信息辅助类基类
│       ├── SerialPortListener.h # CSerialPortListener interface class 串口事件监听接口类
│       ├── SerialPortUnixBase.h # CSerialPort unix Base class unix串口基类
│       ├── SerialPort_version.h # CSerialPort version 版本定义
│       └── SerialPortWinBase.h # CSerialPort Windows Base class windows串口基类
├── lib # lib 库目录
├── LICENSE # LGPL3.0 license
├── pic # picture 图片
├── README.md
├── README_zh_CN.md
├── src # source 源代码
├── test # unit test 单元测试
└── VERSION # version 版本号

2. CSerialPort常用函数

2.1 串口信息相关函数

2.1.1 获取串口信息列表函数 availablePortInfos

该函数获取串口信息列表,主要包括:

  • 串口名称 (如COM2)
  • 描述信息 (如USB-SERIAL CH340)
  • 硬件id (如USB\VID_1A86&PID_7523&REV_0264)
static vector<SerialPortInfo> itas109::CSerialPortInfo::availablePortInfos()

2.2 串口操作相关函数

2.2.1 串口初始化函数 init

该函数用于串口初始化。

void itas109::CSerialPort::init(const char *portName,                                 // 串口名称 Windows:COM1 Linux:/dev/ttyS0int baudRate = itas109::BaudRate9600,                 // 波特率itas109::Parity parity = itas109::ParityNone,         // 校验位itas109::DataBits dataBits = itas109::DataBits8,      // 数据位itas109::StopBits stopbits = itas109::StopOne,        // 停止位itas109::FlowControl flowControl = itas109::FlowNone, // 流控制unsigned int readBufferSize = 4096                    // 读取缓冲区大小
)

注意:

  • 5位数据位不能使用2位停止位
  • 1.5位停止位不能使用5位数据位
  • POSIX系统8位数据位不能使用0校验
  • windows数据位范围为4 - 8
  • 1.5位停止位仅对windows有效
  • 停止位数字1表示StopOneAndHalf,即1.5位停止位,并非1位停止位

2.2.2 打开串口函数 open

该函数用于打开串口。

bool itas109::CSerialPort::open()

true表示打开成功,false表示打开失败。

打开失败可用itas109::CSerialPort::getLastError()获取错误码

2.2.3 关闭串口函数 close

该函数用于关闭串口。

void itas109::CSerialPort::close()

2.2.4 是否打开串口成功函数 isOpen

该函数用于获取是否打开串口成功。

bool itas109::CSerialPort::isOpen()

true表示串口打开成功,false表示串口打开失败。

2.2.5 向串口写入数据函数 writeData

该函数用于向串口写入数据。

int itas109::CSerialPort::writeData(const void *data, // 待写入数据int maxSize       // 写入长度
)

成功则返回写入字节数,失败则返回-1。

写入失败可用itas109::CSerialPort::getLastError()获取错误码。

2.2.6 从串口读取指定长度数据函数 readData

该函数用于从串口读取指定长度数据。

int readData(void *data,  // 读取结果int size     // 读取长度
)

正常则返回读取字节数,失败则返回-1。

读取失败可用itas109::CSerialPort::getLastError()获取错误码。

注意:
CSerialPort异步操作模式下,需要配合connectReadEvent函数使用。详见第三节的代码示例。

2.2.7 从串口读取所有数据函数 readAllData

该函数用于从串口读取所有数据。

int itas109::CSerialPort::readAllData(void *data // 读取结果
)

正常则返回读取字节数,失败则返回-1。

读取失败可用itas109::CSerialPort::getLastError()获取错误码。

注意:
CSerialPort异步操作模式下,需要配合connectReadEvent函数使用。详见第三节的代码示例。

2.2.8 绑定读取事件函数 connectReadEvent

该函数用于异步模式(默认)下,绑定读取响应的结果。

需要继承CSerialPortListener,并实现onReadEvent虚函数。详见第三节的代码示例。

class MyListener : public CSerialPortListener
{
public:void onReadEvent(const char *portName, unsigned int readBufferLen){}
}

2.2.9 获取CSerialPort版本信息函数 getVersion

该函数用于获取CSerialPort版本信息。

std::string itas109::CSerialPort::getVersion()

返回CSerialPort版本信息,如https://github.com/itas109/CSerialPort - V4.3.0.230215

2.2.10 错误码 SerialPortError

错误码数值错误码宏定义错误码说明
-1ErrorUnknownunknown error 未知错误
0ErrorOKok 成功
1ErrorFailgeneral error一般性错误
2ErrorNotImplementednot implemented 未实现
3ErrorInnerinner error 内部错误(如内存访问异常等)
4ErrorNullPointernull pointer error 空指针错误
5ErrorInvalidParaminvalid parameter error 无效的参数
6ErrorAccessDeniedaccess denied error 权限错误
7ErrorOutOfMemoryout of memory 内存不足
8ErrorTimeouttime out error 超时
9ErrorNotInitnot init 未初始化
10ErrorInitFailedinit failed 初始化失败
11ErrorAlreadyExistalready exist 已经存在
12ErrorNotExistnot exist 不存在
13ErrorAlreadyOpenalready open 已经打开
14ErrorNotOpennot open 未打开
15ErrorOpenFailedopen failed 打开失败
16ErrorCloseFailedclose failed 关闭失败
17ErrorWriteFailedwrite failed 写入失败
18ErrorReadFailedread failed 读取失败

3. CSerialPort简单代码示例

  • 操作步骤
$ mkdir CSerialPortDemo
$ cd CSerialPortDemo
$ git clone https://github.com/itas109/CSerialPort
$ touch CSerialPortDemo.cpp
$ touch CMakeLists.txt
$ mkdir bin 
$ cd bin
$ cmake ..
$ cmake --build .
  • 目录结构
$ tree
.
+--- CMakeLists.txt
+--- CSerialPort
|   +--- include
|   +--- src
|   +--- ...
+--- CSerialPortDemo.cpp
  • CSerialPortDemo.cpp

注意:接收函数需要继承CSerialPortListener

#include <iostream>#include "CSerialPort/SerialPort.h"
#include "CSerialPort/SerialPortInfo.h"#include <vector>
using namespace itas109;
using namespace std;class MyListener : public CSerialPortListener
{
public:MyListener(CSerialPort *sp): p_sp(sp){};void onReadEvent(const char *portName, unsigned int readBufferLen){if (readBufferLen > 0){char *data = new char[readBufferLen + 1]; // '\0'if (data){// readint recLen = p_sp->readData(data, readBufferLen);if (recLen > 0){data[recLen] = '\0';std::cout << portName << ", Length: " << recLen << ", Str: " << data << std::endl;}delete[] data;data = NULL;}}};private:CSerialPort *p_sp;
};int main()
{CSerialPort sp;MyListener listener(&sp);std::cout << "Version : " << sp.getVersion() << std::endl << std::endl;vector<SerialPortInfo> m_availablePortsList = CSerialPortInfo::availablePortInfos();std::cout << "availableFriendlyPorts: " << std::endl;for (size_t i = 1; i <= m_availablePortsList.size(); ++i){SerialPortInfo serialPortInfo = m_availablePortsList[i - 1];std::cout << i << " - " << serialPortInfo.portName << " " << serialPortInfo.description << " " << serialPortInfo.hardwareId << std::endl;}if (m_availablePortsList.size() == 0){std::cout << "No valid port" << std::endl;}else{std::cout << std::endl;int input = -1;do{std::cout << "Please Input The Index Of Port(1 - " << m_availablePortsList.size() << ")" << std::endl;std::cin >> input;if (input >= 1 && input <= m_availablePortsList.size()){break;}} while (true);const char *portName = m_availablePortsList[input - 1].portName;std::cout << "Port Name: " << portName << std::endl;sp.init(portName,              // windows:COM1 Linux:/dev/ttyS0itas109::BaudRate9600, // baudrateitas109::ParityNone,   // parityitas109::DataBits8,    // data bititas109::StopOne,      // stop bititas109::FlowNone,     // flow4096                   // read buffer size);sp.setReadIntervalTimeout(0); // read interval timeout 0ms// sp.setOperateMode(itas109::SynchronousOperate);sp.open();std::cout << "Open " << portName << (sp.isOpen() ? " Success. " : " Failed. ");std::cout << "Code: " << sp.getLastError() << ", Message: " << sp.getLastErrorMsg() << std::endl;// 绑定读取函数sp.connectReadEvent(&listener);// 写入数据sp.writeData("itas109", 7);for (;;){}}return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)project(CSerialPortDemo)if(APPLE)find_library(IOKIT_LIBRARY IOKit)find_library(FOUNDATION_LIBRARY Foundation)
endif()include_directories(CSerialPort/include)
file(GLOB_RECURSE COMMON_SOURCES CSerialPort/src/SerialPort.cpp CSerialPort/src/SerialPortBase.cpp CSerialPort/src/SerialPortInfo.cpp CSerialPort/src/SerialPortInfoBase.cpp)
if (CMAKE_HOST_WIN32)file(GLOB_RECURSE OS_ABOUT_SOURCES CSerialPort/src/SerialPortInfoWinBase.cpp CSerialPort/src/SerialPortWinBase.cpp)
elseif (CMAKE_HOST_UNIX)file(GLOB_RECURSE OS_ABOUT_SOURCES CSerialPort/src/SerialPortInfoUnixBase.cpp CSerialPort/src/SerialPortUnixBase.cpp)
endif ()	add_executable( ${PROJECT_NAME} CSerialPortDemo.cpp ${COMMON_SOURCES} ${OS_ABOUT_SOURCES})if (WIN32)target_link_libraries( ${PROJECT_NAME} setupapi )
elseif (APPLE)target_link_libraries( ${PROJECT_NAME} ${FOUNDATION_LIBRARY} ${IOKIT_LIBRARY})
elseif (UNIX)target_link_libraries( ${PROJECT_NAME} pthread )
endif ()
  • 运行结果(windows下环回测试)
Version : https://github.com/itas109/CSerialPort - V4.3.0.230215availableFriendlyPorts:
1 - COM1 USB-SERIAL CH340  USB\VID_1A86&PID_7523&REV_0264Please Input The Index Of Port(1 - 1)
1
Port Name: COM1
Open COM1 Success. Code: 0, Message: success
COM1, Length: 7, Str: itas109

License

License under CC BY-NC-ND 4.0: 署名-非商业使用-禁止演绎


Reference:

  1. https://github.com/itas109/CSerialPort
  2. https://gitee.com/itas109/CSerialPort
  3. https://blog.csdn.net/itas109

相关文章:

CSerialPort教程4.3.x (2) - CSerialPort源码简介

CSerialPort教程4.3.x (2) - CSerialPort源码简介 前言 CSerialPort项目是一个基于C/C的轻量级开源跨平台串口类库&#xff0c;可以轻松实现跨平台多操作系统的串口读写&#xff0c;同时还支持C#, Java, Python, Node.js等。 CSerialPort项目的开源协议自 V3.0.0.171216 版本…...

【数据结构OJ题】有效的括号

原题链接&#xff1a;https://leetcode.cn/problems/valid-parentheses/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 这道题目主要考查了栈的特性&#xff1a; 题目的意思主要是要做到3点匹配&#xff1a;类型、顺序、数量。 题目给的例子是比较…...

Java性能分析中常用命令和工具

当涉及到 Java 性能分析时&#xff0c;有一系列强大的命令和工具可以帮助开发人员分析应用程序的性能瓶颈、内存使用情况和线程问题。以下是一些常用的 Java 性能分析命令和工具&#xff0c;以及它们的详细说明和示例。 以下是一些常用的性能分析命令和工具汇总&#xff1a; …...

JVM性能分析-jstat工具观察gc频率

jstat jstat是java自带的工具&#xff0c;在bin目录下 用法 语法&#xff1a;jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] [kqkyyj-2 bin]$ jstat -help Usage: jstat -help|-optionsjstat -<option> [-t] [-h&l…...

mysql 查询报错 1267 - Illegal mix of collations

mysql 查询报错 1267 - Illegal mix of collations 详细报错: 1267 - Illegal mix of collations (utf8mb4_0900_ai_ci,IMPLICIT) and (utf8mb4_unicode_ci,IMPLICIT) for 主要的原因其实就是两张表的字符集不一样改一下就行了。 注: 改了表还是报错的话,那就是表内的字段没有…...

【ARM】Day6

cotex-A7核UART总线实验 1. 键盘输入一个字符‘a’&#xff0c;串口工具显示‘b’ 2. 键盘输入一个字符串"nihao"&#xff0c;串口工具显示“nihao” uart.h #ifndef __UART4_H__ #define __UART4_H__#include "stm32mp1xx_rcc.h" #include "stm3…...

深入理解Flink Mailbox线程模型

文章目录 整体设计processMail1.Checkpoint Tigger2.ProcessingTime Timer Trigger processInput兼容SourceStreamTask 整体设计 Mailbox线程模型通过引入阻塞队列配合一个Mailbox线程的方式&#xff0c;可以轻松修改StreamTask内部状态的修改。Checkpoint、ProcessingTime Ti…...

Docker搭建LNMP运行Wordpress平台

一、项目1.1 项目环境1.2 服务器环境1.3 任务需求 二、Linux 系统基础镜像三、Nginx1、建立工作目录2、编写 Dockerfile 脚本3、准备 nginx.conf 配置文件4、生成镜像5、创建自定义网络6、启动镜像容器7、验证 nginx 四、Mysql1、建立工作目录2、编写 Dockerfile3、准备 my.cnf…...

10个常见渐变交互效果

1、透明度渐变背景交互 <div class"fade-background"></div> Copy .fade-background {width: 200px;height: 200px;background: linear-gradient(to bottom, rgba(255, 0, 0, 0), rgba(255, 0, 0, 1));transition: background 0.5s ease; }.fade-backgro…...

[线程/C]基础

文章目录 1. 线程介绍2. 创建线程2.1 线程函数2.2 创建线程 3. 线程退出4. 线程回收4.1 线程函数4.2 回收子线程数据4.2.1 使用子线程栈4.2.2 使用全局变量4.2.3 使用主线程栈 5. 线程分离6. 其他线程函数6.1 线程取消6.2 线程ID的比较 1. 线程介绍 线程是轻量级的进程&#x…...

Spring Clould 负载均衡 - Ribbon

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; Ribbon-负载均衡原理&#xff08;P14&#xff09; 具体实现时通过LoaBalanced注解实现&#xff0c;表示RestTemplate要被Ribbon拦截处理 orderservice调用user时候&#xff0c…...

活用DNS技术实现相同IP的不同端口映射不同域名

WindowsDNS基本配置 在内网的 Windows 服务器环境中&#xff0c;你可以通过配置 DNS 服务和 Web 服务器来实现所需的域名解析和端口转发。如下是一些基本的步骤来实现配置&#xff1a; 1&#xff0c;配置 Windows DNS 服务 在你的 Windows 服务器上配置 DNS 服务&#xff0c…...

AutoHotkey:定时删除目录下指定分钟以前的文件,带UI界面

删除指定目录下&#xff0c;所有在某个指定分钟以前的文件&#xff0c;可以用来清理经常生成很多文件的目录&#xff0c;但又需要保留最新的一部分文件 支持拖放目录到界面 能够记忆设置&#xff0c;下次启动后不用重新设置&#xff0c;可以直接开始 应用场景比如&#xff1a…...

一文学会sklearn中的交叉验证的方法

前言 在机器学习中&#xff0c;我们经常需要评估模型的性能。而为了准确评估模型的性能&#xff0c;我们需要使用一种有效的评估方法。五折交叉验证&#xff08;5-fold cross-validation&#xff09;就是其中一种常用的模型评估方法&#xff0c;用于评估机器学习模型的性能和泛…...

【MySQL面试题(66道)】

文章目录 MySQL面试题(66道)基础1.什么是内连接、外连接、交叉连接、笛卡尔积呢&#xff1f;2.那 MySQL 的内连接、左连接、右连接有有什么区别&#xff1f;3.说一下数据库的三大范式&#xff1f;4.varchar 与 char 的区别&#xff1f;5.blob 和 text 有什么区别&#xff1f;6.…...

CSSCI、北核期刊投稿指南(2023年更新)

该数据为经管类的期刊投稿指南&#xff0c;包含发表难度&#xff0c;文章数量&#xff0c;影响因子&#xff0c;用户评价等指标。共5份文件&#xff0c;分别为国内所有期刊信息库、投稿指南&#xff08;CSSCI版本、CSSCI扩展版本、北大核刊版本、建议期刊版本&#xff09; 一、…...

构建 NodeJS 影院微服务并使用 docker 部署它(02/4)

一、说明 构建一个微服务的电影网站&#xff0c;需要Docker、NodeJS、MongoDB&#xff0c;这样的案例您见过吗&#xff1f;如果对此有兴趣&#xff0c;您就继续往下看吧。 图片取自网络 — 封面由我制作 这是✌️“构建 NodeJS 影院微服务”系列的第二篇文章。 二、对第一部分的…...

HTML <style> 标签

实例 <html> <head> <style type="text/css"> h1 {color:red} p {color:blue} </style> </head><body> <h1>Header 1</h1> <p>A paragraph.</p> </body> </html>定义和用法 <style>…...

设计模式——迪米特法则

文章目录 基本介绍应用实例应用实例改进迪米特法则注意事项和细节 基本介绍 一个对象应该对其他对象保持最少的了解类与类关系越密切&#xff0c;耦合度越大迪米特法则(Demeter Principle)又叫最少知道原则&#xff0c;即一个类对自己依赖的类知道的越少越好。也就是说&#x…...

区块链基本概念与当前生态简介

区块链是一种去中心化的分布式账本技术&#xff0c;它通过将数据按照时间顺序链接成区块&#xff0c;并使用密码学算法确保数据的安全性和完整性。每个区块包含一定数量的交易记录&#xff0c;而且每个区块都包含了前一个区块的哈希值&#xff0c;这样形成了一个不可篡改的链式…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...