README
多路 CAN <--> TCP/IP 转发器:can_agent + libControlCan.so/libControlCan.dll。使用 Boost.Asio 实现跨平台支持:
- Windows 10/7
- Linux/Ubuntu
- Arm Linux
CAN 设备接收数据可通过 Socket 转发给多个客户端(主要实现Receive);同时 Socket 客户端可以通过 Transmit 发送消息到 CAN 设备。
Socket客户端依赖 libControlCan.so/libControlCan.dll 实现通讯,且可以使用 libControlCan.dll 替换周立功 can_test 中的同名dll,使得周立功 can_test 转为通过 can_agent 访问 USBCAN设备。
底层支持的CAN设备:
- 周立功 USB CAN II 设备;
- 其他兼容周立功 USB CAN II 的设备,及升级型号;
代码结构:
|
|-- include : libControlCAN API头文件,高性能bytes/text转换
|-- libControlCAN : CAN <--> Socket 透传实现lib
|-- can_agent : Socket agent 服务
|-- test : Boost.Asio TCP/UDP, eventpp, zmq, CAN收发, CAN/Socket透传测试及demo
|-- asio_example : Boost.Asio 学习测试代码
使用 eventpp(MCMP)实现数据分发,性能测试结果pdf:can_agent performance
1. 开发环境
- VS2022扩展(Windows):Clang Power Tools ;
- VS2022扩展(Windows):Format Document On Save ;
- 依赖安装的 boost >= 1.79;
- 3rd -- gtest源码 v1.11.0;
- 3rd -- glog源码 v0.6.0。
2. 编译选项
- 编译选项 ENABLE_PROFILER :使能链接 gperftools profiler。
3. 自带第三方库的编译
3.1 gtest源码目录相对于官方gtest仓库修改
- googletest/CMakeLists.txt:set(GOOGLETEST_VERSION 1.11.0),否则找不到GOOGLETEST_VERSION会报错;
- googletest/cmake/internal_utils.cmake:函数cxx_library_with_type中更改 RUNTIME_OUTPUT_DIRECTORY 等变量的路径为 CMAKE_ARCHIVE_OUTPUT_DIRECTORY ,使输出路径与父CMakeLists.txt保持一致。
- googletest/CMakeLists.txt:添加 set(gtest ${gtest} PARENT_SCOPE),让test目录能够依赖于gtest之后编译;
- googletest/CMakeLists.txt:gtest,gtest_main 静态编译修改为 cxx_shared_library 动态编译。
3.2 glog源码相对于官方glog的修改
# 3rd/glog-0.6.0/CMakeLists.txt
set(BUILD_TESTING OFF)
set(glog ${glog} PARENT_SCOPE)
configure_file (src/glog/logging.h.in glog/logging.h @ONLY) # 在该语句后面添加如下两条
configure_file (src/glog/log_severity.h glog/log_severity.h @ONLY)
configure_file (src/glog/platform.h glog/platform.h @ONLY)
set(GLOG_PUBLIC_H
# ...
) # 在该语句下面添加一条语句
set(GLOG_INC_DIR "${CMAKE_CURRENT_BINARY_DIR}" PARENT_SCOPE)
# 注释掉如下语句
# set(CMAKE_DEBUG_POSTFIX d)
在根CMakeLists.txt中添加:
include_directories(${GLOG_INC_DIR})
3.3 引入libzmq,辅助测试代码引用libzmp
- 注释掉 RELEASE_POSTFIX , RELWITHDEBINFO_POSTFIX , MINSIZEREL_POSTFIX , DEBUG_POSTFIX ,并且测试例程针对Windows 链接名称为 libzmq;
- BUILD_TESTS 设置为 OFF;
- WITH_LIBSODIUM 设置为 OFF;
- WITH_LIBBSD 设置为 OFF;
- BUILD_STATIC 设置为 OFF,否则Windows编译报错(与BUILD_SHARED二选一);
- set(ZeroMQ ${ZeroMQ} PARENT_SCOPE);
- WITH_DOCS 位置为 OFF;
3.4 boost编译适用于libControlCAN.so的静态库
./boostrap.sh
./b2 -layout=versioned variant=release cxxflags='-fPIC -std=c++17' runtime-link=static link=static threading=multi
sudo ./b2 install
# 删除系统安装的boost
sudo apt-get --purge remove libboost-dev
sudo apt-get --purge remove libboost-all-dev
4. 官方glog使用vs2022编译命令
cmake .. -G "Visual Studio 17 2022" -A Win32 -DCMAKE_BUILD_TYPE="Release" -DBUILD_SHARED_LIBS="ON" -DCMAKE_INSTALL_BINDIR="bin" -DCMAKE_INSTALL_SBINDIR="bin" -DCMAKE_INSTALL_LIBEXECDIR="bin" -DCMAKE_INSTALL_LIBDIR="lib" -DCMAKE_INSTALL_INCLUDEDIR="include" -DCMAKE_INSTALL_DATAROOTDIR="share" -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY="ON" -DWITH_THREADS="True" -DWITH_SYMBOLIZE="True" -DWITH_UNWIND="True" -DBUILD_TESTING="False"
5. Windows 仅使用命令行编译
cmake -G "Visual Studio 17 2022" -A Win32 -S ./ -B "build32"
# cmake --build build32 --config Release --clean-first -j
cmake --build build32 --config Release -j
6. 编译问题解决
- 编译libControlCAN时,出现 relocation against in read-only section。是由于系统安装了多个版本的boost导致,添加 **link_directories("/usr/local/lib")**覆盖系统boost安装位置。
- Windows编译时,导出__stdcall函数时,导出符号带有_Func_Name@num,需要将def文件带入源文件一起编译;
7. 编译资源文件参考
- TVersionFixedInfo
- Go利用windres.exe和.rc文件在Windows下生成的程序带有版本、版权、产品名称、图标等属性信息
- llvm windows_version_resource.rc
8. 代码clang-format全部格式化
find . -regex '.*\.\(cc\|cpp\|hpp\|cu\|c\|h\)' -exec clang-format -style=file -i {} \;
代码检查:Extra Clang Tools 16.0.0git documentation
9. 代码静态检查
python run-clang-tidy.py -p ./build -config-file .clang-tidy -quiet
在代码中,使用NOLINT等(以及带参数的版本)标注禁用静态检查。
// NOLINT
// NOLINTNEXTLINE
// NOLINTBEGIN
// NOLINTEND
10. 参考
- CMake设置MSVC工程MT/MTd/MD/MDd
- 周立功 USBCAN 资料
- 周立功 USBCAN Linux资料
- windows临界区与std::lock_guargd性能对比
- concurrentqueue
- Boost ASIO例程
- C++ Client Server with Boost.Asio
- Boost ASIO 教程
11. 引用第三方库
12. template相关参考
13. template std::true_type std::false_type
#include <type_traits>
#include <iostream>
/* https://ideone.com/469YTq */
template<typename T>
void use_impl(const T&, std::false_type) {
std::cout << "use_impl(false)" << std::endl;
}
template<typename T>
void use_impl(const T&, std::true_type) {
std::cout << "use_impl(true)" << std::endl;
}
template<typename T>
void use(const T& v) {
use_impl(v, typename std::is_integral<T>::type());
}
int main() {
use(1);
use(1.2);
}