Commit 723933d0 authored by 唐永康's avatar 唐永康

Initial commit

parents
---
Language: Cpp
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 100
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortBlocksOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakAssignment: 2
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: C++17
---
Checks: >
-*,
bugprone-*,
cert-*,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-avoid-non-const-global-variables,
misc-*,
-misc-non-private-member-variables-in-classes,
performance-*,
-performance-avoid-endl,
readability-*,
-readability-magic-numbers,
-readability-identifier-length,
-readability-function-cognitive-complexity,
modernize-*,
-modernize-use-trailing-return-type,
-modernize-avoid-c-arrays
WarningsAsErrors: ''
HeaderFilterRegex: '.*'
AnalyzeTemporaryDtors: false
FormatStyle: 'file'
User: ''
CheckOptions:
- key: readability-identifier-naming.NamespaceCase
value: lower_case
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.StructCase
value: CamelCase
- key: readability-identifier-naming.FunctionCase
value: camelBack
- key: readability-identifier-naming.VariableCase
value: camelBack
- key: readability-identifier-naming.ParameterCase
value: camelBack
- key: readability-identifier-naming.MemberCase
value: camelBack
- key: readability-identifier-naming.PrivateMemberPrefix
value: m_
- key: readability-identifier-naming.ProtectedMemberPrefix
value: m_
- key: readability-identifier-naming.EnumCase
value: CamelCase
- key: readability-identifier-naming.EnumConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.ConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.MacroDefinitionCase
value: UPPER_CASE
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: true
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
value: true
# 自动检测文本文件并规范化行尾
* text=auto
# 明确指定文本文件使用 LF 换行符
*.cpp text eol=lf
*.h text eol=lf
*.hpp text eol=lf
*.c text eol=lf
*.cmake text eol=lf
CMakeLists.txt text eol=lf
*.txt text eol=lf
*.md text eol=lf
*.sh text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
# 二进制文件
*.so binary
*.dll binary
*.dylib binary
*.a binary
*.lib binary
*.exe binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
# 第三方库目录保持原样
third_party/** -text
name: CI/CD
on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
workflow_dispatch:
env:
BUILD_TYPE: Release
jobs:
build-and-test:
name: Build and Test - ${{ matrix.os }} (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux x86_64 (主要测试平台)
- os: ubuntu-latest
arch: x86_64
cmake_build_type: Release
use_qemu: false
# Linux x86_64 Debug 构建
- os: ubuntu-latest
arch: x86_64
cmake_build_type: Debug
use_qemu: false
# Linux aarch64 Release 构建 (使用 QEMU 模拟)
- os: ubuntu-latest
arch: aarch64
cmake_build_type: Release
use_qemu: true
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 设置 QEMU (aarch64)
if: matrix.use_qemu == true
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: 缓存 CMake 构建
uses: actions/cache@v4
with:
path: |
build
~/.cmake
key: ${{ runner.os }}-cmake-${{ matrix.arch }}-${{ matrix.cmake_build_type }}-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: |
${{ runner.os }}-cmake-${{ matrix.arch }}-${{ matrix.cmake_build_type }}-
- name: 安装构建依赖
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
git \
libpthread-stubs0-dev
# 对于 aarch64,安装交叉编译工具链或 QEMU 用户模式
if [ "${{ matrix.arch }}" = "aarch64" ]; then
sudo apt-get install -y \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
qemu-user-static \
binfmt-support
fi
- name: 验证工具链版本
run: |
echo "=== CMake 版本 ==="
cmake --version
echo ""
echo "=== 编译器版本 ==="
if [ "${{ matrix.arch }}" = "aarch64" ]; then
aarch64-linux-gnu-gcc --version
aarch64-linux-gnu-g++ --version
else
gcc --version
g++ --version
fi
echo ""
echo "=== 系统信息 ==="
uname -a
echo "目标架构: ${{ matrix.arch }}"
echo "实际架构: $(uname -m)"
- name: 创建构建目录
run: mkdir -p build
- name: 配置 CMake
working-directory: build
run: |
if [ "${{ matrix.arch }}" = "aarch64" ]; then
# 使用交叉编译工具链
cmake .. \
-DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \
-DBUILD_TESTING=ON \
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
-DCMAKE_FIND_ROOT_PATH=/usr/aarch64-linux-gnu
else
cmake .. \
-DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \
-DBUILD_TESTING=ON
fi
- name: 构建项目
working-directory: build
run: |
cmake --build . \
--config ${{ matrix.cmake_build_type }} \
--parallel $(nproc) \
--verbose
- name: 运行测试
working-directory: build
run: |
if [ "${{ matrix.arch }}" = "aarch64" ]; then
# 对于 aarch64,使用 QEMU 运行测试
# 设置 QEMU 环境变量
export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu
# 使用较少的并行任务,因为 QEMU 模拟较慢
ctest --output-on-failure --parallel 2 || ctest --output-on-failure
else
ctest --output-on-failure --parallel $(nproc) || ctest --output-on-failure
fi
continue-on-error: false
- name: 显示测试结果
if: always()
working-directory: build
run: |
echo "=== 测试摘要 ==="
ctest --print-labels || true
echo ""
echo "=== 构建产物 ==="
find . -type f -executable -name "test_*" -exec file {} \; || true
find . -type f -executable -name "*example*" -exec file {} \; || true
build-examples:
name: Build Examples
runs-on: ubuntu-latest
needs: build-and-test
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装构建依赖
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
git \
libpthread-stubs0-dev
- name: 创建构建目录
run: mkdir -p build
- name: 配置 CMake
working-directory: build
run: |
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
- name: 构建示例程序
working-directory: build
run: |
cmake --build . \
--config Release \
--parallel $(nproc) \
--target toolset_example action_group_show_l10
- name: 验证示例程序
working-directory: build
run: |
echo "=== 验证构建产物 ==="
if [ -f toolset_example ]; then
echo "✓ toolset_example 构建成功"
file toolset_example
ls -lh toolset_example
else
echo "✗ toolset_example 未找到"
exit 1
fi
if [ -f action_group_show_l10 ]; then
echo "✓ action_group_show_l10 构建成功"
file action_group_show_l10
ls -lh action_group_show_l10
else
echo "✗ action_group_show_l10 未找到"
exit 1
fi
code-quality:
name: Code Quality Checks
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 检查文件编码和换行符
run: |
echo "检查文件编码和换行符..."
# 检查是否有 Windows 换行符(排除第三方库目录)
CRLF_FILES=$(find . -type f \
! -path "./third_party/*" \
\( -name "*.cpp" -o -name "*.h" -o -name "*.cmake" -o -name "CMakeLists.txt" \) \
-exec file {} \; | grep -i "CRLF" || true)
if [ -n "$CRLF_FILES" ]; then
echo "错误: 发现 Windows 换行符 (CRLF)"
echo ""
echo "以下文件需要修复:"
echo "$CRLF_FILES"
echo ""
echo "修复方法(Linux/macOS):"
echo " find . -type f ! -path './third_party/*' \\( -name '*.cpp' -o -name '*.h' -o -name '*.cmake' -o -name 'CMakeLists.txt' \\) -exec sed -i 's/\\r$//' {} \\;"
echo ""
echo "或者使用 dos2unix:"
echo " find . -type f ! -path './third_party/*' \\( -name '*.cpp' -o -name '*.h' -o -name '*.cmake' -o -name 'CMakeLists.txt' \\) -exec dos2unix {} \\;"
exit 1
fi
echo "✓ 文件编码检查通过(已排除 third_party 目录)"
- name: 检查 CMake 语法
run: |
echo "检查 CMake 语法..."
cmake --version
# 尝试解析 CMakeLists.txt
mkdir -p /tmp/cmake-check
cd /tmp/cmake-check
cmake ${{ github.workspace }} -Wno-dev > /dev/null 2>&1 || true
echo "✓ CMake 语法检查完成"
- name: 检查头文件包含
run: |
echo "检查头文件包含..."
# 检查是否有明显的头文件问题
if find ${{ github.workspace }}/include -name "*.h" -exec grep -l "#include.*\.\./" {} \; | head -5; then
echo "警告: 发现相对路径包含"
fi
echo "✓ 头文件检查完成"
summary:
name: CI Summary
runs-on: ubuntu-latest
needs: [build-and-test, build-examples, code-quality]
if: always()
steps:
- name: 生成 CI 摘要
run: |
echo "## CI/CD 构建摘要" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 构建状态" >> $GITHUB_STEP_SUMMARY
echo "- 构建和测试: ${{ needs.build-and-test.result }}" >> $GITHUB_STEP_SUMMARY
echo "- 示例构建: ${{ needs.build-examples.result }}" >> $GITHUB_STEP_SUMMARY
echo "- 代码质量: ${{ needs.code-quality.result }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 详细信息" >> $GITHUB_STEP_SUMMARY
echo "查看上方的作业详情以获取更多信息。" >> $GITHUB_STEP_SUMMARY
build
.vscode/
linker_hand/build
TODO.md
PROJECT_ANALYSIS.md
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
LinkerHand-CPP-SDK
\ No newline at end of file
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<RiderCodeStyleSettings>
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
</RiderCodeStyleSettings>
<clangFormatSettings>
<option name="ENABLED" value="true" />
</clangFormatSettings>
</code_scheme>
</component>
\ No newline at end of file
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BackendCodeEditorSettings">
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/linkerhand-cpp-sdk.iml" filepath="$PROJECT_DIR$/.idea/linkerhand-cpp-sdk.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
cmake_minimum_required(VERSION 3.15)
project(LinkerHand-CPP-SDK
VERSION 1.1.7
LANGUAGES CXX
DESCRIPTION "LinkerHand C++ SDK for robotic hand control"
)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
set(LIB_SUBDIR "x86_64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(LIB_SUBDIR "aarch64")
else()
message(WARNING "Unknown architecture, defaulting to x86_64")
set(LIB_SUBDIR "x86_64")
endif()
#-----------------------------------------------------------------------------
# LINKER_HAND_CPP_SDK
#-----------------------------------------------------------------------------
find_library(LINKER_HAND_LIB
NAMES linkerhand_cpp_sdk linkerhand_cpp
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib/${LIB_SUBDIR}
/usr/local/lib/linkerhand-cpp-sdk/${LIB_SUBDIR}
/usr/lib/linkerhand-cpp-sdk/${LIB_SUBDIR}
${CMAKE_INSTALL_PREFIX}/lib/linkerhand-cpp-sdk/${LIB_SUBDIR}
NO_DEFAULT_PATH
)
set(LINKER_HAND_INCLUDE_DIR
${CMAKE_CURRENT_SOURCE_DIR}/include
/usr/local/include/linkerhand-cpp-sdk
/usr/include/linkerhand-cpp-sdk
${CMAKE_INSTALL_PREFIX}/include/linkerhand-cpp-sdk
)
if(NOT LINKER_HAND_LIB)
message(FATAL_ERROR "linkerhand_cpp_sdk library not found!")
endif()
if(NOT LINKER_HAND_INCLUDE_DIR)
message(FATAL_ERROR "LinkerHand headers not found!")
endif()
message(STATUS "Found linkerhand_cpp_sdk library: ${LINKER_HAND_LIB}")
message(STATUS "Found LinkerHand headers: ${LINKER_HAND_INCLUDE_DIR}")
#-----------------------------------------------------------------------------
# INCLUDE_DIRECTORIES
#-----------------------------------------------------------------------------
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${LINKER_HAND_INCLUDE_DIR}
)
#-----------------------------------------------------------------------------
# EXECUTABLE
#-----------------------------------------------------------------------------
add_executable(my_project src/main.cpp)
target_link_libraries(my_project ${LINKER_HAND_LIB} pthread)
add_executable(toolset_example examples/toolset_example.cpp)
target_link_libraries(toolset_example ${LINKER_HAND_LIB} pthread)
add_executable(action_group_show_l10 examples/action_group_show_l10.cpp)
target_link_libraries(action_group_show_l10 ${LINKER_HAND_LIB} pthread)
add_executable(o6_async_reader examples/o6_async_reader.cpp)
target_link_libraries(o6_async_reader ${LINKER_HAND_LIB} pthread)
#-----------------------------------------------------------------------------
# INSTALL TARGETS
#-----------------------------------------------------------------------------
# 安装头文件
install(DIRECTORY include/
DESTINATION include/linkerhand-cpp-sdk
FILES_MATCHING PATTERN "*.h"
)
# 安装库文件
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/lib/${LIB_SUBDIR})
install(DIRECTORY lib/${LIB_SUBDIR}/
DESTINATION lib/linkerhand-cpp-sdk/${LIB_SUBDIR}
FILES_MATCHING PATTERN "*.so*"
)
endif()
#-----------------------------------------------------------------------------
# PACKAGE CONFIGURATION
#-----------------------------------------------------------------------------
include(CMakePackageConfigHelpers)
# 创建包配置文件
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/LinkerHandCPPSDKConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
# 设置包配置变量(用于 configure_file)
set(PACKAGE_INCLUDE_INSTALL_DIR "include/linkerhand-cpp-sdk")
set(PACKAGE_LIB_INSTALL_DIR "lib/linkerhand-cpp-sdk/${LIB_SUBDIR}")
# 创建包配置文件模板
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/LinkerHandCPPSDKConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/LinkerHandCPPSDKConfig.cmake"
@ONLY
)
# 安装包配置文件
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/LinkerHandCPPSDKConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/LinkerHandCPPSDKConfigVersion.cmake"
DESTINATION lib/cmake/LinkerHandCPPSDK
)
#-----------------------------------------------------------------------------
# TESTING
#-----------------------------------------------------------------------------
# 添加选项以启用/禁用测试
option(BUILD_TESTING "Build the testing tree" ON)
# 如果启用测试,包含测试子目录
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
MIT License
Copyright (c) 2026 灵心巧手(北京)科技有限公司
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# LinkerHand-CPP-SDK
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Platform](https://img.shields.io/badge/Platform-Linux-blue.svg)](https://www.linux.org/)
[![Architecture](https://img.shields.io/badge/Arch-x86__64%20%7C%20aarch64-lightgrey.svg)]()
[![CI/CD](https://github.com/linker-bot/linkerhand-cpp-sdk/workflows/CI/CD/badge.svg)](https://github.com/linker-bot/linkerhand-cpp-sdk/actions)
> 用于灵心巧手系列灵巧手的 C++ 软件开发工具包
LinkerHand-CPP-SDK 是由灵心巧手(北京)科技有限公司开发的官方 C++ SDK,提供完整的 API 接口用于控制 O6、L6、L7、L10、L20、L21、L25 等型号的灵巧手设备。
## 📋 目录
- [特性](#-特性)
- [系统要求](#-系统要求)
- [快速开始](#-快速开始)
- [安装](#-安装)
- [使用示例](#-使用示例)
- [API 文档](#-api-文档)
- [通信协议](#-通信协议)
- [项目结构](#-项目结构)
- [构建项目](#-构建项目)
- [故障排查](#-故障排查)
- [常见问题](#-常见问题)
- [贡献](#-贡献)
- [许可证](#-许可证)
- [联系我们](#-联系我们)
## ✨ 特性
- 🎯 **多型号支持** - 支持 O6、L6、L7、L10、L20、L21、L25 等多种型号
- 🚀 **简单易用** - 提供简洁的 C++ API 接口
- 🔌 **通信协议** - 支持 CAN 通信
- 📊 **传感器数据** - 实时获取压力、温度、电流等传感器数据
- 🎮 **精确控制** - 支持关节位置、速度、扭矩的精确控制
- 🔄 **实时反馈** - 获取关节状态、电机故障码等实时信息
- 🛠️ **跨平台** - 支持 Linux (x86_64, aarch64)
- 📚 **完整文档** - 提供详细的 API 文档和使用示例
## 💻 系统要求
- **操作系统**: Linux (Ubuntu 18.04+ 推荐)
- **架构**: x86_64 或 aarch64
- **编译器**: GCC 7.0+ 或 Clang 5.0+
- **CMake**: 3.15+
- **依赖**: pthread
## 🚀 快速开始
### 1. 克隆仓库
```bash
git clone https://github.com/linker-bot/linkerhand-cpp-sdk.git
cd linkerhand-cpp-sdk
```
### 2. 使用安装脚本(推荐)
```bash
./script.sh
```
选择选项 `[2]: Install SDK` 进行构建和安装。
### 3. 基本使用示例
创建 `main.cpp` 文件:
```cpp
#include "LinkerHandApi.h"
#include <iostream>
#include <thread>
#include <chrono>
int main() {
// 初始化 L10 型号右手
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 获取版本信息
std::cout << "SDK Version: " << hand.getVersion() << std::endl;
// 握拳动作
std::vector<uint8_t> fist_pose = {101, 60, 0, 0, 0, 0, 255, 255, 255, 51};
hand.fingerMove(fist_pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
// 张开动作
std::vector<uint8_t> open_pose = {255, 104, 255, 255, 255, 255, 255, 255, 255, 71};
hand.fingerMove(open_pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
```
### 4. 编译和运行
创建 `CMakeLists.txt`:
```cmake
cmake_minimum_required(VERSION 3.15)
project(LinkerHand-CPP-SDK)
# 检测系统架构
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
set(LIB_SUBDIR "x86_64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(LIB_SUBDIR "aarch64")
else()
message(WARNING "Unknown architecture, defaulting to x86_64")
set(LIB_SUBDIR "x86_64")
endif()
# 查找库文件
find_library(LINKER_HAND_LIB
NAMES linkerhand_cpp_sdk
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib/${LIB_SUBDIR}
/usr/local/lib/linkerhand-cpp-sdk/${LIB_SUBDIR}
/usr/lib/linkerhand-cpp-sdk/${LIB_SUBDIR}
NO_DEFAULT_PATH
)
# 查找头文件
set(LINKER_HAND_INCLUDE_DIR
${CMAKE_CURRENT_SOURCE_DIR}/include
/usr/local/include/linkerhand-cpp-sdk
/usr/include/linkerhand-cpp-sdk
)
if(NOT LINKER_HAND_LIB)
message(FATAL_ERROR "linkerhand_cpp_sdk library not found!")
endif()
# 包含头文件
include_directories(${LINKER_HAND_INCLUDE_DIR})
# 创建可执行文件
add_executable(my_project main.cpp)
target_link_libraries(my_project ${LINKER_HAND_LIB} pthread)
```
编译和运行:
```bash
mkdir build && cd build
cmake ..
make
./my_project
```
## 📦 安装
### 方法一:使用安装脚本(推荐)
```bash
./script.sh
```
脚本提供以下功能:
- `[1]`: 构建 SDK
- `[2]`: 构建并安装 SDK
- `[3]`: 卸载 SDK
- `[6]`: 运行示例程序
### 方法二:手动安装
```bash
# 构建项目
mkdir build && cd build
cmake ..
make
# 安装(需要 root 权限)
sudo make install
```
安装后,库文件将安装到:
- 头文件: `/usr/local/include/linkerhand-cpp-sdk/`
- 库文件: `/usr/local/lib/linkerhand-cpp-sdk/{arch}/`
## 💡 使用示例
### 基本控制
```cpp
#include "LinkerHandApi.h"
#include <vector>
#include <thread>
#include <chrono>
int main() {
// 创建 API 实例
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 设置速度
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
hand.setSpeed(speed);
// 设置扭矩
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
hand.setTorque(torque);
// 控制手指运动
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
hand.fingerMove(pose);
return 0;
}
```
### 获取传感器数据
```cpp
// 获取压力数据
auto force_data = hand.getForce();
// 获取关节状态
auto joint_state = hand.getState();
// 获取电机温度
auto temperature = hand.getTemperature();
// 获取故障码
auto fault_code = hand.getFaultCode();
```
### 使用弧度制控制(L10/L20/L21/L25)
```cpp
// 使用弧度制控制关节
std::vector<double> pose_arc = {0.5, 0.3, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
hand.fingerMoveArc(pose_arc);
// 获取弧度制关节状态
auto state_arc = hand.getStateArc();
```
更多示例请参考 `examples/` 目录。详细说明请查看 [示例代码文档](examples/README.md)。
## 📚 API 文档
详细的 API 文档请参考:[API 参考文档](docs/API-Reference.md)
文档包含:
- 完整的 API 函数说明
- 参数和返回值详解
- 使用示例和注意事项
- 版本兼容性说明
### 命名规范
项目已进行命名规范改进,详细信息请参考:[命名规范改进文档](docs/NAMING_IMPROVEMENTS.md)
主要改进包括:
- 统一命名空间结构(所有型号实现类迁移到 `linkerhand::hand` 命名空间)
- 类名改进(不同型号使用不同类名,如 `L10Hand`, `L20Hand` 等)
- 参数命名修正(`handJoint` → `handModel`)
- 完全向后兼容(旧命名仍可使用)
## 🧪 测试
### 运行测试
```bash
# 构建并运行测试
mkdir build && cd build
cmake .. -DBUILD_TESTING=ON
make
ctest --output-on-failure
```
### 测试文档
- **测试指南**: [测试文档](docs/TESTING.md)(待创建) - 详细的测试框架安装、编写和运行指南
- **测试说明**: [测试目录 README](tests/README.md) - 测试结构和快速参考
- **CI/CD 文档**: [CI/CD 文档](docs/CI-CD.md) - 持续集成和持续部署配置说明
测试文档包含:
- 测试框架安装和配置(Google Test)
- 如何编写和运行测试
- 测试覆盖率配置
- 测试最佳实践
- CI/CD 集成指南
### 当前测试覆盖
项目已包含以下单元测试:
- ✅ `test_Common.cpp` - Common.h 枚举和类型测试
- ✅ `test_RangeToArc.cpp` - 范围到弧度转换函数测试
- ✅ `test_IHand_Utils.cpp` - IHand 工具函数测试
- ✅ `test_CanFrame.cpp` - CAN 帧结构测试
### 主要 API 接口
#### 控制接口
- `fingerMove()` - 设置关节位置(0-255)
- `fingerMoveArc()` - 设置关节位置(弧度制)
- `setSpeed()` - 设置运动速度
- `setTorque()` - 设置扭矩限制
#### 状态查询接口
- `getState()` - 获取关节状态
- `getStateArc()` - 获取关节状态(弧度制)
- `getSpeed()` - 获取当前速度设置
- `getTorque()` - 获取当前扭矩设置
#### 传感器接口
- `getForce()` - 获取压力数据(法向、切向、方向、接近感应)
- `getTemperature()` - 获取电机温度
- `getFaultCode()` - 获取电机故障码
- `getCurrent()` - 获取电机电流
## 🔌 通信协议
SDK 支持以下通信协议:
- **CAN** (`COMM_CAN_0`, `COMM_CAN_1`) - CAN 总线通信
- **ModBus** (`COMM_MODBUS`) - ModBus 通信协议
- **EtherCAT** (`COMM_ETHERCAT`) - EtherCAT 工业以太网通信
默认使用 `COMM_CAN_0`。
```cpp
// 使用 CAN0 通信(默认)
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 使用 CAN1 通信
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_CAN_1);
// 使用 ModBus 通信
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_MODBUS);
// 使用 EtherCAT 通信
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_ETHERCAT);
```
## 📁 项目结构
```
linkerhand-cpp-sdk/
├── include/ # 头文件
│ ├── LinkerHandApi.h # 主 API 接口
│ ├── Common.h # 通用定义
│ └── ...
├── lib/ # 预编译库文件
│ ├── x86_64/ # x86_64 架构库
│ └── aarch64/ # aarch64 架构库
├── examples/ # 示例代码
│ ├── toolset_example.cpp
│ └── action_group_show_l10.cpp
├── docs/ # 文档
│ ├── API-Reference.md # API 参考文档
│ ├── TROUBLESHOOTING.md # 故障排查指南
│ └── FAQ.md # 常见问题解答
├── src/ # 源代码
├── third_party/ # 第三方依赖
├── CMakeLists.txt # CMake 配置
├── script.sh # 安装脚本
└── README.md # 本文档
```
## 🔨 构建项目
### 使用 CMake
```bash
mkdir build
cd build
cmake ..
make
```
### 运行示例
```bash
cd build
./toolset_example
./action_group_show_l10
```
## 📖 关节映射表
不同型号的关节映射关系:
### L6/O6
```
["大拇指弯曲", "大拇指横摆", "食指弯曲", "中指弯曲", "无名指弯曲", "小拇指弯曲"]
```
### L7
```
["大拇指弯曲", "大拇指横摆", "食指弯曲", "中指弯曲", "无名指弯曲", "小拇指弯曲", "拇指旋转"]
```
### L10
```
["拇指根部", "拇指侧摆", "食指根部", "中指根部", "无名指根部", "小指根部",
"食指侧摆", "无名指侧摆", "小指侧摆", "拇指旋转"]
```
### L20
```
["拇指根部", "食指根部", "中指根部", "无名指根部", "小指根部",
"拇指侧摆", "食指侧摆", "中指侧摆", "无名指侧摆", "小指侧摆",
"拇指横摆", "预留", "预留", "预留", "预留",
"拇指尖部", "食指末端", "中指末端", "无名指末端", "小指末端"]
```
### L21/L25
详细映射请参考 [API 文档](docs/API-Reference.md)。
## 🔧 故障排查
如果遇到问题,请参考以下文档:
- **[故障排查指南](docs/TROUBLESHOOTING.md)** - 常见问题的排查和解决方案
- 编译问题
- 运行时问题
- 通信问题
- API 使用问题
- 性能问题
- **[常见问题解答](docs/FAQ.md)** - 常见问题的快速解答
- 安装相关问题
- 使用相关问题
- API 相关问题
- 兼容性问题
- 性能相关问题
如果文档无法解决您的问题,请:
1. 查看 [GitHub Issues](https://github.com/linker-bot/linkerhand-cpp-sdk/issues) 查看是否有类似问题
2. 提交新的 Issue,并提供详细的错误信息和复现步骤
3. 联系技术支持:[https://linkerbot.cn/aboutUs](https://linkerbot.cn/aboutUs)
## ❓ 常见问题
快速查找常见问题的答案,请参考 [常见问题解答 (FAQ)](docs/FAQ.md)。
常见问题包括:
- 如何安装和配置 SDK?
- 如何选择通信接口?
- 不同型号的关节数量是多少?
- 如何提高性能?
- 如何获取技术支持?
## 🤝 贡献
我们欢迎社区贡献!请参考以下步骤:
1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 开启 Pull Request
更多贡献指南请参考 [CONTRIBUTING.md](CONTRIBUTING.md)(待创建)。
## 📄 许可证
本项目采用 [MIT 许可证](LICENSE)。
Copyright (c) 2026 灵心巧手(北京)科技有限公司
## 📞 联系我们
- **官方网站**: [https://linkerbot.cn](https://linkerbot.cn)
- **关于我们**: [https://linkerbot.cn/aboutUs](https://linkerbot.cn/aboutUs)
- **GitHub**: [https://github.com/linker-bot/linkerhand-cpp-sdk](https://github.com/linker-bot/linkerhand-cpp-sdk)
## 📝 更新日志
详细的版本更新记录请参考 [CHANGELOG.md](CHANGELOG.md)(待创建)。
---
**注意**: 使用前请确保设备已正确连接并配置好通信接口。
@PACKAGE_INIT@
# 确定系统架构
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
set(LIB_SUBDIR "x86_64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
set(LIB_SUBDIR "aarch64")
else()
set(LIB_SUBDIR "x86_64")
endif()
# 设置包含目录和库目录(相对于安装前缀)
set(LinkerHandCPPSDK_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../@PACKAGE_INCLUDE_INSTALL_DIR@")
set(LinkerHandCPPSDK_LIB_DIR "${CMAKE_CURRENT_LIST_DIR}/../../@PACKAGE_LIB_INSTALL_DIR@")
# 也支持从构建目录查找(用于开发时)
list(APPEND LinkerHandCPPSDK_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../include/linkerhand-cpp-sdk")
list(APPEND LinkerHandCPPSDK_LIB_DIR "${CMAKE_CURRENT_LIST_DIR}/../../lib/linkerhand-cpp-sdk/${LIB_SUBDIR}")
# 查找库文件
find_library(LinkerHandCPPSDK_LIBRARY
NAMES linkerhand_cpp_sdk
PATHS ${LinkerHandCPPSDK_LIB_DIR}
NO_DEFAULT_PATH
)
# 检查库文件是否存在
if(NOT LinkerHandCPPSDK_LIBRARY)
message(FATAL_ERROR "LinkerHandCPPSDK library not found in ${LinkerHandCPPSDK_LIB_DIR}")
endif()
# 设置变量供外部使用
set(LinkerHandCPPSDK_FOUND TRUE)
set(LinkerHandCPPSDK_VERSION @PROJECT_VERSION@)
# 创建导入目标
if(NOT TARGET LinkerHandCPPSDK::LinkerHandCPPSDK)
add_library(LinkerHandCPPSDK::LinkerHandCPPSDK SHARED IMPORTED)
set_target_properties(LinkerHandCPPSDK::LinkerHandCPPSDK PROPERTIES
IMPORTED_LOCATION "${LinkerHandCPPSDK_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${LinkerHandCPPSDK_INCLUDE_DIR}"
)
endif()
check_required_components(LinkerHandCPPSDK)
# LinkerHand C++ API 参考文档
## 目录
- [API 概述](#api-概述)
- [快速索引](#快速索引)
- [构造函数](#构造函数)
- [控制接口](#控制接口)
- [状态查询接口](#状态查询接口)
- [传感器接口](#传感器接口)
- [电机管理接口](#电机管理接口)
- [使用示例](#使用示例)
- [注意事项](#注意事项)
- [版本兼容性](#版本兼容性)
---
## API 概述
LinkerHand C++ API 提供了完整的接口用于控制灵心巧手系列灵巧手设备。支持 O6、L6、L7、L10、L20、L21、L25 等多种型号,支持 CAN、ModBus、EtherCAT 等多种通信协议。
---
## 快速索引
### 控制接口
- [`fingerMove()`](#fingermove) - 设置关节位置(0-255)
- [`fingerMoveArc()`](#fingermovearc) - 设置关节位置(弧度制)
- [`setSpeed()`](#setspeed) - 设置运动速度
- [`setTorque()`](#settorque) - 设置扭矩限制
### 状态查询接口
- [`getState()`](#getstate) - 获取关节状态
- [`getStateArc()`](#getstatearc) - 获取关节状态(弧度制)
- [`getSpeed()`](#getspeed) - 获取当前速度设置
- [`getTorque()`](#gettorque) - 获取当前扭矩设置
- [`getVersion()`](#getversion) - 获取版本信息
### 传感器接口
- [`getForce()`](#getforce) - 获取压力数据(法向、切向、方向、接近感应)
- [`getTemperature()`](#gettemperature) - 获取电机温度
- [`getFaultCode()`](#getfaultcode) - 获取电机故障码
- [`getCurrent()`](#getcurrent) - 获取电机电流
### 电机管理接口
- [`setCurrent()`](#setcurrent) - 设置电流(仅 L20)
- [`setEnable()`](#setenable) - 使能电机(仅 L25)
- [`setDisable()`](#setdisable) - 禁用电机(仅 L25)
- [`clearFaultCode()`](#clearfaultcode) - 清除故障码(仅 L20)
---
## 构造函数
### LinkerHandApi
```cpp
LinkerHandApi(const LINKER_HAND &handModel, const HAND_TYPE &handType, const COMM_TYPE commType = COMM_CAN_0);
```
**功能描述**
创建并初始化 LinkerHand API 实例。
**参数说明**
- `handModel` (LINKER_HAND): 机械手型号
- 可选值: `LINKER_HAND::O6`, `LINKER_HAND::L6`, `LINKER_HAND::L7`, `LINKER_HAND::L10`, `LINKER_HAND::L20`, `LINKER_HAND::L21`, `LINKER_HAND::L25`
- `handType` (HAND_TYPE): 机械手类型
- `HAND_TYPE::LEFT` - 左手
- `HAND_TYPE::RIGHT` - 右手
- `commType` (COMM_TYPE): 通信类型(可选,默认 `COMM_CAN_0`)
- `COMM_CAN_0` - CAN 总线 0
- `COMM_CAN_1` - CAN 总线 1
- `COMM_MODBUS` - ModBus 通信协议
- `COMM_ETHERCAT` - EtherCAT 工业以太网通信
**返回值**
无
```cpp
LinkerHandApi(const LINKER_HAND &handModel, const HAND_TYPE &handType,
const std::string canChannel, const int baudrate);
```
**功能描述**
创建并初始化 LinkerHand API 实例。
**参数说明**
- `handModel` (LINKER_HAND): 机械手型号
- 可选值: `LINKER_HAND::O6`, `LINKER_HAND::L6`, `LINKER_HAND::L7`, `LINKER_HAND::L10`, `LINKER_HAND::L20`, `LINKER_HAND::L21`, `LINKER_HAND::L25`
- `handType` (HAND_TYPE): 机械手类型
- `HAND_TYPE::LEFT` - 左手
- `HAND_TYPE::RIGHT` - 右手
- `canChannel` (std::string): can 通道名称
- `baudrate` (int): can 波特率
**返回值**
无
**使用示例**
```cpp
#include "LinkerHandApi.h"
int main() {
// 创建 L10 型号右手实例,使用默认 CAN0 通信
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 创建 L20 型号左手实例,使用 CAN1 通信
LinkerHandApi hand(LINKER_HAND::L20, HAND_TYPE::LEFT, COMM_CAN_1);
return 0;
}
```
```cpp
#include "LinkerHandApi.h"
int main() {
// 调用API接口
LinkerHandApi hand(LINKER_HAND::O6, HAND_TYPE::LEFT, "can0", 115200);
// 获取版本信息
std::cout << hand.getVersion() << std::endl;
// 四指握拳
std::vector<uint8_t> fist_pose = {255, 255, 0, 0, 0, 0};
hand.fingerMove(fist_pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
// 四指张开
std::vector<uint8_t> open_pose = {255, 255, 255, 255, 255, 255};
hand.fingerMove(open_pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
return 0;
}
```
**注意事项**
- 构造函数会自动初始化通信接口
- 确保在创建实例前,通信接口已正确配置(如 CAN 总线已启动、ModBus 端口已配置、EtherCAT 网络已初始化)
- 不同型号支持的通信协议可能不同,请参考设备手册
- 使用 CAN 总线前,确保总线已正确配置和启动
- 使用 ModBus 前,确保串口或网络连接已建立
- 使用 EtherCAT 前,确保 EtherCAT 主站已正确配置
---
## 控制接口
### fingerMove
```cpp
void fingerMove(const std::vector<uint8_t> &pose);
```
**功能描述**
设置关节的目标位置,用于控制手指的运动。使用 0-255 的数值范围。
**参数说明**
- `pose` (std::vector<uint8_t>): 关节位置数组
- **L6/O6**: 长度为 6
- **L7**: 长度为 7
- **L10**: 长度为 10
- **L20**: 长度为 20
- **L21**: 长度为 25
- **L25**: 长度为 25
- 取值范围: 0-255(0 表示完全弯曲,255 表示完全伸直)
**返回值**
无
**关节映射关系**
**L6/O6** (6 个关节):
```
[0] 大拇指弯曲
[1] 大拇指横摆
[2] 食指弯曲
[3] 中指弯曲
[4] 无名指弯曲
[5] 小拇指弯曲
```
**L7** (7 个关节):
```
[0] 大拇指弯曲
[1] 大拇指横摆
[2] 食指弯曲
[3] 中指弯曲
[4] 无名指弯曲
[5] 小拇指弯曲
[6] 拇指旋转
```
**L10** (10 个关节):
```
[0] 拇指根部
[1] 拇指侧摆
[2] 食指根部
[3] 中指根部
[4] 无名指根部
[5] 小指根部
[6] 食指侧摆
[7] 无名指侧摆
[8] 小指侧摆
[9] 拇指旋转
```
**L20** (20 个关节):
```
[0-4] 拇指根部、食指根部、中指根部、无名指根部、小指根部
[5-9] 拇指侧摆、食指侧摆、中指侧摆、无名指侧摆、小指侧摆
[10] 拇指横摆
[11-14] 预留
[15-19] 拇指尖部、食指末端、中指末端、无名指末端、小指末端
```
**L21** (25 个关节):
```
[0-4] 大拇指根部、食指根部、中指根部、无名指根部、小拇指根部
[5-9] 大拇指侧摆、食指侧摆、中指侧摆、无名指侧摆、小拇指侧摆
[10] 大拇指横滚
[11-14] 预留
[15] 大拇指中部
[16-19] 预留
[20-24] 大拇指指尖、食指指尖、中指指尖、无名指指尖、小拇指指尖
```
**L25** (25 个关节):
```
[0-4] 大拇指根部、食指根部、中指根部、无名指根部、小拇指根部
[5-9] 大拇指侧摆、食指侧摆、中指侧摆、无名指侧摆、小拇指侧摆
[10] 大拇指横滚
[11-14] 预留
[15-19] 大拇指中部、食指中部、中指中部、无名指中部、小拇指中部
[20-24] 大拇指指尖、食指指尖、中指指尖、无名指指尖、小拇指指尖
```
**使用示例**
```cpp
// L10 握拳
std::vector<uint8_t> fist_pose = {101, 60, 0, 0, 0, 0, 255, 255, 255, 51};
hand.fingerMove(fist_pose);
// L10 张开
std::vector<uint8_t> open_pose = {255, 104, 255, 255, 255, 255, 255, 255, 255, 71};
hand.fingerMove(open_pose);
```
**注意事项**
- 数组长度必须与型号匹配,否则可能导致未定义行为
- 建议在调用前先设置速度和扭矩
- 动作执行需要时间,建议在调用后添加适当的延时
---
### fingerMoveArc
```cpp
void fingerMoveArc(const std::vector<double> &pose);
```
**功能描述**
设置关节的目标位置,使用弧度制。适用于需要精确角度控制的场景。
**参数说明**
- `pose` (std::vector<double>): 关节位置数组(弧度制)
- **L10**: 长度为 10
- **L20**: 长度为 20
- **L21**: 长度为 25
- **L25**: 长度为 25
- 取值范围: 根据 URDF 限位定义
**返回值**
无
**使用示例**
```cpp
// L10 使用弧度制控制
std::vector<double> pose_arc = {0.5, 0.3, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
hand.fingerMoveArc(pose_arc);
```
**注意事项**
- 仅支持 L10、L20、L21、L25 型号
- 弧度值必须在 URDF 定义的限位范围内
- 建议参考设备的 URDF 文件了解各关节的限位范围
---
### setSpeed
```cpp
void setSpeed(const std::vector<uint8_t> &speed);
```
**功能描述**
设置手部的运动速度。速度值影响关节运动的快慢。
**参数说明**
- `speed` (std::vector<uint8_t>): 速度数组
- 长度: 5 个元素(对应 5 根手指)
- 取值范围: 0-255
- 值越大,运动速度越快
**返回值**
无
**使用示例**
```cpp
// 设置中等速度
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
hand.setSpeed(speed);
// 设置不同手指的不同速度
std::vector<uint8_t> speed_custom = {255, 200, 200, 200, 150};
hand.setSpeed(speed_custom);
```
**注意事项**
- 速度设置会影响所有后续的 `fingerMove()` 调用
- 建议在初始化时设置速度
- 过高的速度可能导致运动不稳定
---
### setTorque
```cpp
void setTorque(const std::vector<uint8_t> &torque);
```
**功能描述**
设置手部的扭矩限制。扭矩值影响手指的抓握力度。
**参数说明**
- `torque` (std::vector<uint8_t>): 扭矩数组
- 长度: 5 个元素(对应 5 根手指)
- 取值范围: 0-255
- 值越大,允许的最大扭矩越大
**返回值**
无
**使用示例**
```cpp
// 设置最大扭矩
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
hand.setTorque(torque);
// 设置较小的扭矩(轻柔抓握)
std::vector<uint8_t> torque_light = {128, 128, 128, 128, 128};
hand.setTorque(torque_light);
```
**注意事项**
- 扭矩设置会影响所有后续的 `fingerMove()` 调用
- 建议在初始化时设置扭矩
- 过高的扭矩可能导致设备损坏,请谨慎设置
---
## 状态查询接口
### getState
```cpp
std::vector<uint8_t> getState();
```
**功能描述**
获取当前关节的状态信息,返回值为 0-255 的数值。
**参数说明**
无
**返回值**
- `std::vector<uint8_t>`: 当前关节状态数组
- 长度: 根据型号不同(L10=10, L20=20, L21=25, L25=25)
- 取值范围: 0-255
**使用示例**
```cpp
auto state = hand.getState();
for (size_t i = 0; i < state.size(); i++) {
std::cout << "关节 " << i << ": " << static_cast<int>(state[i]) << std::endl;
}
```
**注意事项**
- 返回值反映的是当前关节的实际位置
- 如果关节正在运动,返回值会持续变化
---
### getStateArc
```cpp
std::vector<double> getStateArc();
```
**功能描述**
获取当前关节的状态信息,返回值为弧度制。
**参数说明**
无
**返回值**
- `std::vector<double>`: 当前关节状态数组(弧度制)
- 长度: 根据型号不同(L10=10, L20=20, L21=25, L25=25)
**使用示例**
```cpp
auto state_arc = hand.getStateArc();
for (size_t i = 0; i < state_arc.size(); i++) {
std::cout << "关节 " << i << ": " << state_arc[i] << " 弧度" << std::endl;
}
```
**注意事项**
- 仅支持 L10、L20、L21、L25 型号
- 返回值反映的是当前关节的实际位置(弧度制)
---
### getSpeed
```cpp
std::vector<uint8_t> getSpeed();
```
**功能描述**
获取当前设置的速度值。
**参数说明**
无
**返回值**
- `std::vector<uint8_t>`: 当前速度设置数组
- 长度: 5 个元素
**使用示例**
```cpp
auto speed = hand.getSpeed();
std::cout << "当前速度设置: ";
for (auto s : speed) {
std::cout << static_cast<int>(s) << " ";
}
std::cout << std::endl;
```
---
### getTorque
```cpp
std::vector<uint8_t> getTorque();
```
**功能描述**
获取当前设置的最大扭矩值。
**参数说明**
无
**返回值**
- `std::vector<uint8_t>`: 当前扭矩设置数组
- 长度: 5 个元素
**使用示例**
```cpp
auto torque = hand.getTorque();
std::cout << "当前扭矩设置: ";
for (auto t : torque) {
std::cout << static_cast<int>(t) << " ";
}
std::cout << std::endl;
```
---
### getVersion
```cpp
std::string getVersion();
```
**功能描述**
获取当前软件或硬件的版本号。
**参数说明**
无
**返回值**
- `std::string`: 版本号字符串
**使用示例**
```cpp
std::string version = hand.getVersion();
std::cout << "版本号: " << version << std::endl;
```
---
## 传感器接口
### getForce
```cpp
std::vector<std::vector<std::vector<uint8_t>>> getForce();
```
**功能描述**
获取手部传感器的综合数据,包括法向压力、切向压力、切向方向和接近感应。
**参数说明**
无
**返回值**
- `std::vector<std::vector<std::vector<uint8_t>>>`: 三维向量
- 第一维: 手指索引(0-4,对应拇指、食指、中指、无名指、小指)
- 第二维: 传感器类型(法向压力、切向压力、切向方向、接近感应)
- 第三维: 传感器数据矩阵
**使用示例**
```cpp
auto force_data = hand.getForce();
// 遍历每根手指
for (size_t finger = 0; finger < force_data.size(); finger++) {
std::cout << "手指 " << finger << ":" << std::endl;
// 遍历传感器类型
for (size_t sensor_type = 0; sensor_type < force_data[finger].size(); sensor_type++) {
std::cout << " 传感器类型 " << sensor_type << ": ";
// 遍历传感器数据
for (auto value : force_data[finger][sensor_type]) {
std::cout << static_cast<int>(value) << " ";
}
std::cout << std::endl;
}
}
```
**注意事项**
- 返回值结构复杂,建议参考示例代码理解数据结构
- 不同型号的传感器配置可能不同
---
### getTemperature
```cpp
std::vector<uint8_t> getTemperature();
```
**功能描述**
获取电机的温度数据。
**参数说明**
无
**返回值**
- `std::vector<uint8_t>`: 电机温度数组
- 长度: 根据型号不同
- 单位: 摄氏度(具体换算方式请参考设备手册)
**使用示例**
```cpp
auto temperature = hand.getTemperature();
for (size_t i = 0; i < temperature.size(); i++) {
std::cout << "电机 " << i << " 温度: " << static_cast<int>(temperature[i]) << std::endl;
}
```
**注意事项**
- 温度值可能需要根据设备手册进行换算
- 建议定期检查温度,避免过热
---
### getFaultCode
```cpp
std::vector<uint8_t> getFaultCode();
```
**功能描述**
获取电机的故障码。用于诊断设备故障。
**参数说明**
无
**返回值**
- `std::vector<uint8_t>`: 故障码数组
- 长度: 根据型号不同
- 0 表示正常,非 0 表示存在故障
**使用示例**
```cpp
auto fault_code = hand.getFaultCode();
for (size_t i = 0; i < fault_code.size(); i++) {
if (fault_code[i] != 0) {
std::cout << "警告: 电机 " << i << " 故障码: "
<< static_cast<int>(fault_code[i]) << std::endl;
}
}
```
**注意事项**
- 故障码的具体含义请参考设备手册
- 出现故障码时,建议停止操作并检查设备
---
### getCurrent
```cpp
std::vector<uint8_t> getCurrent();
```
**功能描述**
获取电机的当前电流值。
**参数说明**
无
**返回值**
- `std::vector<uint8_t>`: 电流数组
- 长度: 根据型号不同
- 单位: 安培(具体换算方式请参考设备手册)
**使用示例**
```cpp
auto current = hand.getCurrent();
for (size_t i = 0; i < current.size(); i++) {
std::cout << "电机 " << i << " 电流: " << static_cast<int>(current[i]) << std::endl;
}
```
**注意事项**
- 电流值可能需要根据设备手册进行换算
- 异常高的电流可能表示负载过大或故障
---
## 电机管理接口
### setCurrent
```cpp
void setCurrent(const std::vector<uint8_t> &current);
```
**功能描述**
设置电机的电流值。**目前仅支持 L20 型号。**
**参数说明**
- `current` (std::vector<uint8_t>): 电流数组
- 长度: 根据电机数量
- 取值范围: 请参考设备手册
**返回值**
无
**使用示例**
```cpp
// 仅 L20 支持
if (hand.handModel_ == LINKER_HAND::L20) {
std::vector<uint8_t> current = {100, 100, 100, 100, 100};
hand.setCurrent(current);
}
```
**注意事项**
- 仅支持 L20 型号
- 电流设置需要谨慎,过高的电流可能损坏设备
---
### setEnable
```cpp
void setEnable(const std::vector<uint8_t> &enable = std::vector<uint8_t>(5, 0));
```
**功能描述**
使能电机。**目前仅支持 L25 型号。**
**参数说明**
- `enable` (std::vector<uint8_t>): 使能数组(可选,默认全 0)
- 长度: 5 个元素
- 0 表示禁用,非 0 表示使能
**返回值**
无
**使用示例**
```cpp
// 仅 L25 支持
if (hand.handModel_ == LINKER_HAND::L25) {
std::vector<uint8_t> enable = {1, 1, 1, 1, 1}; // 使能所有手指
hand.setEnable(enable);
}
```
**注意事项**
- 仅支持 L25 型号
- 默认参数为全 0(禁用状态)
---
### setDisable
```cpp
void setDisable(const std::vector<uint8_t> &disable = std::vector<uint8_t>(5, 1));
```
**功能描述**
禁用电机。**目前仅支持 L25 型号。**
**参数说明**
- `disable` (std::vector<uint8_t>): 禁用数组(可选,默认全 1)
- 长度: 5 个元素
- 0 表示使能,非 0 表示禁用
**返回值**
无
**使用示例**
```cpp
// 仅 L25 支持
if (hand.handModel_ == LINKER_HAND::L25) {
std::vector<uint8_t> disable = {1, 1, 1, 1, 1}; // 禁用所有手指
hand.setDisable(disable);
}
```
**注意事项**
- 仅支持 L25 型号
- 默认参数为全 1(禁用状态)
---
### clearFaultCode
```cpp
void clearFaultCode(const std::vector<uint8_t> &torque = std::vector<uint8_t>(5, 1));
```
**功能描述**
清除电机的故障码。**目前仅支持 L20 型号。**
**参数说明**
- `torque` (std::vector<uint8_t>): 扭矩数组(可选,默认全 1)
- 长度: 5 个元素
**返回值**
无
**使用示例**
```cpp
// 仅 L20 支持
if (hand.handModel_ == LINKER_HAND::L20) {
hand.clearFaultCode();
}
```
**注意事项**
- 仅支持 L20 型号
- 清除故障码前,请确保故障原因已解决
---
## 使用示例
### 完整示例:基本控制流程
```cpp
#include "LinkerHandApi.h"
#include <iostream>
#include <thread>
#include <chrono>
int main() {
// 1. 初始化 API
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 2. 获取版本信息
std::cout << "SDK Version: " << hand.getVersion() << std::endl;
// 3. 设置速度和扭矩
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
hand.setSpeed(speed);
hand.setTorque(torque);
// 4. 握拳动作
std::vector<uint8_t> fist_pose = {101, 60, 0, 0, 0, 0, 255, 255, 255, 51};
hand.fingerMove(fist_pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
// 5. 张开动作
std::vector<uint8_t> open_pose = {255, 104, 255, 255, 255, 255, 255, 255, 255, 71};
hand.fingerMove(open_pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
// 6. 获取状态信息
auto state = hand.getState();
std::cout << "当前关节状态: ";
for (auto s : state) {
std::cout << static_cast<int>(s) << " ";
}
std::cout << std::endl;
return 0;
}
```
### 示例:使用弧度制控制(L10/L20/L21/L25)
```cpp
#include "LinkerHandApi.h"
int main() {
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 使用弧度制控制关节
std::vector<double> pose_arc = {0.5, 0.3, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
hand.fingerMoveArc(pose_arc);
// 获取弧度制关节状态
auto state_arc = hand.getStateArc();
for (size_t i = 0; i < state_arc.size(); i++) {
std::cout << "关节 " << i << ": " << state_arc[i] << " 弧度" << std::endl;
}
return 0;
}
```
### 示例:读取传感器数据
```cpp
#include "LinkerHandApi.h"
#include <iostream>
int main() {
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// 获取压力数据
auto force_data = hand.getForce();
// 获取电机温度
auto temperature = hand.getTemperature();
// 获取故障码
auto fault_code = hand.getFaultCode();
// 获取电流
auto current = hand.getCurrent();
// 处理数据...
return 0;
}
```
---
## 注意事项
1. **初始化顺序**
- 建议在使用 API 前先设置速度和扭矩
- 确保通信接口已正确配置
2. **参数范围**
- `fingerMove()` 的参数范围是 0-255
- `fingerMoveArc()` 的参数范围由 URDF 限位定义
- 速度和扭矩的范围是 0-255
3. **型号差异**
- 不同型号支持的关节数量不同
- 部分功能仅特定型号支持(如 `setCurrent()` 仅 L20 支持)
- 请根据实际使用的型号调整代码
4. **通信协议**
- 默认使用 CAN0,可通过构造函数参数修改
- 使用 CAN 总线前,确保总线已正确配置和启动
- 使用 ModBus 前,确保串口或网络连接已建立
- 使用 EtherCAT 前,确保 EtherCAT 主站已正确配置
5. **错误处理**
- 建议定期检查故障码
- 出现故障时及时停止操作
- 温度过高时应暂停使用
6. **性能考虑**
- 动作执行需要时间,建议添加适当的延时
- 频繁调用 API 可能影响性能
- 建议在循环中适当添加延时
---
## 版本兼容性
### 支持的型号
- ✅ O6
- ✅ L6
- ✅ L7
- ✅ L10
- ✅ L20
- ✅ L21
- ✅ L25
### 功能支持矩阵
| 功能 | O6 | L6 | L7 | L10 | L20 | L21 | L25 |
|------|----|----|----|-----|-----|-----|-----|
| `fingerMove()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `fingerMoveArc()` | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
| `setCurrent()` | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| `setEnable()` / `setDisable()` | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| `clearFaultCode()` | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
### 通信协议支持
- ✅ CAN (CAN0, CAN1)
- ✅ ModBus
- ✅ EtherCAT
---
## 获取帮助
- **官方网站**: [https://linkerbot.cn](https://linkerbot.cn)
- **技术支持**: [https://linkerbot.cn/aboutUs](https://linkerbot.cn/aboutUs)
- **GitHub**: [https://github.com/linker-bot/linkerhand-cpp-sdk](https://github.com/linker-bot/linkerhand-cpp-sdk)
- **故障排查**: 请参考 [故障排查指南](TROUBLESHOOTING.md)
- **常见问题**: 请参考 [常见问题解答](FAQ.md)
# CI/CD 文档
本文档介绍项目的持续集成和持续部署(CI/CD)配置。
## 📋 目录
- [概述](#概述)
- [工作流配置](#工作流配置)
- [触发条件](#触发条件)
- [构建矩阵](#构建矩阵)
- [作业说明](#作业说明)
- [状态徽章](#状态徽章)
- [故障排查](#故障排查)
- [本地测试](#本地测试)
## 概述
项目使用 GitHub Actions 进行持续集成,自动执行以下任务:
- ✅ 多平台构建(Linux x86_64)
- ✅ 自动运行单元测试
- ✅ 构建示例程序
- ✅ 代码质量检查
- ✅ 构建状态报告
## 工作流配置
CI/CD 工作流配置文件位于:`.github/workflows/ci.yml`
### 主要特性
- **多构建配置**: 支持 Release 和 Debug 构建
- **并行测试**: 使用多核并行运行测试以加快速度
- **缓存优化**: 缓存 CMake 构建文件以提高效率
- **详细日志**: 提供详细的构建和测试输出
## 触发条件
工作流在以下情况下自动触发:
1. **推送代码** - 推送到 `main`、`master` 或 `develop` 分支
2. **Pull Request** - 创建或更新 PR 到 `main`、`master` 或 `develop` 分支
3. **手动触发** - 通过 GitHub Actions 界面手动运行(`workflow_dispatch`)
## 构建矩阵
当前支持的构建配置:
| 操作系统 | 架构 | 构建类型 | 说明 |
|---------|------|---------|------|
| Ubuntu Latest | x86_64 | Release | 主要构建配置 |
| Ubuntu Latest | x86_64 | Debug | 调试构建配置 |
| Ubuntu Latest | aarch64 | Release | ARM64 架构构建(使用 QEMU 模拟) |
### 架构支持说明
- **x86_64**: 原生支持,使用系统默认工具链
- **aarch64**: 使用交叉编译工具链(`aarch64-linux-gnu-gcc`)和 QEMU 用户模式模拟运行测试
- 构建速度较慢(由于 QEMU 模拟)
- 测试并行度降低(使用 2 个并行任务)
- 确保库文件在 `lib/aarch64/` 目录下可用
## 作业说明
### 1. build-and-test
**目的**: 构建项目并运行所有单元测试
**步骤**:
1. 检出代码
2. 设置 QEMU(仅 aarch64 架构)
3. 缓存 CMake 构建文件
4. 安装构建依赖(CMake、GCC、Git 等,aarch64 需要交叉编译工具链)
5. 验证工具链版本
6. 配置 CMake(启用测试,aarch64 使用交叉编译配置)
7. 构建项目
8. 运行测试(使用 CTest,aarch64 通过 QEMU 运行)
9. 显示测试结果和构建产物
**架构特定说明**:
- **x86_64**: 使用系统原生工具链,并行运行所有测试
- **aarch64**: 使用 `aarch64-linux-gnu-gcc` 交叉编译,通过 QEMU 用户模式运行测试(并行度降低为 2)
**输出**: 测试结果、构建的可执行文件信息
### 2. build-examples
**目的**: 验证示例程序可以成功构建
**步骤**:
1. 检出代码
2. 安装构建依赖
3. 配置 CMake(禁用测试)
4. 构建示例程序(`toolset_example`、`action_group_show_l10`)
5. 验证构建产物
**依赖**: 等待 `build-and-test` 作业完成
**输出**: 示例程序构建状态
### 3. code-quality
**目的**: 执行代码质量检查
**检查项**:
- 文件编码和换行符(确保使用 LF)
- CMake 语法验证
- 头文件包含检查
**输出**: 代码质量报告
### 4. summary
**目的**: 生成 CI/CD 摘要报告
**功能**: 汇总所有作业的状态,生成易于阅读的摘要
## 状态徽章
将以下 Markdown 代码添加到 README.md 以显示构建状态:
```markdown
![CI/CD](https://github.com/你的用户名/linkerhand-cpp-sdk/workflows/CI/CD/badge.svg)
```
或者使用 shields.io 样式:
```markdown
![CI/CD Status](https://img.shields.io/github/workflow/status/你的用户名/linkerhand-cpp-sdk/CI/CD?label=CI%2FCD)
```
## 故障排查
### 常见问题
#### 1. 测试失败
**症状**: `build-and-test` 作业失败
**可能原因**:
- 代码更改导致测试失败
- 测试超时
- 依赖库未找到
**解决方法**:
1. 查看作业日志中的详细错误信息
2. 在本地运行测试:`cd build && ctest --output-on-failure`
3. 检查 CMake 配置是否正确
#### 2. 构建失败
**症状**: CMake 配置或构建步骤失败
**可能原因**:
- CMakeLists.txt 语法错误
- 缺少依赖库
- 编译器版本不兼容
**解决方法**:
1. 检查 CMake 输出日志
2. 验证本地构建是否成功
3. 检查依赖库路径配置
#### 3. 缓存问题
**症状**: 构建使用过期的缓存
**解决方法**:
1. 在 GitHub Actions 界面清除缓存
2. 修改工作流中的缓存 key
3. 手动触发工作流
#### 4. aarch64 构建问题
**症状**: aarch64 架构构建或测试失败
**可能原因**:
- QEMU 未正确设置
- 交叉编译工具链未安装
- 库文件路径不正确
- QEMU 模拟运行失败
**解决方法**:
1. 检查 QEMU 设置步骤是否成功
2. 验证交叉编译工具链是否安装:`aarch64-linux-gnu-gcc --version`
3. 确认 `lib/aarch64/` 目录下存在库文件
4. 检查测试可执行文件架构:`file build/test_*`
5. 查看 QEMU 相关日志和错误信息
6. 如果 QEMU 模拟失败,可以尝试减少并行任务数量
### 查看日志
1. 进入 GitHub 仓库
2. 点击 "Actions" 标签
3. 选择失败的工作流运行
4. 查看具体作业的日志
## 本地测试
在提交代码前,建议在本地运行 CI/CD 流程:
### 1. 安装依赖
```bash
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
git \
libpthread-stubs0-dev
```
### 2. 运行完整构建和测试
#### x86_64 架构
```bash
# 创建构建目录
mkdir -p build
cd build
# 配置 CMake(启用测试,CMake 最低版本要求 3.15)
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON
# 构建项目
cmake --build . --config Release --parallel $(nproc)
# 运行测试
ctest --output-on-failure --parallel $(nproc)
```
#### aarch64 架构(交叉编译)
```bash
# 安装交叉编译工具链和 QEMU
sudo apt-get update
sudo apt-get install -y \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
qemu-user-static \
binfmt-support
# 创建构建目录
mkdir -p build
cd build
# 配置 CMake(交叉编译,CMake 最低版本要求 3.15)
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=ON \
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
-DCMAKE_FIND_ROOT_PATH=/usr/aarch64-linux-gnu
# 构建项目
cmake --build . --config Release --parallel $(nproc)
# 运行测试(通过 QEMU)
export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu
ctest --output-on-failure --parallel 2
```
### 3. 构建示例程序
```bash
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF
cmake --build . --target toolset_example action_group_show_l10
```
### 4. 代码质量检查
```bash
# 检查文件编码
find . -type f \( -name "*.cpp" -o -name "*.h" \) \
-exec file {} \; | grep -q "CRLF" && echo "发现 CRLF" || echo "✓ 使用 LF"
# 验证 CMake 语法
cmake --version
mkdir -p /tmp/cmake-check
cd /tmp/cmake-check
cmake /path/to/project -Wno-dev
```
## 最佳实践
1. **提交前测试**: 在本地运行测试确保通过
2. **小步提交**: 频繁提交小改动,便于定位问题
3. **查看日志**: 失败时仔细查看详细日志
4. **更新文档**: 修改 CI/CD 配置时更新本文档
5. **监控状态**: 定期检查构建状态,及时修复问题
## 相关文档
- [测试文档](tests/README.md) - 测试框架和运行指南
- [构建文档](../README.md#构建项目) - 项目构建说明
- [故障排查](TROUBLESHOOTING.md) - 常见问题解决方案
## 贡献
如果您想改进 CI/CD 配置:
1. Fork 仓库
2. 创建特性分支
3. 修改 `.github/workflows/ci.yml`
4. 测试您的更改
5. 提交 Pull Request
---
**最后更新**: 2026-01-XX
**注意**: 本文档描述了项目的 CI/CD 配置。如果您的项目尚未配置 CI/CD,可以参考本文档进行配置。实际的工作流配置文件位于 `.github/workflows/ci.yml`。
本文整理 `linkerhand-cpp-sdk` 当前仓库中的通信协议、分层结构、实际使用情况,以及如何与外部设备尤其是机械臂联动。
内容优先级遵循:
- 头文件和工厂逻辑
- 示例和 README
- 文档说明
如果某项结论来自头文件声明而非 `.so` 源码实现,本文会明确标注为“推断”。
---
## 1. 总览
当前 SDK 对外暴露的通信类型枚举在 [include/Common.h](../include/Common.h) 中定义:
- `COMM_CAN_0`
- `COMM_CAN_1`
- `COMM_MODBUS`
- `COMM_ETHERCAT`
见 [include/Common.h](../include/Common.h)。
从公开说明看,仓库希望支持三类协议:
- CAN
- ModBus
- EtherCAT
---
## 2. 通信分层
### 2.1 对外 API 层
业务代码通常从 `LinkerHandApi` 进入,构造时传入型号、左右手和通信类型:
```cpp
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_CAN_0);
```
这一层是业务层最应该依赖的统一入口。
### 2.2 型号工厂层
`HandFactory` 负责根据:
- 手型号
- 左/右手 ID
- 通信方式
实例化具体型号实现类。
从 [include/HandFactory.h](../include/HandFactory.h) 当前逻辑可确认:
- `CAN0/CAN1`:O6、L6、L7、L10、L20、L21、L25 都有分发路径
- `COMM_MODBUS`:只有 `L10` 会走 `ModbusL10Hand`
- `COMM_ETHERCAT`:枚举构造器会把通道映射为 `"ethercat"`,然后仍分发到各型号 `LxHand`
这意味着:
- “是否支持某协议”,先看 `HandFactory`
- “是否真能跑通”,还要继续看底层总线工厂和对应实现
### 2.3 底层传输抽象层
仓库把通信抽象分成两类:
- `ICanBus`
- 面向 `CAN` 风格的帧式通信
- 接口是 `send(data, can_id)` / `recv(id)`
- `ICommunication`
- 面向 `ModBus` 这类寄存器式通信
- 接口是 `send(data, id, start_address, num)` / `recv(id, start_address, num)`
对应文件:
- [include/ICanBus.h](../include/ICanBus.h)
- [include/ICommunication.h](../include/ICommunication.h)
这两个抽象本身很关键,因为它解释了仓库当前对协议的建模方式:
- CAN 和 EtherCAT 在这个仓库里都被包装成“类似 CAN 帧”的总线接口
- ModBus 被单独建模成寄存器读写接口
---
## 3. 协议分类与当前使用情况
## 3.1 CAN
### 3.1.1 当前定位
CAN 是当前仓库里最直接、最明确、最成熟的通信主路径。
证据:
- `COMM_CAN_0` / `COMM_CAN_1` 为一级枚举入口
- `HandFactory` 对几乎所有型号都支持 CAN 分发
- Linux 下有 `CanBus`
- Windows 下有 `PCANBus`
- 示例和 README 也都默认按 CAN 使用
相关文件:
- [include/HandFactory.h](../include/HandFactory.h)
- [include/CanBusFactory.h](../include/CanBusFactory.h)
- [include/CanBus.h](../include/CanBus.h)
- [include/PCANBus.h](../include/PCANBus.h)
### 3.1.2 平台划分
Linux:
- 使用 `CanBus`
- 基于 Linux SocketCAN
- 需要系统里存在 `can0`、`can1` 等接口
Windows:
- 使用 `PCANBus`
- 依赖 `PCANBasic`
### 3.1.3 典型用法
默认构造:
```cpp
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
```
显式指定 CAN1:
```cpp
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_CAN_1);
```
显式指定字符串通道:
```cpp
LinkerHandApi hand(LINKER_HAND::O6, HAND_TYPE::RIGHT, "can0", 1000000);
```
### 3.1.4 适用型号
从工厂头文件可直接确认,以下型号存在 CAN 路径:
- O6
- L6
- L7
- L10
- L20
- L21
- L25
### 3.1.5 使用建议
- 如果你只是要把灵巧手跑起来,优先选 CAN
- Linux 上先确保 `can0/can1` 被正确配置
- 同一进程内多个对象同时用 CAN 时,要明确每个对象的通道和设备 ID
### 3.1.6 常见检查项
Linux 常见检查:
```bash
ip link show can0
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
candump can0
```
---
## 3.2 ModBus
### 3.2.1 当前定位
ModBus 在这个仓库里不是通用主路径,而是一个明显带条件限制的接入分支。
从 [include/HandFactory.h](../include/HandFactory.h) 可确认:
- `COMM_MODBUS` 只会在 `USE_RMAN` 打开时生效
- 当前只有 `L10` 会被分发到 `ModbusL10Hand`
- 其他型号走 `COMM_MODBUS` 会报错
从 [include/ModbusLinkerHandL10.h](../include/ModbusLinkerHandL10.h) 可确认:
- `ModbusL10Hand` 继承自 `IHand`
- 内部通信对象是 `Communication::ModBus`
### 3.2.2 与瑞尔曼关联的modbus
`ModBus` 类并不是一个纯串口/纯 TCP 客户端实现。它直接持有:
- `rm_robot_handle *robot_handle`
- `RM_Service robotic_arm`
见 [include/ModBus.h](../include/ModBus.h)。
这说明当前仓库里的 ModBus 路径,设计上是通过睿尔曼机械臂 SDK 做中转,而不是一个完全独立的通用 ModBus 栈。
### 3.2.3 当前可确认的支持范围
- `L10 + USE_RMAN + COMM_MODBUS`
### 3.2.4 使用方式
表面 API 用法是:
```cpp
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_MODBUS);
```
### 3.2.5 适合什么场景
适合:
- 灵巧手挂在睿尔曼机械臂末端
- 由机械臂控制器充当 ModBus 主站
- 想通过机械臂统一控制末端设备
不适合直接假设为:
- 任意型号都能直接串口 ModBus 接入
- 不依赖机械臂环境即可独立运行
---
## 3.3 EtherCAT
### 3.3.1 当前定位
仓库里存在 `EtherCAT` 类,也存在 `COMM_ETHERCAT` 枚举和 README 说明,所以“目标能力”上 EtherCAT 是被纳入设计范围的。
相关文件:
- [include/EtherCAT.h](../include/EtherCAT.h)
- [include/HandFactory.h](../include/HandFactory.h)
- [README.md](../README.md)
### 3.3.2 公开头文件能确认什么
从 [include/EtherCAT.h](../include/EtherCAT.h) 可确认:
- 它继承自 `ICanBus`
- 使用 `ecrt.h`
- 内部定义了 PDO 映射
- 包含位置、速度、力矩等目标/实际值字段
说明它的设计目标不是“把 EtherCAT 重新包装成 ModBus”,而是用一个与 `ICanBus` 兼容的接口去承载 EtherCAT 读写。
## 4. 支持矩阵
基于当前头文件,建议按下面理解:
| 协议 | 公开枚举入口 | 当前头文件可确认的型号支持 | 运行依赖 | 当前稳定性判断 |
|---|---|---|---|---|
| CAN | `COMM_CAN_0` / `COMM_CAN_1` | O6、L6、L7、L10、L20、L21、L25 | Linux SocketCAN 或 Windows PCAN | 最高 |
| ModBus | `COMM_MODBUS` | 仅 L10 | `USE_RMAN` + 睿尔曼机械臂 SDK | 条件可用 |
| EtherCAT | `COMM_ETHERCAT` | 工厂层面对多型号放行 | `USE_ETHERCAT` + EtherCAT 主站环境 | 需额外验证 |
---
## 5. 与机械臂通讯的几种方式
这里的“和机械臂实现通讯”至少有三种不同语义,实际工程里不要混淆。
## 5.1 方式 A:PC 直接控制机械手,机械臂单独控制
架构:
- 上位机进程 A 控制灵巧手
- 上位机进程 B 或同进程另一模块控制机械臂
- 两边在应用层做同步
特点:
- 结构最清晰
- 灵巧手协议和机械臂协议完全解耦
- 最适合调试
适用:
- 灵巧手走 CAN
- 机械臂走自身 TCP/IP SDK
- 需要先分别验证两边
## 5.2 方式 B:通过睿尔曼机械臂末端生态协议接入灵巧手
这是仓库里最值得关注的机械臂联动路径。
RM SDK 公开接口支持:
- `rm_set_rm_plus_mode`
- `rm_set_rm_plus_touch`
- `rm_get_rm_plus_base_info`
- `rm_get_rm_plus_state_info`
见 [third_party/Robotic_Arm/include/rm_interface.h](../third_party/Robotic_Arm/include/rm_interface.h)。
同时,RM 的实时 UDP 上报结构 `rm_realtime_arm_joint_state_t` 里直接带有:
- `rm_plus_state`
- `plus_base_info`
- `plus_state_info`
见 [third_party/Robotic_Arm/include/rm_define.h](../third_party/Robotic_Arm/include/rm_define.h)。
这意味着:
- 机械臂控制器可以把末端设备状态纳入统一实时上报
- 末端灵巧手的基础信息、实时位置、电流、触觉、力矩等都有统一结构可读
`rm_plus_base_info_t` 里明确包含:
- 是否支持力控 `force`
- 是否支持触觉 `touch`
- 触觉数量 `touch_num`
`rm_plus_state_info_t` 里明确包含:
- `pos`
- `speed`
- `angle`
- `current`
- `normal_force`
- `tangential_force`
- `touch_data`
- `force`
这条路径特别适合:
- 灵巧手作为机械臂末端执行器
- 需要机械臂和手的状态在同一条实时通道里统一采集
## 5.3 方式 C:通过机械臂的 Modbus RTU / TCP 主站能力访问末端设备
RM SDK 还公开了更底层的外设通信接口,包括:
- `rm_set_controller_rs485_mode`
- `rm_set_tool_rs485_mode`
- `rm_read_modbus_rtu_*`
- `rm_write_modbus_rtu_*`
- `rm_read_modbus_tcp_*`
- `rm_write_modbus_tcp_*`
见 [third_party/Robotic_Arm/include/rm_interface.h](../third_party/Robotic_Arm/include/rm_interface.h)。
其中关键点:
- 控制器端 RS485 可配置为 Modbus RTU 主站/从站
- 工具端 RS485 可配置为 `RTU 主站 / 灵巧手模式 / 夹爪模式`
这说明机械臂控制器本身就能承担末端总线主站角色。
这条路径适合:
- 你明确知道末端设备的寄存器协议
- 你希望通过机械臂统一做外设接入
- 你不想让 PC 额外直连末端设备
---
## 6. 推荐的机械臂联动方案
## 6.1 如果目标是“尽快跑通”
推荐:
- 灵巧手:CAN
- 机械臂:RM 自身 TCP/IP SDK
- 在上位机应用层做动作编排
原因:
- 调试边界清晰
- 出问题时容易定位是手、臂还是协同逻辑
## 6.2 如果目标是“机械臂统一管理末端设备”
推荐优先顺序:
1. 末端生态协议 `rm_plus`
2. 工具端 RS485 + Modbus RTU
3. 控制器端 Modbus TCP/RTU
原因:
- `rm_plus` 已经把“灵巧手是末端设备”这个语义内建进机械臂 SDK
- 还能直接得到触觉、力矩、状态等统一数据结构
## 6.3 如果目标是“仓库内直接复用现有 ModBus 手实现”
当前只能保守地按下面理解:
- 型号:L10
- 前提:`USE_RMAN`
- 路径:`LinkerHandApi(..., COMM_MODBUS)`
如果你的手不是 L10,当前仓库不建议直接假设可以复用这条路径。
---
## 7. 接入流程建议
## 7.1 CAN 直连灵巧手
1. 配置 `can0/can1`
2. 用 `LinkerHandApi(..., COMM_CAN_0)` 或字符串 `"can0"` 创建设备
3. 先读版本、状态、故障码
4. 再做动作和传感采集
## 7.2 通过机械臂末端生态协议接入
1. `rm_init(...)`
2. `rm_create_robot_arm(ip, port)`
3. 开启 `rm_plus` 模式
4. 如需要触觉,设置 `rm_set_rm_plus_touch(...)`
5. 读取 `rm_get_rm_plus_base_info(...)`
6. 周期性读取 `rm_get_rm_plus_state_info(...)` 或启用实时 UDP 推送
这个流程是从头文件能力推导出的推荐路径。
## 7.3 通过机械臂 Modbus 主站访问末端设备
1. 建立机械臂连接
2. 设置控制器端或工具端 RS485 模式
3. 准备 RTU/TCP 参数结构体
4. 用 `rm_read_modbus_*` / `rm_write_modbus_*` 读写设备
5. 在应用层把寄存器语义映射成手的业务语义
---
## 8. 当前仓库里的限制和坑
## 8.1 EtherCAT 头文件路径存在可疑点
`CanBusFactory` 当前 Linux 分支会直接返回 `CanBus`,导致 `EtherCAT` 分支逻辑看起来不可达。
建议:
- 不要只看 README 就认为 EtherCAT 已稳定可用
- 真要落地 EtherCAT,先单独修这一层
## 8.2 ModBus 不是“全型号通用”
当前工厂里 ModBus 只给了 `L10` 路径,且依赖 `USE_RMAN`。
## 8.3 字符串构造器与枚举构造器能力不完全一致
从 `HandFactory` 可见:
- 枚举构造器会把 `COMM_ETHERCAT` 映射成 `"ethercat"`
- 字符串构造器仅当字符串里包含 `"can"` 才走 CAN 路径
- 字符串 `"ethercat"` 当前没有对应分支
因此:
- 若你要尝试 EtherCAT,不应假设字符串重载一定能工作
## 8.4 大量实现封装在预编译库中
仓库很多核心行为在 `.so` 中,头文件只能说明:
- 有这个接口
- 有这条调用路径
但不能 100% 证明:
- 现场设备一定可用
- 某些组合一定完全实现
---
## 9. 实际选型建议
如果你的目标是:
- 单独控制手
- 快速验证功能
- 先把手跑通
选:
- CAN
如果你的目标是:
- 手挂在睿尔曼机械臂末端
- 希望机械臂统一管理末端设备
- 需要联合采集末端实时状态
优先选:
- `rm_plus` 末端生态协议
如果你的目标是:
- 明确基于寄存器协议接入末端
- 想复用机械臂的 RS485 / Modbus 能力
选:
- 工具端 RS485 + Modbus RTU
- 或控制器端 Modbus TCP/RTU
如果你的目标是:
- 工业现场总线统一化
- 已经有 EtherCAT 主站体系
可以评估:
- EtherCAT
但在当前仓库里应先补通信层验证,不建议直接投入业务。
---
## 10. 一页结论
- 现阶段最稳的主路径是 CAN。
- ModBus 在这个仓库里是“依赖睿尔曼机械臂 SDK 的 L10 特化路径”,不是全型号通用路径。
- EtherCAT 在设计上被纳入支持范围,但当前头文件分发逻辑存在疑点,落地前必须补验证。
- 如果要和机械臂联动,最值得优先考虑的是 RM 的 `rm_plus` 末端生态协议,因为它已经把末端设备状态、触觉、力矩和实时上报结构统一起来了。
# 常见问题解答 (FAQ)
本文档回答 LinkerHand-CPP-SDK 的常见问题。
## 目录
- [安装相关问题](#安装相关问题)
- [使用相关问题](#使用相关问题)
- [API 相关问题](#api-相关问题)
- [兼容性问题](#兼容性问题)
- [性能相关问题](#性能相关问题)
- [其他问题](#其他问题)
---
## 安装相关问题
### Q1: 如何安装 SDK?
**A**: 有两种安装方式:
**方法一:使用安装脚本(推荐)**
```bash
./script.sh
# 选择选项 [2]: Install SDK
```
**方法二:手动安装**
```bash
mkdir build && cd build
cmake ..
make
sudo make install
```
详细说明请参考 [README.md](../README.md#安装)。
---
### Q2: 安装后找不到库文件怎么办?
**A**: 检查以下几点:
1. **确认安装路径**:
```bash
ls /usr/local/lib/linkerhand-cpp-sdk/
```
2. **检查架构匹配**:
```bash
uname -m # 查看系统架构
ls lib/x86_64/ # 或 lib/aarch64/
```
3. **设置库路径**:
```bash
export LD_LIBRARY_PATH=/usr/local/lib/linkerhand-cpp-sdk/x86_64:$LD_LIBRARY_PATH
```
4. **更新动态链接库缓存**:
```bash
sudo ldconfig
```
---
### Q3: 支持哪些操作系统和架构?
**A**:
- **操作系统**: Linux (Ubuntu 18.04+ 推荐)
- **架构**: x86_64、aarch64
- **编译器**: GCC 7.0+ 或 Clang 5.0+
- **CMake**: 3.11+
---
### Q4: 如何卸载 SDK?
**A**: 使用安装脚本:
```bash
./script.sh
# 选择选项 [3]: Uninstall SDK
```
或手动删除:
```bash
sudo rm -rf /usr/local/include/linkerhand-cpp-sdk
sudo rm -rf /usr/local/lib/linkerhand-cpp-sdk
```
---
## 使用相关问题
### Q5: 如何快速开始使用 SDK?
**A**: 参考以下步骤:
1. **创建项目文件**:
```cpp
// main.cpp
#include "LinkerHandApi.h"
#include <iostream>
int main() {
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
std::cout << "Version: " << hand.getVersion() << std::endl;
return 0;
}
```
2. **创建 CMakeLists.txt**:
```cmake
cmake_minimum_required(VERSION 3.5)
project(MyProject)
# 查找库和头文件
find_library(LINKER_HAND_LIB linkerhand_cpp_sdk
PATHS /usr/local/lib/linkerhand-cpp-sdk/x86_64)
include_directories(/usr/local/include/linkerhand-cpp-sdk)
add_executable(my_project main.cpp)
target_link_libraries(my_project ${LINKER_HAND_LIB} pthread)
```
3. **编译和运行**:
```bash
mkdir build && cd build
cmake ..
make
./my_project
```
详细说明请参考 [README.md](../README.md#快速开始)。
---
### Q6: 如何选择正确的通信接口?
**A**: 根据您的硬件配置选择:
- **CAN 总线**: 默认使用 `COMM_CAN_0`,如果有多个 CAN 接口可使用 `COMM_CAN_1`
- **ModBus**: 使用 `COMM_MODBUS` 进行 ModBus 通信
- **EtherCAT**: 使用 `COMM_ETHERCAT` 进行 EtherCAT 工业以太网通信
```cpp
// CAN0(默认)
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// CAN1
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_CAN_1);
// ModBus
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_MODBUS);
// EtherCAT
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_ETHERCAT);
```
---
### Q7: 如何配置通信接口?
**A**: 根据不同的通信协议进行配置:
#### CAN 总线配置
在 Linux 系统中配置 CAN 总线:
```bash
# 加载 CAN 模块
sudo modprobe can
sudo modprobe can_raw
sudo modprobe vcan # 虚拟 CAN(用于测试)
# 配置 CAN 接口
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
# 查看 CAN 接口状态
ip link show can0
# 测试 CAN 通信
cansend can0 123#DEADBEEF
candump can0
```
#### ModBus 配置
ModBus 配置取决于使用的接口类型(串口或网络):
- **串口 ModBus**: 确保串口设备权限正确,通常需要将用户添加到 `dialout` 组
- **网络 ModBus**: 确保网络连接正常,ModBus TCP/IP 端口已开放
#### EtherCAT 配置
EtherCAT 需要配置 EtherCAT 主站:
- 确保 EtherCAT 主站软件已安装和配置
- 检查 EtherCAT 网络拓扑
- 验证 EtherCAT 从站设备已正确连接
---
### Q8: 如何控制手指运动?
**A**: 使用 `fingerMove()` 函数:
```cpp
// 1. 设置速度和扭矩
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
hand.setSpeed(speed);
hand.setTorque(torque);
// 2. 设置关节位置(L10 示例)
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
hand.fingerMove(pose);
// 3. 等待动作完成
std::this_thread::sleep_for(std::chrono::seconds(1));
```
---
### Q9: 如何读取传感器数据?
**A**: 使用相应的获取函数:
```cpp
// 获取压力数据
auto force = hand.getForce();
// 获取温度
auto temperature = hand.getTemperature();
// 获取故障码
auto fault_code = hand.getFaultCode();
// 获取电流
auto current = hand.getCurrent();
// 获取关节状态
auto state = hand.getState();
```
---
## API 相关问题
### Q10: 不同型号的关节数量是多少?
**A**:
- **L6/O6**: 6 个关节
- **L7**: 7 个关节
- **L10**: 10 个关节
- **L20**: 20 个关节
- **L21**: 25 个关节
- **L25**: 25 个关节
详细映射关系请参考 [README.md](../README.md#关节映射表) 或 [API 参考文档](API-Reference.md)。
---
### Q11: `fingerMove()` 和 `fingerMoveArc()` 有什么区别?
**A**:
- **`fingerMove()`**: 使用 0-255 的数值范围,适用于快速控制
- **`fingerMoveArc()`**: 使用弧度制,适用于精确角度控制
```cpp
// 使用 0-255 范围(L10)
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
hand.fingerMove(pose);
// 使用弧度制(L10)
std::vector<double> pose_arc = {0.5, 0.3, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
hand.fingerMoveArc(pose_arc);
```
**注意**: `fingerMoveArc()` 仅支持 L10、L20、L21、L25 型号。
---
### Q12: 速度和扭矩的取值范围是多少?
**A**:
- **范围**: 0-255
- **速度**: 值越大,运动速度越快
- **扭矩**: 值越大,允许的最大扭矩越大
```cpp
// 中等速度
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
// 最大扭矩
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
```
---
### Q13: `getForce()` 返回的数据结构是什么?
**A**: `getForce()` 返回三维向量:
```cpp
std::vector<std::vector<std::vector<uint8_t>>> force = hand.getForce();
// force[finger][sensor_type][data]
// finger: 0-4 (拇指、食指、中指、无名指、小指)
// sensor_type: 0-3 (法向压力、切向压力、切向方向、接近感应)
// data: 传感器数据矩阵
```
示例:
```cpp
auto force = hand.getForce();
for (size_t finger = 0; finger < force.size(); finger++) {
for (size_t sensor_type = 0; sensor_type < force[finger].size(); sensor_type++) {
// 处理数据...
}
}
```
---
### Q14: 哪些功能仅特定型号支持?
**A**:
- **`setCurrent()`**: 仅 L20 支持
- **`setEnable()` / `setDisable()`**: 仅 L25 支持
- **`clearFaultCode()`**: 仅 L20 支持
- **`fingerMoveArc()`**: 仅 L10、L20、L21、L25 支持
详细支持矩阵请参考 [API 参考文档](API-Reference.md#版本兼容性)。
---
## 兼容性问题
### Q15: SDK 版本和设备固件版本需要匹配吗?
**A**: 建议使用匹配的版本。如果遇到兼容性问题:
1. 检查 SDK 版本:
```cpp
std::string version = hand.getVersion();
std::cout << "SDK Version: " << version << std::endl;
```
2. 查看 [更新日志](../CHANGELOG.md)(如果存在)了解版本变更
3. 联系技术支持获取兼容性信息
---
### Q16: 可以在 Windows 上使用吗?
**A**: 当前版本主要支持 Linux 系统。Windows 支持情况:
- **当前状态**: 主要支持 Linux
- **Windows**: 可能需要额外的配置和编译
- **建议**: 使用 Linux 系统(Ubuntu 18.04+ 推荐)
如有 Windows 支持需求,请联系技术支持。
---
### Q17: 支持哪些编译器?
**A**:
- **GCC**: 7.0 或更高版本
- **Clang**: 5.0 或更高版本
建议使用较新的编译器版本以获得更好的兼容性。
---
## 性能相关问题
### Q18: API 调用的响应时间是多少?
**A**: 响应时间取决于多个因素:
- **系统负载**: 系统负载高时响应会变慢
- **网络延迟**: EtherCAT 网络延迟
**建议**:
- 在动作后添加适当的延时:`std::this_thread::sleep_for(std::chrono::milliseconds(100))`
- 避免过于频繁的 API 调用
- 使用多线程处理传感器数据
---
### Q19: 如何提高性能?
**A**: 以下建议可以提高性能:
1. **降低轮询频率**:
```cpp
// 从 10ms 改为 100ms
std::this_thread::sleep_for(std::chrono::milliseconds(100));
```
2. **使用多线程**:
```cpp
std::thread sensor_thread([&hand]() {
while (running) {
auto force = hand.getForce();
// 处理数据...
}
});
```
3. **批量处理操作**:
- 减少不必要的 API 调用
- 缓存不需要实时更新的数据
4. **优化通信**:
- 优化通信参数
---
### Q20: CPU 占用过高怎么办?
**A**: 可能的原因和解决方案:
1. **轮询频率过高**:
```cpp
// 增加延时
std::this_thread::sleep_for(std::chrono::milliseconds(100));
```
2. **阻塞操作**:
- 使用异步操作
- 避免在循环中进行阻塞调用
3. **资源泄漏**:
- 检查资源是否正确释放
- 使用 RAII 原则管理资源
---
## 其他问题
### Q21: 如何获取技术支持?
**A**: 可以通过以下方式获取支持:
1. **文档**:
- [API 参考文档](API-Reference.md)
- [故障排查指南](TROUBLESHOOTING.md)
- [README](../README.md)
2. **在线资源**:
- **官方网站**: [https://linkerbot.cn](https://linkerbot.cn)
- **技术支持**: [https://linkerbot.cn/aboutUs](https://linkerbot.cn/aboutUs)
- **GitHub**: [https://github.com/linker-bot/linkerhand-cpp-sdk](https://github.com/linker-bot/linkerhand-cpp-sdk)
3. **GitHub Issues**:
- 提交问题报告
- 查看已有问题和解决方案
---
### Q22: 如何贡献代码?
**A**: 欢迎贡献!请参考以下步骤:
1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 开启 Pull Request
详细说明请参考 [README.md](../README.md#贡献)。
---
### Q23: 如何报告 Bug?
**A**: 在 GitHub Issues 中报告 Bug 时,请提供:
1. **错误信息**: 完整的错误信息或日志
2. **系统信息**:
- 操作系统和版本
- 系统架构(x86_64/aarch64)
- SDK 版本
3. **设备信息**:
- 设备型号(L6/L7/L10/L20/L21/L25)
- 固件版本(如果知道)
4. **复现步骤**: 详细的步骤说明
5. **相关代码**: 能够复现问题的代码片段
---
### Q24: 有示例代码吗?
**A**: 是的,项目提供了示例代码:
- **位置**: `examples/` 目录
- **示例**:
- `toolset_example.cpp` - 工具集示例
- `action_group_show_l10.cpp` - L10 动作组示例
运行示例:
```bash
cd build
./toolset_example
./action_group_show_l10
```
详细说明请参考 [示例代码文档](../examples/README.md)。
---
### Q25: 如何更新 SDK?
**A**: 更新步骤:
1. **拉取最新代码**:
```bash
git pull origin main
```
2. **重新编译和安装**:
```bash
./script.sh
# 选择选项 [2]: Install SDK
```
3. **或手动更新**:
```bash
cd build
cmake ..
make
sudo make install
```
如有其他问题,请参考 [故障排查指南](TROUBLESHOOTING.md) 或联系技术支持。
# L6 灵巧手 API 开发指南
## 1. 指南目标
本文聚焦 `L6/O6` 型号在当前 SDK 中的 API 使用与二次开发方法,回答三个问题:
1. 应该使用哪一层接口
2. 哪些能力属于通用 API,哪些属于 L6 专有 API
3. 做二次封装时应如何避免常见误用
## 2. API 分层结构
L6 在当前仓库中的调用链如下:
```text
应用代码
-> LinkerHandApi
-> HandFactory
-> IHand
-> L6Hand
```
各层职责:
| 层级 | 主要文件 | 作用 |
|---|---|---|
| 业务入口层 | `include/LinkerHandApi.h` | 对外提供统一接口 |
| 实例工厂层 | `include/HandFactory.h` | 根据型号和通信方式实例化具体手型 |
| 抽象接口层 | `include/IHand.h` | 定义跨型号公共能力与异常行为 |
| 型号实现层 | `include/LinkerHandL6.h` | 暴露 L6/O6 专有接口 |
## 3. 推荐使用策略
### 3.1 优先使用 `LinkerHandApi`
适用场景:
- 快速接入 L6
- 做上层业务逻辑
- 多型号共用一套代码
- 仅使用基础动作与基础状态读取
典型接口:
- `fingerMove`
- `setSpeed`
- `setTorque`
- `getState`
- `getSpeed`
- `getTorque`
- `getTemperature`
- `getFaultCode`
- `getForce`
- `getVersion`
### 3.2 需要 L6 专有能力时直接使用 `L6Hand`
适用场景:
- 需要加速度控制
- 需要重调零
- 需要读取序列号/硬件版本/机械版本
- 需要恢复出厂设置或保存参数
## 4. L6 能力矩阵
### 4.1 通过 `LinkerHandApi` 可直接调用的 L6 能力
| 方法 | 说明 | L6 使用建议 |
|---|---|---|
| `fingerMove(const std::vector<uint8_t>&)` | 位置控制 | 数组长度固定为 `6` |
| `setSpeed(const std::vector<uint8_t>&)` | 速度设置 | 建议长度 `6` |
| `setTorque(const std::vector<uint8_t>&)` | 扭矩设置 | 建议长度 `6` |
| `getState()` | 当前位置 | 返回当前 6 关节状态 |
| `getSpeed()` | 当前速度 | 用于回读配置 |
| `getTorque()` | 当前扭矩 | 用于回读配置 |
| `getTemperature()` | 温度信息 | 适合做热保护监控 |
| `getFaultCode()` | 故障码 | 每轮任务前后都应检查 |
| `clearFaultCode()` | 清故障 | 对跨型号代码建议包装异常处理 |
| `getForce()` | 触觉/压力矩阵 | 返回三维向量 |
| `getVersion()` | 版本信息 | 用于联机确认 |
### 4.2 仅在 `L6Hand` 中暴露的能力
| 方法 | 说明 |
|---|---|
| `setAcceleration(const std::vector<uint8_t>&)` | 设置 6 关节加速度 |
| `getAcceleration()` | 读取加速度 |
| `reHome()` | 重新调零 |
| `getSerialNumber()` | 获取设备序列号 |
| `getHardwareVersion()` | 获取硬件版本 |
| `getMechanicalVersion()` | 获取机械结构版本 |
| `factoryReset()` | 恢复出厂设置 |
| `saveParameters()` | 保存参数 |
如果你的项目需要这些能力,不建议只停留在 `LinkerHandApi` 层。
## 5. 构造方式与通信选择
### 5.1 推荐构造方式
```cpp
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::RIGHT, COMM_CAN_0);
```
或者显式指定通道:
```cpp
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::RIGHT, "can0", 1000000);
```
### 5.2 工厂逻辑中的通信差异
从 `include/HandFactory.h` 当前实现可见:
- 枚举构造器 `LinkerHandApi(..., COMM_TYPE)` 会把
- `COMM_CAN_0` 映射为 `can0`
- `COMM_CAN_1` 映射为 `can1`
- `COMM_ETHERCAT` 映射为 `ethercat`
- 对 L6 来说,上述三者都会走到 `L6Hand` 创建逻辑
但字符串构造器 `LinkerHandApi(..., std::string canChannel, int baudrate)` 的工厂判断是:
- `canChannel` 包含 `"can"` 时才走 L6/L7/L10/L20/L25 的 CAN 分支
- `canChannel == "modbus"` 只支持 `L10`
这意味着:
- 对 L6,`"can0"`、`"can1"` 是明确可用路径
- 如果你想走 `COMM_ETHERCAT`,优先使用枚举构造器,不要假设字符串 `"ethercat"` 在当前重载中一定可用
这是当前头文件逻辑直接能确认的限制,二次开发时应显式规避。
## 6. 基础 API 示例
### 6.1 使用 `LinkerHandApi`
```cpp
#include "LinkerHandApi.h"
#include <chrono>
#include <thread>
int main() {
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::LEFT, COMM_CAN_0);
std::vector<uint8_t> speed(6, 180);
std::vector<uint8_t> torque(6, 220);
std::vector<uint8_t> open_pose = {255, 255, 255, 255, 255, 255};
std::vector<uint8_t> close_pose = {120, 160, 0, 0, 0, 0};
hand.setSpeed(speed);
hand.setTorque(torque);
hand.fingerMove(open_pose);
std::this_thread::sleep_for(std::chrono::milliseconds(600));
hand.fingerMove(close_pose);
std::this_thread::sleep_for(std::chrono::milliseconds(600));
auto state = hand.getState();
auto force = hand.getForce();
auto fault = hand.getFaultCode();
}
```
### 6.2 使用 `L6Hand`
```cpp
#include "LinkerHandL6.h"
#include <iostream>
int main() {
linkerhand::hand::L6Hand hand(static_cast<uint32_t>(HAND_TYPE::RIGHT), "can0", 1000000);
hand.setSpeed(std::vector<uint8_t>(6, 150));
hand.setTorque(std::vector<uint8_t>(6, 180));
hand.setAcceleration(std::vector<uint8_t>(6, 90));
std::cout << hand.getVersion() << std::endl;
std::cout << hand.getSerialNumber() << std::endl;
return 0;
}
```
## 7. `getForce()` 数据使用建议
`LinkerHandApi::getForce()` 返回:
```cpp
std::vector<std::vector<std::vector<uint8_t>>>
```
现有文档与示例中,通常把第一维按五指处理:
- `0`:拇指
- `1`:食指
- `2`:中指
- `3`:无名指
- `4`:小指
建议做法:
- 先打印原始结构,确认维度
- 再做语义命名和阈值封装
- 将触觉解析与动作控制拆开,避免强耦合
## 8. 异常与兼容性策略
### 8.1 未实现能力会抛异常
`IHand` 中大量默认方法会抛出 `UnsupportedFeatureException`,因此跨型号开发时建议统一做保护:
```cpp
try {
auto value = hand.getCurrent();
} catch (const linkerhand::UnsupportedFeatureException& e) {
std::cerr << e.what() << std::endl;
}
```
### 8.2 参数错误要在业务层先拦截
建议所有二次封装先检查:
- 位置数组长度是否为 `6`
- 速度/扭矩/加速度长度是否为 `6`
- 数值是否在 `0-255`
例如:
```cpp
void ensureL6Vector(const std::vector<uint8_t>& data) {
if (data.size() != 6) {
throw std::invalid_argument("L6 expects exactly 6 joint values");
}
}
```
## 9. 二次封装建议
### 9.1 业务层包装器
建议封装一个 `L6Controller`,只暴露业务语义接口,例如:
- `openHand()`
- `prepareGrip()`
- `pinch()`
- `release()`
- `readStatus()`
不要让上层任务代码直接散落大量 `std::vector<uint8_t>` 常量。
### 9.2 型号能力分层
如果项目同时支持 `L6/L7/L10/L20`,建议分成:
- 公共接口层:只调用 `LinkerHandApi`
- 型号扩展层:只在确有必要时下钻到 `L6Hand`
这样既能复用业务逻辑,也能保留 L6 的特性能力。
### 9.3 基于当前仓库的事实约束
当前仓库中很多实现位于预编译动态库中,因此在做深度扩展时要区分两类问题:
- 头文件已经声明,但库内部行为未公开
- 头文件本身就没有声明
前者可以通过小样例验证;后者则需要新增头文件接口与实现。
## 10. 推荐阅读顺序
1. `include/LinkerHandApi.h`
2. `include/HandFactory.h`
3. `include/IHand.h`
4. `include/LinkerHandL6.h`
5. `src/main.cpp`
6. `examples/toolset_example.cpp`
7. `docs/API-Reference.md`
8. `docs/TROUBLESHOOTING.md`
# L6 灵巧手应用开发手册
## 1. 适用范围
本文面向使用 `LinkerHand-CPP-SDK` 开发 `L6/O6` 灵巧手上位机应用的工程师,重点覆盖:
- 开发环境准备
- L6 关节与数据模型
- 典型控制流程
- 触觉、状态、故障数据读取
- 应用层开发建议
本文内容基于当前仓库中的公开头文件、示例程序和构建脚本整理,适合作为二次开发入口文档。
## 2. 项目内的 L6 开发入口
L6 的开发主要有两条路径:
| 路径 | 入口 | 适用场景 |
|---|---|---|
| 通用业务接口 | `LinkerHandApi` | 快速接入、动作控制、通用状态查询 |
| L6 型号专用接口 | `linkerhand::hand::L6Hand` | 需要重调零、加速度、设备信息等 L6 专有能力 |
关联文件:
- `include/LinkerHandApi.h`:统一 API 入口
- `include/HandFactory.h`:型号与通信工厂
- `include/IHand.h`:抽象接口与异常约束
- `include/LinkerHandL6.h`:L6/O6 专有能力定义
- `examples/toolset_example.cpp`:交互式示例
- `src/main.cpp`:最小示例
## 3. 开发环境准备
### 3.1 软件环境
- Linux
- `x86_64` 或 `aarch64`
- CMake `3.15+`
- GCC `7+` 或 Clang `5+`
- `pthread`
### 3.2 构建 SDK
```bash
mkdir build
cd build
cmake ..
make
```
也可以使用仓库脚本:
```bash
./script.sh
```
### 3.3 CAN 通信准备
L6 当前仓库中的常规接入方式以 CAN 为主。典型配置:
```bash
sudo modprobe can
sudo modprobe can_raw
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
ip link show can0
```
如果设备接在 `can1`,对应替换接口名即可。
## 4. L6 运动与数据模型
### 4.1 关节顺序
`L6` 的位置控制数组长度固定为 `6`,关节顺序如下:
| 索引 | 含义 |
|---|---|
| `0` | 大拇指弯曲 |
| `1` | 大拇指横摆 |
| `2` | 食指弯曲 |
| `3` | 中指弯曲 |
| `4` | 无名指弯曲 |
| `5` | 小拇指弯曲 |
### 4.2 数值语义
- 位置范围:`0-255`
- 当前文档按仓库现有 API 说明采用如下语义:
- `0`:更接近完全弯曲
- `255`:更接近完全伸直
实际机械极限、零位、方向仍应以设备标定结果和设备手册为准。
### 4.3 L6 专有协议能力
从 `include/LinkerHandL6.h` 可见,L6 除基础控制外还定义了以下能力:
- 位置控制
- 速度设置
- 扭矩设置
- 加速度设置
- 重调零 `reHome()`
- 温度读取
- 故障码读取与清除
- 触觉矩阵读取
- 软件/硬件/机械版本读取
- 序列号读取
- 恢复出厂设置与参数保存
注意:这些能力并不都透出到 `LinkerHandApi`,部分需要直接使用 `L6Hand`。
## 5. 最小应用开发流程
### 5.1 使用统一 API 快速接入
```cpp
#include "LinkerHandApi.h"
#include <chrono>
#include <iostream>
#include <thread>
int main() {
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::RIGHT, "can0", 1000000);
std::vector<uint8_t> open_pose = {255, 255, 255, 255, 255, 255};
std::vector<uint8_t> pinch_pose = {160, 180, 20, 255, 255, 255};
hand.setSpeed(std::vector<uint8_t>(6, 180));
hand.setTorque(std::vector<uint8_t>(6, 200));
hand.fingerMove(open_pose);
std::this_thread::sleep_for(std::chrono::milliseconds(800));
hand.fingerMove(pinch_pose);
std::this_thread::sleep_for(std::chrono::milliseconds(800));
auto state = hand.getState();
auto fault = hand.getFaultCode();
std::cout << "joint count: " << state.size() << std::endl;
std::cout << "fault count: " << fault.size() << std::endl;
return 0;
}
```
推荐顺序:
1. 初始化对象
2. 设置速度和扭矩
3. 下发目标位姿
4. 等待动作完成
5. 读取状态/故障/温度/触觉数据
### 5.2 使用 L6 专有类获取更完整能力
```cpp
#include "LinkerHandL6.h"
#include <iostream>
int main() {
linkerhand::hand::L6Hand hand(static_cast<uint32_t>(HAND_TYPE::RIGHT), "can0", 1000000);
hand.setSpeed(std::vector<uint8_t>(6, 150));
hand.setTorque(std::vector<uint8_t>(6, 180));
hand.setAcceleration(std::vector<uint8_t>(6, 100));
std::cout << "version: " << hand.getVersion() << std::endl;
std::cout << "serial: " << hand.getSerialNumber() << std::endl;
return 0;
}
```
当应用需要以下能力时,优先使用 `L6Hand`:
- `setAcceleration`
- `getAcceleration`
- `reHome`
- `getSerialNumber`
- `getHardwareVersion`
- `getMechanicalVersion`
- `factoryReset`
- `saveParameters`
## 6. 典型应用模式
### 6.1 预设动作控制
适合演示、产线联调、抓取动作库调用。可直接参考 `examples/toolset_example.cpp` 中的 `L6_POSE_1`。
建议做法:
- 将常用动作封装为固定长度的 `std::vector<uint8_t>(6)`
- 每个动作之间保留 `100-1000ms` 过渡时间
- 动作切换前检查故障码
### 6.2 状态轮询
适合闭环可视化、日志记录、简易监控。
推荐读取项:
- `getState()`
- `getTemperature()`
- `getFaultCode()`
- `getForce()`
轮询周期建议从 `50-200ms` 起步,根据总线和上位机实时性要求调整。
### 6.3 触觉驱动应用
L6 头文件中定义了拇指、食指、中指、无名指、小指以及掌部触觉相关帧。当前示例程序对 `getForce()` 的使用方式是按五指矩阵读取并打印。
适合场景:
- 抓取接触检测
- 滑移趋势判断
- 触碰事件触发
- 人机交互实验
开发建议:
- 先记录空载基线
- 用阈值做一层滤波与触发
- 不要直接把原始矩阵值作为动作切换唯一条件
### 6.4 故障恢复
推荐在每轮任务前后调用:
- `getFaultCode()`
- 必要时 `clearFaultCode()`
如果应用直接使用 `L6Hand`,可进一步封装:
- 故障码非零立即停止新动作下发
- 清故障后重新回到张开位
- 重复故障时提示人工检查通信、供电和机构
## 7. 接口使用约束
### 7.1 向量长度必须严格匹配
L6 常用数组长度均应按 `6` 个关节处理,包括:
- `fingerMove`
- `setSpeed`
- `setTorque`
- `setAcceleration`
不要把 L10/L20 的示例长度直接复用到 L6。
### 7.2 并非所有型号都支持所有接口
`IHand` 中大量方法默认会抛出 `UnsupportedFeatureException`。这意味着:
- 某个接口在 `LinkerHandApi` 中存在
- 不等于当前型号一定实现了该接口
对跨型号应用,建议统一加异常处理。
### 7.3 动作控制要保留缓冲时间
SDK 接口是命令式下发,不会自动等待动作完成。应用层需要自己控制:
- 动作间隔
- 超时
- 重试
- 状态回读
### 7.4 当前仓库中实现以预编译库为主
当前仓库公开了头文件与二进制库,很多实现细节位于 `lib/x86_64/` 和 `lib/aarch64/` 下的 `.so` 中。开发时应以:
- 头文件签名
- 示例代码
- 现有文档
作为第一依据。
## 8. 推荐的应用层封装方式
建议把应用分成三层:
1. 设备适配层:封装 `LinkerHandApi` 或 `L6Hand`
2. 动作层:定义张开、握持、捏取、释放等动作模板
3. 任务层:把动作与视觉、力控、机械臂流程连接
一个稳定的应用封装至少应包含:
- 初始化与连接检测
- 安全张开位
- 动作超时控制
- 故障查询与恢复
- 数据日志
## 9. 调试建议
建议先跑仓库自带示例,再做业务接入:
```bash
./script.sh
```
或:
```bash
mkdir build
cd build
cmake ..
make
./toolset_example
```
优先验证:
- CAN 接口是否正常
- `getVersion()` 是否有返回
- `fingerMove()` 是否能完成张开/闭合
- `getState()` 和 `getFaultCode()` 是否能持续读取
## 10. 相关文档
- `docs/API-Reference.md`
- `docs/TROUBLESHOOTING.md`
- `docs/FAQ.md`
- `examples/README.md`
# L6 灵巧手关节开发 README
本文档面向 `linkerhand-cpp-sdk` 中 `L6` 灵巧手的关节功能开发、联调和二次封装。
目标是帮助开发者快速回答下面几个问题:
- `L6` 在 SDK 里怎么初始化
- 6 个关节的控制数据应该怎么组织
- 常用的关节开发接口有哪些
- 调试关节动作时推荐什么流程
- 如果要做更底层的 L6 能力开发,应该改哪里
## 1. 模型概览
`L6`/`O6` 是 6 关节型号,在当前 SDK 中由以下文件承载:
- 统一 API 入口:`include/LinkerHandApi.h`
- L6 专用实现:`include/LinkerHandL6.h`
- 公共枚举定义:`include/Common.h`
其中:
- `LinkerHandApi` 适合业务开发和上层应用集成
- `linkerhand::hand::L6Hand` 适合做 L6 专项能力开发、协议扩展和底层调试
## 2. L6 关节数据约定
从 `include/LinkerHandL6.h` 可知,L6 的核心关节控制帧按 `1-6` 号关节组织,长度固定为 `6`:
- 关节位置:`JOINT_POSITION`
- 力矩限制:`TORQUE_LIMIT`
- 关节速度:`JOINT_SPEED`
- 关节加速度:`JOINT_ACCELERATION`
这意味着所有面向 L6 的关节数组都应默认按 6 维组织,例如:
```cpp
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128};
std::vector<uint8_t> speed = {120, 120, 120, 120, 120, 120};
std::vector<uint8_t> torque = {180, 180, 180, 180, 180, 180};
```
推荐把这 6 个槽位统一命名为:
```text
joint1, joint2, joint3, joint4, joint5, joint6
```
注意:
- 当前仓库头文件明确了 L6 是 6 关节控制,但没有在公开文档里给出每个关节与具体手指机构的一一对应关系
- 在没有机械图纸、固件协议表或标定记录之前,建议先按 `joint1 ~ joint6` 做协议层开发
- 实机联调时再建立 “关节编号 -> 手指/自由度名称” 的映射表,避免早期写死错误语义
## 3. 推荐开发分层
### 3.1 上层业务开发
如果你的目标是:
- 下发关节角度
- 读取关节状态
- 做抓握动作编排
- 在现有 SDK 上快速做应用
优先使用 `LinkerHandApi`。
示例:
```cpp
#include "LinkerHandApi.h"
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
int main() {
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::RIGHT);
std::vector<uint8_t> speed = {100, 100, 100, 100, 100, 100};
std::vector<uint8_t> torque = {180, 180, 180, 180, 180, 180};
std::vector<uint8_t> open = {255, 255, 255, 255, 255, 255};
std::vector<uint8_t> close = {0, 0, 0, 0, 0, 0};
hand.setSpeed(speed);
hand.setTorque(torque);
hand.fingerMove(open);
std::this_thread::sleep_for(std::chrono::seconds(1));
hand.fingerMove(close);
std::this_thread::sleep_for(std::chrono::seconds(1));
auto state = hand.getState();
std::cout << "joint state size = " << state.size() << std::endl;
return 0;
}
```
### 3.2 底层功能开发
如果你的目标是:
- 调整 L6 专用协议
- 增加加速度、回零、参数保存等底层能力
- 扩展设备信息、触觉、故障处理逻辑
- 直接排查 L6 驱动收发问题
优先查看并使用 `linkerhand::hand::L6Hand`。
`include/LinkerHandL6.h` 中已经暴露出以下 L6 专用能力:
- `setJointPositions`
- `setJointPositionArc`
- `setSpeed`
- `setTorque`
- `setAcceleration`
- `reHome`
- `getCurrentStatus`
- `getCurrentStatusArc`
- `getSpeed`
- `getTorque`
- `getAcceleration`
- `getFaultCode`
- `clearFaultCode`
- `getForce`
- `getTemperature`
- `getVersion`
- `getSerialNumber`
- `getHardwareVersion`
- `getMechanicalVersion`
- `factoryReset`
- `saveParameters`
这部分适合做 L6 关节驱动能力的主开发面。
## 4. 关节开发建议流程
建议按下面顺序推进,能明显降低实机风险。
### 第一步:先确认基础连通
确认以下信息一致:
- 手型:`LINKER_HAND::L6`
- 左右手:`HAND_TYPE::LEFT` 或 `HAND_TYPE::RIGHT`
- 通信口:默认构造使用 `COMM_CAN_0`
- 如果是指定 CAN 通道,使用带 `canChannel` 和 `baudrate` 的构造函数
例如:
```cpp
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::RIGHT, "can0", 1000000);
```
建议首次联调先读信息,不先运动:
```cpp
auto version = hand.getVersion();
auto temp = hand.getTemperature();
auto fault = hand.getFaultCode();
```
### 第二步:单关节试动
第一次动关节时,不要六轴同时大幅运动,建议:
- 速度设置为低值
- 力矩限制设置为中低值
- 一次只改变一个关节
- 每次动作后读取状态和故障码
示例:
```cpp
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128};
std::vector<uint8_t> speed = {60, 60, 60, 60, 60, 60};
std::vector<uint8_t> torque = {100, 100, 100, 100, 100, 100};
hand.setSpeed(speed);
hand.setTorque(torque);
pose[0] = 150;
hand.fingerMove(pose);
```
### 第三步:建立关节语义映射
实机调试时,记录每个关节对应的实际运动效果,例如:
```text
joint1 -> 拇指弯曲
joint2 -> 食指弯曲
joint3 -> 中指弯曲
joint4 -> 无名指弯曲
joint5 -> 小指弯曲
joint6 -> 某个联动或姿态自由度
```
上面只是示例格式,不代表当前仓库已经确认的最终定义。
你应该在实机动作和结构设计图一致后,再把这张映射表固化到代码或文档中。
### 第四步:封装动作层
完成关节映射后,再继续封装:
- 张开
- 握拳
- 两指捏合
- 三指捏合
- 循环抓握
- 自定义姿态组
推荐做法是先保留底层 `joint1 ~ joint6` 数组,再在上层增加动作语义层,避免后面硬件版本调整时要大面积改代码。
## 5. 关节控制接口说明
### 5.1 位置控制
位置控制是最基础的开发入口:
```cpp
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128};
hand.fingerMove(pose);
```
说明:
- 数组长度必须与 L6 关节数一致
- 每个元素通常是 `0~255` 的范围值
- 实际机械含义需要结合 L6 机构定义和标定结果确认
### 5.2 弧度控制
如果你希望从更接近运动学的方式开发,可使用弧度接口:
```cpp
std::vector<double> pose_arc = {0.0, 0.2, 0.2, 0.2, 0.2, 0.1};
hand.fingerMoveArc(pose_arc);
```
适用场景:
- 上层算法输出弧度值
- 需要统一不同型号的角度控制接口
- 后续要接逆运动学或手势规划模块
### 5.3 速度控制
```cpp
std::vector<uint8_t> speed = {80, 80, 80, 80, 80, 80};
hand.setSpeed(speed);
```
建议:
- 联调初期使用低速
- 只有在动作方向和关节映射确认后,再逐步提速
### 5.4 力矩控制
```cpp
std::vector<uint8_t> torque = {120, 120, 120, 120, 120, 120};
hand.setTorque(torque);
```
建议:
- 初期避免满力矩
- 抓取脆弱目标时,应单独下调相关关节力矩
### 5.5 状态读取
```cpp
auto state = hand.getState();
auto speed_now = hand.getSpeed();
auto torque_now = hand.getTorque();
auto temperature = hand.getTemperature();
auto fault = hand.getFaultCode();
```
推荐在每个动作阶段都保留状态回读,便于排查:
- 命令已发送但未执行
- 关节卡死
- 力矩不足
- 温度异常
- 驱动报错
## 6. L6 底层开发关注点
如果你准备继续开发 `L6Hand` 实现,建议重点关注下面几类内容。
### 6.1 协议帧定义
L6 的协议属性在 `include/LinkerHandL6.h` 的 `L6FrameProperty` 中定义。
这里是新增关节能力、读写设备参数、扩展触觉读取时最关键的入口之一。
### 6.2 接收线程
`L6Hand` 内部包含:
- `receiveThread`
- `receiveResponse()`
- 多类缓存数据,如 `joint_position`、`joint_speeds`、`error_codes`
如果后续要增强稳定性,优先检查:
- 收包线程退出条件
- 多线程读写锁粒度
- 状态缓存是否会被旧帧覆盖
- 异常 CAN 帧的过滤和日志
### 6.3 设备参数与持久化
L6 还包含以下维护类能力:
- `reHome()`
- `factoryReset()`
- `saveParameters()`
这类操作有潜在风险,建议只在以下情况下使用:
- 已完成关节方向和零点确认
- 已有明确的标定流程
- 能保证操作后立即复核状态
## 7. 实机调试建议
### 建议做的事
- 先单关节,再多关节
- 先低速低力矩,再逐步放开
- 每次动作后都读取 `fault code`
- 为每个 joint 建立独立测试用例
- 记录左右手差异
- 将“协议编号”和“机械语义”分开管理
### 不建议直接做的事
- 首次上电就六关节满量程动作
- 未确认零点就做连续动作组
- 没有限速限力矩就抓取硬物
- 没有故障读取就长时间循环运行
## 8. 推荐的 L6 开发目录约定
如果你接下来要继续扩展仓库,推荐按下面方式组织:
```text
docs/
L6-Joint-Development-README.md
examples/
l6_joint_basic.cpp
l6_joint_debug.cpp
l6_action_group.cpp
tests/
unit/
test_L6JointMapping.cpp
test_L6CommandPacking.cpp
```
这样可以把:
- 文档
- 示例
- 测试
三部分都围绕 L6 独立起来,后续维护会轻松很多。
## 9. 开发起步模板
下面这段代码适合作为 L6 关节开发的最小起步模板:
```cpp
#include "LinkerHandApi.h"
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
int main() {
LinkerHandApi hand(LINKER_HAND::L6, HAND_TYPE::RIGHT);
std::vector<uint8_t> speed = {60, 60, 60, 60, 60, 60};
std::vector<uint8_t> torque = {100, 100, 100, 100, 100, 100};
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128};
hand.setSpeed(speed);
hand.setTorque(torque);
for (size_t joint = 0; joint < pose.size(); ++joint) {
auto test_pose = pose;
test_pose[joint] = 160;
hand.fingerMove(test_pose);
std::this_thread::sleep_for(std::chrono::milliseconds(800));
auto state = hand.getState();
auto fault = hand.getFaultCode();
std::cout << "joint " << joint + 1
<< " test, state size = " << state.size()
<< ", fault size = " << fault.size() << std::endl;
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::milliseconds(800));
}
return 0;
}
```
## 10. 当前文档结论
基于当前仓库代码,可以确认以下事实:
- `L6` 是 SDK 已支持型号
- `L6` 的关节控制长度为 6
- 统一开发入口是 `LinkerHandApi`
- L6 专用深度开发入口是 `linkerhand::hand::L6Hand`
- 目前仓库里缺少一份专门面向 L6 的清晰开发文档
- 目前公开代码没有直接给出 L6 六个关节的机械语义映射,需要通过实机标定补齐
如果后续你要继续推进,我建议下一步直接补两样内容:
1. `examples/l6_joint_basic.cpp`
2. `tests/unit/test_L6CommandPacking.cpp`
这样文档、示例和测试就能形成完整闭环。
# LinkerHand C++ SDK 命名规范改进指南
## 概述
本文档描述了 LinkerHand C++ SDK 的命名规范改进,这些改进旨在提高代码一致性、可维护性和可读性。
## 改进内容
### 1. 统一命名空间结构
所有手型号实现类已迁移到统一的 `linkerhand::hand` 命名空间:
**改进前:**
```cpp
namespace LinkerHandL10 {
class LinkerHand : public linkerhand::hand::IHand { ... };
}
```
**改进后:**
```cpp
namespace linkerhand {
namespace hand {
class L10Hand : public IHand { ... };
} // namespace hand
} // namespace linkerhand
```
### 2. 类名改进
不同型号的手现在使用不同的类名,便于区分:
| 型号 | 旧类名 | 新类名 | 命名空间 |
|------|--------|--------|---------|
| L6/O6 | `LinkerHandL6::LinkerHand` | `linkerhand::hand::L6Hand` | `linkerhand::hand` |
| L7 | `LinkerHandL7::LinkerHand` | `linkerhand::hand::L7Hand` | `linkerhand::hand` |
| L10 | `LinkerHandL10::LinkerHand` | `linkerhand::hand::L10Hand` | `linkerhand::hand` |
| L20 | `LinkerHandL20::LinkerHand` | `linkerhand::hand::L20Hand` | `linkerhand::hand` |
| L25/L21 | `LinkerHandL25::LinkerHand` | `linkerhand::hand::L25Hand` | `linkerhand::hand` |
| Modbus L10 | `ModbusLinkerHandL10::LinkerHand` | `linkerhand::hand::ModbusL10Hand` | `linkerhand::hand` |
### 3. 帧属性枚举重命名和改进
各型号的帧属性枚举已重命名,使用更清晰的命名,并改为使用 `enum class` 以避免命名冲突:
| 型号 | 旧枚举名 | 新枚举名 |
|------|---------|---------|
| L6/O6 | `LinkerHandL6::FRAME_PROPERTY` | `linkerhand::hand::L6FrameProperty` |
| L7 | `LinkerHandL7::FRAME_PROPERTY` | `linkerhand::hand::L7FrameProperty` |
| L10 | `LinkerHandL10::FRAME_PROPERTY` | `linkerhand::hand::L10FrameProperty` |
| L20 | `LinkerHandL20::FRAME_PROPERTY` | `linkerhand::hand::L20FrameProperty` |
| L25/L21 | `LinkerHandL25::FRAME_PROPERTY` | `linkerhand::hand::L25FrameProperty` |
**重要改进**:
- 枚举类型从 `typedef enum` 改为 `enum class`(C++11 强类型枚举)
- 解决了多个枚举类型之间的命名冲突问题
- 枚举值现在需要使用作用域限定符访问(如 `L6FrameProperty::JOINT_POSITION`)
**使用示例**:
```cpp
// 旧方式(已废弃,但仍可通过向后兼容别名使用)
LinkerHandL6::FRAME_PROPERTY prop = LinkerHandL6::FRAME_PROPERTY::JOINT_POSITION;
// 新方式(推荐)
linkerhand::hand::L6FrameProperty prop = linkerhand::hand::L6FrameProperty::JOINT_POSITION;
// 转换为整数(用于 CAN 帧)
uint8_t frameProperty = static_cast<uint8_t>(linkerhand::hand::L6FrameProperty::JOINT_POSITION);
```
### 4. 参数命名修正
修正了错误的参数命名:
**改进前(错误)**:
```cpp
LinkerHandApi(const LINKER_HAND &handJoint, ...);
LINKER_HAND handJoint_; // 这是手型号,不是关节
```
**改进后(正确)**:
```cpp
LinkerHandApi(const LINKER_HAND &handModel, ...);
LINKER_HAND handModel_; // 手型号(L6, L7, L10, L20, L21, L25 等)
```
**说明**:
- `handJoint` 命名不准确,因为这是手型号(Model),不是关节(Joint)
- 已统一修正为 `handModel`,更准确地表示手型号
## 向后兼容性
为了保持向后兼容,所有旧的命名空间和类名都通过 `using` 别名保留:
```cpp
// 向后兼容:在旧命名空间中提供别名
namespace LinkerHandL10 {
using FRAME_PROPERTY = linkerhand::hand::L10FrameProperty;
using LinkerHand = linkerhand::hand::L10Hand;
} // namespace LinkerHandL10
```
这意味着现有代码可以继续使用旧的命名,无需立即修改。
## 使用示例
### 使用新命名(推荐)
```cpp
#include "LinkerHandL10.h"
#include "HandFactory.h"
// 使用新的命名空间和类名
using namespace linkerhand;
auto hand = factory::HandFactory::createHand(
LINKER_HAND::L10,
HAND_TYPE::RIGHT,
COMM_CAN_0
);
// hand 的类型是 std::unique_ptr<hand::IHand>
// 实际类型是 hand::L10Hand
```
### 使用旧命名(向后兼容)
```cpp
#include "LinkerHandL10.h"
#include "HandFactory.h"
// 仍然可以使用旧的命名空间
LinkerHandL10::LinkerHand hand(0x27, "can0", 1000000);
```
## 迁移建议
### 阶段一:保持兼容(当前)
- ✅ 所有新命名已实现
- ✅ 向后兼容别名已添加
- ✅ 现有代码无需修改即可继续工作
### 阶段二:逐步迁移(推荐)
1. **新代码使用新命名**:所有新编写的代码应使用新的命名空间和类名
2. **更新文档和示例**:逐步更新文档和示例代码使用新命名
3. **代码审查**:在代码审查中鼓励使用新命名
### 阶段三:完全迁移(未来)
在未来版本中,可以考虑:
- 移除向后兼容别名(需要主版本号升级)
- 更新所有内部代码使用新命名
- 更新所有文档和示例
## 优势
1. **一致性**:所有型号使用统一的命名空间结构
2. **可读性**:类名直接反映型号(`L10Hand` vs `LinkerHand`)
3. **可维护性**:统一的命名空间便于管理和查找
4. **扩展性**:新型号可以轻松添加到同一命名空间
## 注意事项
1. **工厂类**:`HandFactory` 已更新为使用新类名,但返回类型仍然是 `IHand` 接口
2. **头文件**:头文件名暂时保持不变,未来可以考虑重命名
3. **枚举**:
- 帧属性枚举已重命名,枚举值保持不变
- 枚举类型已改为 `enum class`,需要使用作用域限定符访问枚举值
- 这解决了多个枚举类型之间的命名冲突问题(如 `JOINT_POSITION`、`TORQUE_LIMIT` 等)
- 如果需要将枚举值转换为整数,使用 `static_cast<uint8_t>()`
## 相关文件
- `include/LinkerHandL6.h` - L6/O6 型号实现
- `include/LinkerHandL7.h` - L7 型号实现
- `include/LinkerHandL10.h` - L10 型号实现
- `include/LinkerHandL20.h` - L20 型号实现
- `include/LinkerHandL25.h` - L25/L21 型号实现
- `include/ModbusLinkerHandL10.h` - Modbus L10 型号实现
- `include/HandFactory.h` - 工厂类
## 版本信息
- **改进版本**:1.1.7+
- **兼容性**:完全向后兼容
# 故障排查指南
本文档提供 LinkerHand-CPP-SDK 常见问题的排查和解决方案。
## 目录
- [编译问题](#编译问题)
- [运行时问题](#运行时问题)
- [通信问题](#通信问题)
- [API 使用问题](#api-使用问题)
- [性能问题](#性能问题)
- [获取帮助](#获取帮助)
---
## 编译问题
### 问题:找不到库文件
**错误信息**:
```
linkerhand_cpp_sdk library not found!
```
**可能原因**:
1. 库文件未正确安装
2. 架构不匹配(x86_64 vs aarch64)
3. CMake 查找路径不正确
**解决方案**:
1. 检查库文件是否存在:
```bash
ls -la lib/x86_64/ # 或 lib/aarch64/
```
2. 确认系统架构:
```bash
uname -m
```
3. 使用安装脚本重新安装:
```bash
./script.sh
# 选择选项 [2]: Install SDK
```
4. 手动指定库路径(在 CMakeLists.txt 中):
```cmake
set(LINKER_HAND_LIB ${CMAKE_CURRENT_SOURCE_DIR}/lib/x86_64/liblinkerhand_cpp_sdk.so)
```
---
### 问题:找不到头文件
**错误信息**:
```
fatal error: LinkerHandApi.h: No such file or directory
```
**可能原因**:
1. 头文件路径未正确配置
2. 头文件未安装
**解决方案**:
1. 检查头文件是否存在:
```bash
ls -la include/LinkerHandApi.h
```
2. 在 CMakeLists.txt 中添加包含目录:
```cmake
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
```
3. 如果已安装,检查安装路径:
```bash
ls /usr/local/include/linkerhand-cpp-sdk/
```
---
### 问题:链接错误
**错误信息**:
```
undefined reference to `LinkerHandApi::...`
```
**可能原因**:
1. 未链接库文件
2. 库文件版本不匹配
3. 缺少依赖库(如 pthread)
**解决方案**:
1. 确保在 CMakeLists.txt 中链接库:
```cmake
target_link_libraries(your_target ${LINKER_HAND_LIB} pthread)
```
2. 检查库文件完整性:
```bash
ldd lib/x86_64/liblinkerhand_cpp_sdk.so
```
3. 重新编译和安装 SDK
---
### 问题:枚举命名冲突编译错误
**错误信息**:
```
error: 'JOINT_POSITION' conflicts with a previous declaration
error: 'TORQUE_LIMIT' conflicts with a previous declaration
error: 'TOUCH_SENSOR_TYPE' conflicts with a previous declaration
```
**可能原因**:
在旧版本中,多个枚举类型(`L6FrameProperty`、`L7FrameProperty`、`L10FrameProperty` 等)使用 `typedef enum`,导致枚举值泄漏到外层命名空间,当多个头文件同时被包含时会发生命名冲突。
**解决方案**:
此问题已在最新版本中修复。所有枚举类型已改为使用 `enum class`(C++11 强类型枚举),每个枚举值都在自己的作用域内,不会发生命名冲突。
**如果使用旧版本**:
1. 升级到最新版本的 SDK
2. 如果必须使用旧版本,可以:
- 避免同时包含多个型号的头文件
- 使用前向声明和单独编译单元
- 使用命名空间别名隔离不同的枚举类型
**新版本使用方式**:
```cpp
// 使用作用域限定符访问枚举值
linkerhand::hand::L6FrameProperty prop = linkerhand::hand::L6FrameProperty::JOINT_POSITION;
// 转换为整数(用于 CAN 帧)
uint8_t frameProperty = static_cast<uint8_t>(linkerhand::hand::L6FrameProperty::JOINT_POSITION);
```
---
### 问题:CMake 版本过低
**错误信息**:
```
CMake 3.5 or higher is required
```
**解决方案**:
1. 升级 CMake:
```bash
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install cmake
# 或从源码编译最新版本
```
2. 检查 CMake 版本:
```bash
cmake --version
```
---
## 运行时问题
### 问题:程序崩溃或段错误
**可能原因**:
1. 通信接口未正确初始化
2. 设备未连接
3. 参数数组长度不匹配
4. 内存访问错误
**解决方案**:
1. 检查设备连接:
```bash
# CAN 总线
ip link show can0
cansend can0 123#DEADBEEF # 测试 CAN 通信
```
2. 检查参数数组长度:
```cpp
// L10 需要 10 个元素
if (pose.size() != 10) {
std::cerr << "错误: pose 数组长度应为 10" << std::endl;
return;
}
hand.fingerMove(pose);
```
3. 使用调试工具:
```bash
gdb ./your_program
# 或
valgrind --leak-check=full ./your_program
```
4. 添加错误检查:
```cpp
try {
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
// ...
} catch (const std::exception& e) {
std::cerr << "错误: " << e.what() << std::endl;
}
```
---
### 问题:设备无响应
**可能原因**:
1. 通信接口配置错误
2. 设备未上电
3. 通信协议不匹配
4. 设备地址错误
**解决方案**:
1. 检查设备电源和连接
2. 验证通信接口:
```cpp
// 尝试不同的通信接口
LinkerHandApi hand1(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_CAN_0);
LinkerHandApi hand2(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_CAN_1);
LinkerHandApi hand3(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_MODBUS);
LinkerHandApi hand4(LINKER_HAND::L10, HAND_TYPE::RIGHT, COMM_ETHERCAT);
```
3. 检查通信接口状态:
**CAN 总线**:
```bash
# 查看 CAN 接口
ip link show can0
# 启动 CAN 接口(如果未启动)
sudo ip link set can0 up type can bitrate 500000
# 监听 CAN 消息
candump can0
```
**ModBus**:
- 检查串口设备或网络连接
- 验证 ModBus 配置参数
**EtherCAT**:
- 使用 EtherCAT 主站工具检查网络状态
- 验证从站配置和连接
4. 检查设备 ID 和地址设置
---
### 问题:关节不运动或运动异常
**可能原因**:
1. 速度和扭矩设置不当
2. 参数值超出范围
3. 电机故障
4. 机械卡阻
**解决方案**:
1. 检查速度和扭矩设置:
```cpp
// 设置合适的速度和扭矩
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
hand.setSpeed(speed);
hand.setTorque(torque);
```
2. 检查参数范围:
```cpp
// 确保所有值在 0-255 范围内
for (auto& val : pose) {
if (val > 255) val = 255;
if (val < 0) val = 0;
}
```
3. 检查故障码:
```cpp
auto fault_code = hand.getFaultCode();
for (size_t i = 0; i < fault_code.size(); i++) {
if (fault_code[i] != 0) {
std::cout << "警告: 电机 " << i << " 故障码: "
<< static_cast<int>(fault_code[i]) << std::endl;
}
}
```
4. 检查温度:
```cpp
auto temperature = hand.getTemperature();
for (size_t i = 0; i < temperature.size(); i++) {
if (temperature[i] > 80) { // 假设阈值
std::cout << "警告: 电机 " << i << " 温度过高: "
<< static_cast<int>(temperature[i]) << std::endl;
}
}
```
---
## 通信问题
### 问题:通信接口连接失败
**错误现象**:
- 设备无响应
- 数据读取失败
- 通信超时
**可能原因**:
- 通信接口未正确配置
- 设备未连接或未上电
- 通信协议不匹配
- 权限问题
**解决方案**:
根据使用的通信协议,参考以下配置:
### CAN 总线通信问题
**错误现象**:
- 设备无响应
- 数据读取失败
- 通信超时
**解决方案**:
1. **检查 CAN 接口配置**:
```bash
# 查看 CAN 接口状态
ip link show can0
# 配置 CAN 接口
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
```
2. **检查 CAN 总线连接**:
```bash
# 测试 CAN 通信
cansend can0 123#DEADBEEF
candump can0
```
3. **检查权限**:
```bash
# 可能需要 root 权限或添加用户到 dialout 组
sudo usermod -a -G dialout $USER
# 重新登录后生效
```
4. **检查终端电阻**:
- CAN 总线两端需要 120Ω 终端电阻
- 检查硬件连接
### ModBus 通信问题
**错误现象**:
- ModBus 连接失败
- 数据读取超时
- 串口权限错误
**解决方案**:
1. **检查串口权限**:
```bash
# 添加用户到 dialout 组
sudo usermod -a -G dialout $USER
# 重新登录后生效
# 检查串口设备
ls -l /dev/ttyUSB* # USB 转串口
ls -l /dev/ttyS* # 串口
```
2. **检查串口配置**:
- 确认串口设备路径正确
- 检查波特率、数据位、停止位、校验位设置
- 验证 ModBus 从站地址
3. **测试 ModBus 通信**:
- 使用 ModBus 测试工具验证连接
- 检查网络连接(ModBus TCP/IP)
### EtherCAT 通信问题
**错误现象**:
- EtherCAT 主站无法识别从站
- 网络拓扑错误
- 同步失败
**解决方案**:
1. **检查 EtherCAT 主站配置**:
- 确保 EtherCAT 主站软件已正确安装
- 验证主站配置与硬件匹配
2. **检查网络拓扑**:
- 验证 EtherCAT 从站设备已正确连接
- 检查网络线缆和连接器
- 确认网络拓扑正确(环形或线性)
3. **检查从站状态**:
- 使用 EtherCAT 主站工具检查从站状态
- 验证从站配置和地址
4. **检查同步**:
- 确保 EtherCAT 网络同步正常
- 检查分布式时钟(DC)配置(如适用)
---
## API 使用问题
### 问题:参数数组长度错误
**错误现象**:
- 程序崩溃
- 关节运动异常
- 未定义行为
**解决方案**:
1. **根据型号使用正确的数组长度**:
```cpp
std::vector<uint8_t> pose;
switch (hand.handModel_) {
case LINKER_HAND::L6:
case LINKER_HAND::O6:
pose.resize(6);
break;
case LINKER_HAND::L7:
pose.resize(7);
break;
case LINKER_HAND::L10:
pose.resize(10);
break;
case LINKER_HAND::L20:
pose.resize(20);
break;
case LINKER_HAND::L21:
case LINKER_HAND::L25:
pose.resize(25);
break;
}
```
2. **添加参数验证**:
```cpp
void safeFingerMove(LinkerHandApi& hand, const std::vector<uint8_t>& pose) {
int expected_size = 0;
switch (hand.handModel_) {
case LINKER_HAND::L10: expected_size = 10; break;
case LINKER_HAND::L20: expected_size = 20; break;
// ...
}
if (pose.size() != expected_size) {
std::cerr << "错误: 数组长度应为 " << expected_size
<< ",实际为 " << pose.size() << std::endl;
return;
}
hand.fingerMove(pose);
}
```
---
### 问题:功能不支持
**错误现象**:
- 调用特定型号不支持的功能
- 无响应或错误
**解决方案**:
1. **检查型号支持**:
```cpp
// 仅 L20 支持 setCurrent
if (hand.handModel_ == LINKER_HAND::L20) {
hand.setCurrent(current);
} else {
std::cerr << "警告: setCurrent 仅支持 L20" << std::endl;
}
```
2. **参考功能支持矩阵**:
- 查看 [API 参考文档](API-Reference.md#版本兼容性)
- 了解各型号支持的功能
---
### 问题:返回值理解错误
**错误现象**:
- 数据解析错误
- 单位换算错误
**解决方案**:
1. **理解返回值格式**:
```cpp
// getForce() 返回三维向量
auto force = hand.getForce();
// force[finger][sensor_type][data]
// getTemperature() 返回温度值(可能需要换算)
auto temp = hand.getTemperature();
// 具体换算方式请参考设备手册
```
2. **参考 API 文档**:
- 查看 [API 参考文档](API-Reference.md) 了解返回值格式
- 参考设备手册了解数据含义
---
## 性能问题
### 问题:响应延迟
**可能原因**:
1. 通信延迟
2. 处理速度慢
3. 系统负载高
**解决方案**:
1. **优化通信频率**:
```cpp
// 避免过于频繁的 API 调用
// 添加适当的延时
std::this_thread::sleep_for(std::chrono::milliseconds(10));
```
2. **使用多线程**:
```cpp
// 在单独线程中处理传感器数据
std::thread sensor_thread([&hand]() {
while (running) {
auto force = hand.getForce();
// 处理数据...
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
```
3. **减少不必要的调用**:
- 缓存不需要实时更新的数据
- 批量处理操作
---
### 问题:CPU 占用过高
**可能原因**:
1. 轮询频率过高
2. 阻塞操作
3. 资源泄漏
**解决方案**:
1. **降低轮询频率**:
```cpp
// 从 10ms 改为 100ms
std::this_thread::sleep_for(std::chrono::milliseconds(100));
```
2. **使用事件驱动**:
- 避免轮询,使用回调或事件
- 仅在需要时读取数据
3. **检查资源管理**:
```cpp
// 确保正确释放资源
// 使用 RAII 原则
```
---
## 获取帮助
如果以上解决方案无法解决您的问题,请尝试以下方式获取帮助:
1. **查看文档**:
- [API 参考文档](API-Reference.md)
- [常见问题解答](FAQ.md)
- [README](README.md)
2. **检查示例代码**:
- 查看 `examples/` 目录下的示例
- 参考示例代码的使用方式
3. **联系技术支持**:
- **官方网站**: [https://linkerbot.cn](https://linkerbot.cn)
- **技术支持**: [https://linkerbot.cn/aboutUs](https://linkerbot.cn/aboutUs)
- **GitHub Issues**: [https://github.com/linker-bot/linkerhand-cpp-sdk/issues](https://github.com/linker-bot/linkerhand-cpp-sdk/issues)
4. **提供问题信息**:
在寻求帮助时,请提供以下信息:
- 错误信息或日志
- 系统信息(操作系统、架构)
- SDK 版本
- 设备型号
- 复现步骤
- 相关代码片段
# 示例代码说明
本文档介绍 LinkerHand-CPP-SDK 提供的示例代码及其使用方法。
## 目录
- [示例列表](#示例列表)
- [如何运行示例](#如何运行示例)
- [示例详细说明](#示例详细说明)
- [学习路径](#学习路径)
- [常见问题](#常见问题)
---
## 示例列表
| 示例文件 | 功能描述 | 适用型号 | 难度 |
|---------|---------|---------|------|
| `toolset_example.cpp` | 交互式工具集,演示所有 API 功能 | 所有型号 | 中级 |
| `o6_async_reader.cpp` | O6 后台采集示例,主线程只消费快照 | O6/L6 | 中级 |
| `action_group_show_l10.cpp` | L10 型号的动作组演示 | L10 | 初级 |
---
## 如何运行示例
### 方法一:使用安装脚本(推荐)
```bash
./script.sh
# 选择选项 [6]: Run examples
```
### 方法二:手动编译和运行
```bash
# 1. 构建项目
mkdir build && cd build
cmake ..
make
# 2. 运行示例
./toolset_example
./o6_async_reader
./action_group_show_l10
```
### 方法三:直接编译示例
```bash
# 编译 toolset_example
g++ -std=c++11 examples/toolset_example.cpp -I./include \
-L./lib/x86_64 -llinkerhand_cpp_sdk -lpthread -o toolset_example
# 编译 o6_async_reader
g++ -std=c++11 examples/o6_async_reader.cpp -I./include \
-L./lib/x86_64 -llinkerhand_cpp_sdk -lpthread -o o6_async_reader
# 运行
./toolset_example
./o6_async_reader
```
---
## 示例详细说明
### toolset_example.cpp
**功能描述**
交互式工具集,提供菜单界面,可以测试所有 API 功能。适合学习和调试。
**主要功能**:
1. 获取版本信息
2. 获取温度数据
3. 获取故障码
4. 获取电流数据
5. 获取扭矩数据
6. 获取速度数据
7. 获取压力传感信息
8. 循环获取关节状态
9. 执行预设动作
10. 清除故障码
**使用步骤**:
1. 运行程序
2. 选择机械手型号(L6/O6、L7、L10、L20、L21、L25)
3. 选择手部方向(左手/右手)
4. 选择通信接口(CAN0、CAN1、ModBus、EtherCAT)
5. 进入交互菜单,选择要测试的功能
**代码结构**:
```cpp
// 1. 选择型号
// 2. 选择手部方向
// 3. 选择通信接口
// 4. 创建 API 实例
LinkerHandApi hand(linkerhand, handType, channel);
// 5. 进入交互模式
interactiveMode(hand);
```
**预设动作**:
- **L6**: 单指循环弯曲
- **L7**: 握拳和张开
- **L10**:
- 手指循环弯曲
- 拇指与其他手指循环对指
- 手指侧摆
- 握拳和张开
- **L20**: 握拳和张开
- **L21/L25**: 握拳和张开
**使用示例**:
```bash
$ ./toolset_example
=========================
Example
=========================
Run Choose LinkerHand:
-------------------------
[1]: L6/O6
-------------------------
[2]: L7
-------------------------
[3]: L10
-------------------------
...
```
---
### o6_async_reader.cpp
**功能描述**
O6 后台采集示例。设备读取放到独立线程中执行,主线程只读取最近一次快照。
**主要功能**:
1. 周期性读取 `getState()`
2. 周期性读取 `getTorque()`
3. 周期性读取 `getTemperature()`
4. 周期性读取 `getFaultCode()`
5. 周期性读取 `getForce()`
6. 检测快照是否超时并标记 `STALE`
**适用场景**:
- 不希望采集逻辑阻塞主线程
- 需要持续监控 O6/L6 状态
- 希望把控制线程和读取线程拆开
**使用说明**:
- 默认参数为 `O6 + RIGHT + can0 + 1000000`
- 若项目还有控制线程,建议控制和读取分别使用独立 `LinkerHandApi` 实例
- 若读取长时间没有更新,输出会标记为 `STALE`
**使用示例**:
```bash
$ ./o6_async_reader
O6 async reader started.
Main thread only consumes cached snapshots.
Press Ctrl+C to stop.
```
---
### action_group_show_l10.cpp
**功能描述**
专门为 L10 型号设计的动作组演示程序。展示如何实现连续的动作序列。
**主要功能**:
- 演示 L10 型号的各种动作组合
- 展示动作序列的编程方式
- 适合学习动作控制的基本方法
**适用型号**: L10(适配球形拇指根部关节版本)
**代码特点**:
- 使用关节映射表管理关节状态
- 实现动作序列的循环执行
- 支持左右手(默认右手,修改 `HAND_TYPE::RIGHT` 为 `HAND_TYPE::LEFT` 可切换为左手)
**关节映射**:
```cpp
// L10 关节顺序
vector<string> joint_order = {
"joint1", // 拇指根部弯曲
"joint2", // 拇指侧摆
"joint3", // 食指根部弯曲
"joint4", // 中指根部弯曲
"joint5", // 无名指根部弯曲
"joint6", // 小指根部弯曲
"joint7", // 食指侧摆
"joint8", // 中指侧摆
"joint9", // 无名指侧摆
"joint10" // 拇指旋转
};
```
**使用示例**:
```bash
$ ./action_group_show_l10
# 程序会自动执行预设的动作序列
```
**注意事项**:
- 本示例仅支持 L10 型号
- 默认使用右手,如需左手请修改代码中的 `HAND_TYPE::RIGHT` 为 `HAND_TYPE::LEFT`
- 确保设备已正确连接
- 确保通信接口已正确配置(CAN 总线、ModBus 或 EtherCAT)
---
## 学习路径
### 初学者
1. **第一步**: 阅读 [README.md](../README.md) 了解基本概念
2. **第二步**: 运行 `action_group_show_l10.cpp` 查看基本动作
3. **第三步**: 阅读代码,理解关节控制的基本方法
4. **第四步**: 尝试修改代码,实现自己的动作
### 中级用户
1. **第一步**: 运行 `toolset_example.cpp` 熟悉所有 API
2. **第二步**: 阅读 [API 参考文档](../docs/API-Reference.md) 了解详细接口
3. **第三步**: 参考示例代码实现自己的应用
4. **第四步**: 学习传感器数据读取和处理
### 高级用户
1. **第一步**: 深入研究示例代码的实现细节
2. **第二步**: 优化代码性能
3. **第三步**: 实现复杂的动作序列
4. **第四步**: 集成到自己的项目中
---
## 代码学习要点
### 1. 初始化 API
```cpp
// 创建 API 实例
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
```
### 2. 设置速度和扭矩
```cpp
// 设置速度(5 个元素对应 5 根手指)
std::vector<uint8_t> speed = {200, 200, 200, 200, 200};
hand.setSpeed(speed);
// 设置扭矩
std::vector<uint8_t> torque = {255, 255, 255, 255, 255};
hand.setTorque(torque);
```
### 3. 控制关节运动
```cpp
// L10 需要 10 个关节值
std::vector<uint8_t> pose = {128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
hand.fingerMove(pose);
// 等待动作完成
std::this_thread::sleep_for(std::chrono::seconds(1));
```
### 4. 读取传感器数据
```cpp
// 获取压力数据
auto force = hand.getForce();
// 获取关节状态
auto state = hand.getState();
// 获取温度
auto temperature = hand.getTemperature();
```
### 5. 错误处理
```cpp
// 检查故障码
auto fault_code = hand.getFaultCode();
for (size_t i = 0; i < fault_code.size(); i++) {
if (fault_code[i] != 0) {
std::cout << "警告: 电机 " << i << " 故障码: "
<< static_cast<int>(fault_code[i]) << std::endl;
}
}
```
---
## 常见问题
### Q1: 示例程序无法运行?
**A**: 检查以下几点:
1. 确保已正确编译
2. 检查库文件路径是否正确
3. 确保设备已连接
4. 检查通信接口配置(CAN 总线等)
详细排查请参考 [故障排查指南](../docs/TROUBLESHOOTING.md)。
---
### Q2: 如何修改示例代码适配其他型号?
**A**:
1. 修改型号参数:
```cpp
// 从 L10 改为 L20
LinkerHandApi hand(LINKER_HAND::L20, HAND_TYPE::RIGHT);
```
2. 修改关节数组长度:
```cpp
// L20 需要 20 个关节值
std::vector<uint8_t> pose(20, 128);
```
3. 参考 [关节映射表](../README.md#关节映射表) 了解不同型号的关节配置
---
### Q3: 如何实现自己的动作序列?
**A**:
1. 定义动作数组:
```cpp
std::vector<std::vector<uint8_t>> actions = {
{255, 104, 255, 255, 255, 255, 255, 255, 255, 71}, // 动作1
{101, 60, 0, 0, 0, 0, 255, 255, 255, 51}, // 动作2
// ...
};
```
2. 循环执行:
```cpp
for (const auto& pose : actions) {
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
```
---
### Q4: 如何读取和处理传感器数据?
**A**: 参考 `toolset_example.cpp` 中的示例:
```cpp
// 获取压力数据
auto force_data = hand.getForce();
// 遍历每根手指
for (size_t finger = 0; finger < force_data.size(); finger++) {
// 处理数据...
}
```
详细说明请参考 [API 参考文档](../docs/API-Reference.md#getforce)。
---
### Q5: 示例代码中的延时时间如何设置?
**A**: 延时时间取决于:
- 动作的复杂度
- 设置的速度
- 设备的响应时间
**建议**:
- 简单动作: 0.5-1 秒
- 复杂动作: 1-2 秒
- 连续动作: 根据实际效果调整
```cpp
// 快速动作
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 标准动作
std::this_thread::sleep_for(std::chrono::seconds(1));
// 慢速动作
std::this_thread::sleep_for(std::chrono::seconds(2));
```
---
## 下一步
- 阅读 [API 参考文档](../docs/API-Reference.md) 了解完整的 API
- 查看 [故障排查指南](../docs/TROUBLESHOOTING.md) 解决遇到的问题
- 参考 [常见问题解答](../docs/FAQ.md) 获取更多帮助
- 贡献您的示例代码到项目
如有问题,请参考 [故障排查指南](../docs/TROUBLESHOOTING.md) 或联系技术支持。
// 本demo为适配球形拇指根部关节版本L10灵巧手,默认支持右手,如需左手,请将 HAND_TYPE::RIGHT 改为 HAND_TYPE::LEFT
#include <vector>
#include "LinkerHandApi.h"
using namespace std;
vector<string> joint_order = {"joint1", "joint2", "joint3", "joint4", "joint5", "joint6", "joint7", "joint8", "joint9", "joint10"};
map<string, int> hand = {
{"joint1", 255}, //拇指根部弯曲
{"joint2", 128}, //拇指侧摆
{"joint3", 255}, //食指根部弯曲
{"joint4", 255}, //中指根部弯曲
{"joint5", 255}, //无名指根部弯曲
{"joint6", 255}, //小指根部弯曲
{"joint7", 128}, //食指侧摆
{"joint8", 128}, //中指侧摆
{"joint9", 128}, //无名指侧摆
{"joint10", 255} //拇指旋转
};
int show_count = 0;
int show_count_obj = 0;
int show_step = 0;
bool running = true;
vector<uint8_t> showLeft() {
static vector<uint8_t> position;
show_count++;
if (show_count >= show_count_obj) {
show_count = 0;
switch (show_step) {
case 0:
show_step++;
show_count_obj = 100;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint3"] = 250;
hand["joint4"] = 250;
hand["joint5"] = 250;
hand["joint6"] = 250;
hand["joint7"] = 128;
hand["joint8"] = 128;
hand["joint9"] = 128;
hand["joint10"] = 250;
break;
case 1:
show_step++;
show_count_obj = 10;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint5"] = 0;
hand["joint6"] = 0;
hand["joint10"] = 250;
break;
case 2:
show_step++;
show_count_obj = 30;
hand["joint1"] = 40;
hand["joint2"] = 240;
hand["joint10"] = 80;
break;
case 3:
show_step++;
show_count_obj = 10;
hand["joint7"] = 200;
break;
case 4:
show_step++;
show_count_obj = 10;
hand["joint7"] = 50;
break;
case 5:
show_step++;
show_count_obj = 15;
hand["joint7"] = 128;
break;
case 6:
show_step++;
show_count_obj = 2;
hand["joint7"] = 50;
break;
case 7:
show_step++;
show_count_obj = 10;
hand["joint7"] = 128;
break;
case 8:
show_step++;
show_count_obj = 10;
hand["joint7"] = 50;
break;
case 9:
show_step++;
show_count_obj = 10;
hand["joint7"] = 128;
break;
case 10:
show_step++;
show_count_obj = 15;
hand["joint3"] = 100;
hand["joint4"] = 100;
break;
case 11:
show_step++;
show_count_obj = 15;
hand["joint3"] = 250;
hand["joint4"] = 250;
break;
case 12:
show_step++;
show_count_obj = 15;
hand["joint3"] = 100;
hand["joint4"] = 100;
break;
case 13:
show_step++;
show_count_obj = 15;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint3"] = 250;
hand["joint4"] = 250;
hand["joint5"] = 250;
hand["joint6"] = 250;
hand["joint7"] = 128;
hand["joint8"] = 128;
hand["joint9"] = 128;
hand["joint10"] = 250;
break;
case 14:
show_step++;
show_count_obj = 40;
hand["joint1"] = 40;
hand["joint2"] = 240;
hand["joint10"] = 80;
break;
case 15:
show_step++;
break;
case 16:
show_step++;
show_count_obj = 30;
hand["joint3"] = 10;
hand["joint4"] = 10;
hand["joint5"] = 10;
hand["joint6"] = 10;
break;
case 17:
show_step++;
show_count_obj = 15;
hand["joint6"] = 250;
break;
case 18:
show_step++;
show_count_obj = 15;
hand["joint5"] = 250;
break;
case 19:
show_step++;
show_count_obj = 15;
hand["joint4"] = 250;
break;
case 20:
show_step++;
show_count_obj = 15;
hand["joint3"] = 250;
break;
case 21:
show_step++;
show_count_obj = 20;
hand["joint1"] = 250;
hand["joint2"] = 110;
hand["joint10"] = 240;
break;
case 22:
show_step++;
show_count_obj = 20;
hand["joint1"] = 250;
hand["joint2"] = 10;
hand["joint10"] = 110;
break;
case 23:
show_step++;
show_count_obj = 40;
hand["joint1"] = 0;
hand["joint2"] = 10;
hand["joint10"] = 110;
break;
case 24:
show_step++;
show_count_obj = 30;
hand["joint1"] = 0;
hand["joint2"] = 240;
hand["joint10"] = 110;
break;
case 25:
show_step++;
show_count_obj = 50;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint10"] = 110;
break;
case 26:
show_step++;
show_count_obj = 10;
hand["joint7"] = 200;
hand["joint8"] = 200;
hand["joint9"] = 200;
break;
case 27:
show_step++;
show_count_obj = 15;
hand["joint7"] = 80;
hand["joint8"] = 80;
hand["joint9"] = 80;
break;
case 28:
show_step++;
show_count_obj = 20;
hand["joint7"] = 128;
hand["joint8"] = 128;
hand["joint9"] = 128;
break;
case 29:
show_step++;
show_count_obj = 15;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint10"] = 250;
break;
case 30:
show_step++;
break;
case 31:
show_step++;
break;
case 32:
show_step++;
break;
case 33:
show_step++;
show_count_obj = 15;
hand["joint3"] = 0;
hand["joint4"] = 250;
hand["joint5"] = 250;
hand["joint6"] = 250;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint10"] = 250;
break;
case 34:
show_step++;
show_count_obj = 15;
hand["joint4"] = 0;
break;
case 35:
show_step++;
show_count_obj = 15;
hand["joint5"] = 0;
break;
case 36:
show_step++;
show_count_obj = 15;
hand["joint6"] = 0;
break;
case 37:
show_step++;
show_count_obj = 40;
hand["joint1"] = 0;
break;
case 38:
show_step++;
show_count_obj = 40;
hand["joint1"] = 250;
hand["joint2"] = 230;
hand["joint10"] = 250;
break;
case 39:
show_step++;
show_count_obj = 30;
hand["joint3"] = 250;
hand["joint6"] = 250;
break;
case 40:
show_step++;
show_count_obj = 40;
hand["joint1"] = 10;
hand["joint2"] = 40;
hand["joint10"] = 60;
break;
case 41:
show_step++;
show_count_obj = 15;
hand["joint7"] = 80;
hand["joint9"] = 200;
break;
case 42:
show_step++;
show_count_obj = 15;
hand["joint7"] = 200;
hand["joint9"] = 80;
break;
case 43:
show_step++;
show_count_obj = 15;
hand["joint7"] = 80;
hand["joint9"] = 200;
break;
case 44:
show_step++;
show_count_obj = 15;
hand["joint7"] = 200;
hand["joint9"] = 80;
break;
case 45:
show_step++;
show_count_obj = 15;
hand["joint7"] = 128;
hand["joint9"] = 128;
break;
case 46:
show_step++;
show_count_obj = 50;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint3"] = 250;
hand["joint4"] = 250;
hand["joint5"] = 250;
hand["joint6"] = 250;
hand["joint7"] = 128;
hand["joint8"] = 128;
hand["joint9"] = 128;
hand["joint10"] = 250;
break;
case 47:
show_step++;
show_count_obj = 50;
hand["joint1"] = 130;
hand["joint2"] = 130;
hand["joint3"] = 130;
hand["joint4"] = 250;
hand["joint5"] = 250;
hand["joint6"] = 250;
hand["joint10"] = 90;
break;
case 48:
show_step++;
show_count_obj = 20;
hand["joint1"] = 250;
hand["joint3"] = 250;
hand["joint4"] = 120;
break;
case 49:
show_step++;
show_count_obj = 35;
hand["joint1"] = 120;
hand["joint4"] = 130;
hand["joint10"] = 60;
break;
case 50:
show_step++;
show_count_obj = 30;
hand["joint1"] = 250;
hand["joint4"] = 250;
hand["joint5"] = 145;
break;
case 51:
show_step++;
show_count_obj = 35;
hand["joint1"] = 113;
hand["joint2"] = 103;
hand["joint5"] = 128;
hand["joint10"] = 42;
break;
case 52:
show_step++;
show_count_obj = 30;
hand["joint1"] = 250;
hand["joint5"] = 250;
break;
case 53:
show_step++;
show_count_obj = 40;
hand["joint1"] = 118;
hand["joint2"] = 103;
hand["joint6"] = 120;
hand["joint10"] = 22;
break;
case 54:
show_step++;
show_count_obj = 20;
hand["joint1"] = 250;
hand["joint2"] = 250;
hand["joint3"] = 250;
hand["joint4"] = 250;
hand["joint5"] = 250;
hand["joint6"] = 250;
hand["joint7"] = 128;
hand["joint8"] = 128;
hand["joint9"] = 128;
hand["joint10"] = 250;
running = false;
break;
default:
break;
}
position.clear();
for (const auto& joint : joint_order) { // 按照固定的顺序提取关节值
std::cout << joint << " " << hand[joint] << std::endl;
position.push_back(static_cast<double>(hand[joint]));
}
}
return position;
}
int main() {
// 调用API接口
LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::LEFT);
hand.setSpeed({100, 100, 100, 100, 100});
hand.setTorque({200, 200, 200, 200, 200});
while (running) {
std::vector<uint8_t> action = showLeft();
hand.fingerMove(action);
std::this_thread::sleep_for(std::chrono::milliseconds(33));
}
return 0;
}
#include "LinkerHandApi.h"
#include "ErrorCode.h"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstdint>
#include <exception>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
namespace {
using ForceData = std::vector<std::vector<std::vector<uint8_t>>>;
using Clock = std::chrono::steady_clock;
constexpr std::chrono::milliseconds kPollInterval(100);
constexpr std::chrono::milliseconds kPrintInterval(200);
constexpr std::chrono::milliseconds kStaleAfter(600);
struct O6Snapshot {
uint64_t sequence = 0;
bool ready = false;
Clock::time_point updated_at{};
std::vector<uint8_t> state;
std::vector<uint8_t> torque;
std::vector<uint8_t> temperature;
std::vector<uint8_t> fault_code;
ForceData force;
std::string last_error;
};
std::string bytesToString(const std::vector<uint8_t> &values) {
if (values.empty()) {
return "[]";
}
std::ostringstream oss;
oss << "[";
for (size_t i = 0; i < values.size(); ++i) {
if (i != 0) {
oss << ' ';
}
oss << static_cast<int>(values[i]);
}
oss << "]";
return oss.str();
}
void appendError(O6Snapshot &snapshot, const std::string &label, const std::string &message) {
if (!snapshot.last_error.empty()) {
snapshot.last_error += " | ";
}
snapshot.last_error += label + ": " + message;
}
uint8_t maxSensorValue(const ForceData &force_data, size_t finger_index, size_t sensor_type_index) {
if (finger_index >= force_data.size()) {
return 0;
}
if (sensor_type_index >= force_data[finger_index].size()) {
return 0;
}
const auto &sensor_values = force_data[finger_index][sensor_type_index];
if (sensor_values.empty()) {
return 0;
}
return *std::max_element(sensor_values.begin(), sensor_values.end());
}
class O6AsyncReader {
public:
O6AsyncReader(HAND_TYPE hand_type,
std::string can_channel,
int baudrate,
std::chrono::milliseconds poll_interval)
: hand_(LINKER_HAND::O6, hand_type, can_channel, baudrate),
poll_interval_(poll_interval) {}
~O6AsyncReader() {
stop();
}
void start() {
if (running_.exchange(true)) {
return;
}
worker_ = std::thread(&O6AsyncReader::pollLoop, this);
}
void stop() {
if (!running_.exchange(false)) {
return;
}
if (worker_.joinable()) {
worker_.join();
}
}
O6Snapshot snapshot() const {
std::lock_guard<std::mutex> lock(snapshot_mutex_);
return snapshot_;
}
private:
template <typename Fn>
void readField(O6Snapshot &next, const char *name, Fn &&fn) {
try {
fn();
} catch (const linkerhand::UnsupportedFeatureException &e) {
appendError(next, name, std::string("unsupported - ") + e.what());
} catch (const std::exception &e) {
appendError(next, name, e.what());
}
}
void pollLoop() {
uint64_t sequence = 0;
while (running_.load()) {
const auto cycle_started = Clock::now();
O6Snapshot next;
next.sequence = ++sequence;
next.ready = true;
next.updated_at = cycle_started;
readField(next, "getState", [&]() { next.state = hand_.getState(); });
readField(next, "getTorque", [&]() { next.torque = hand_.getTorque(); });
readField(next, "getTemperature", [&]() { next.temperature = hand_.getTemperature(); });
readField(next, "getFaultCode", [&]() { next.fault_code = hand_.getFaultCode(); });
readField(next, "getForce", [&]() { next.force = hand_.getForce(); });
{
std::lock_guard<std::mutex> lock(snapshot_mutex_);
snapshot_ = std::move(next);
}
std::this_thread::sleep_until(cycle_started + poll_interval_);
}
}
LinkerHandApi hand_;
std::chrono::milliseconds poll_interval_;
std::atomic<bool> running_{false};
std::thread worker_;
mutable std::mutex snapshot_mutex_;
O6Snapshot snapshot_;
};
void printSnapshot(const O6Snapshot &snapshot) {
if (!snapshot.ready) {
std::cout << "waiting for first O6 snapshot..." << std::endl;
return;
}
const auto age = std::chrono::duration_cast<std::chrono::milliseconds>(
Clock::now() - snapshot.updated_at);
const bool stale = age > kStaleAfter;
const uint8_t thumb_force = maxSensorValue(snapshot.force, 0, 0);
const uint8_t index_force = maxSensorValue(snapshot.force, 1, 0);
std::cout << "seq=" << snapshot.sequence
<< " age=" << age.count() << "ms";
if (stale) {
std::cout << " STALE";
}
std::cout << '\n';
std::cout << "state : " << bytesToString(snapshot.state) << '\n';
std::cout << "torque : " << bytesToString(snapshot.torque) << '\n';
std::cout << "temperature : " << bytesToString(snapshot.temperature) << '\n';
std::cout << "fault : " << bytesToString(snapshot.fault_code) << '\n';
std::cout << "thumb_force : " << static_cast<int>(thumb_force)
<< ", index_force: " << static_cast<int>(index_force) << '\n';
if (!snapshot.last_error.empty()) {
std::cout << "last_error : " << snapshot.last_error << '\n';
}
}
} // namespace
int main() {
try {
// 读取使用独立 SDK 实例和独立线程。
// 如果你的控制线程因为 fingerMove 等调用卡住,主线程和这个读取线程不会一起被抢占。
// 若你还需要控制,请为控制路径再创建一个独立 LinkerHandApi 实例,不要和读取复用同一个对象。
O6AsyncReader reader(HAND_TYPE::RIGHT, "can0", 1000000, kPollInterval);
reader.start();
std::cout << "O6 async reader started." << std::endl;
std::cout << "Main thread only consumes cached snapshots." << std::endl;
std::cout << "Press Ctrl+C to stop." << std::endl;
while (true) {
const O6Snapshot snapshot = reader.snapshot();
printSnapshot(snapshot);
std::cout << "------------------------------" << std::endl;
std::this_thread::sleep_for(kPrintInterval);
}
} catch (const std::exception &e) {
std::cerr << "Failed to start O6 async reader: " << e.what() << std::endl;
return 1;
}
}
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <atomic>
#include <array>
#include "LinkerHandApi.h"
#include <iostream>
// 定义ANSI转义序列常量
const std::string RESET = "\033[0m";
const std::string BLACK = "\033[30m";
const std::string RED = "\033[31m";
const std::string GREEN = "\033[32m";
const std::string YELLOW = "\033[33m";
const std::string BLUE = "\033[34m";
const std::string MAGENTA = "\033[35m";
const std::string CYAN = "\033[36m";
const std::string WHITE = "\033[37m";
const std::string BG_BLACK = "\033[40m";
const std::string BG_RED = "\033[41m";
const std::string BG_GREEN = "\033[42m";
const std::string BG_YELLOW = "\033[43m";
const std::string BG_BLUE = "\033[44m";
const std::string BG_MAGENTA = "\033[45m";
const std::string BG_CYAN = "\033[46m";
const std::string BG_WHITE = "\033[47m";
const std::string BOLD = "\033[1m";
const std::string UNDERLINE = "\033[4m";
const std::string REVERSE = "\033[7m";
#define HAND_SPEED 200
#define HAND_TORQUE 255
// 用于标记程序是否应该退出
std::atomic<bool> running(true);
COMM_TYPE channel;
// 封装函数
void printColorLine2() {
#ifdef _WIN32
std::cout << YELLOW << "----------------------------------------------\n" << RESET;
#else
std::cout << YELLOW << "——————————————————————————————————————————————\n" << RESET;
#endif
}
void printColorLine1() {
#ifdef _WIN32
std::cout << YELLOW << "-------------------------\n" << RESET;
#else
std::cout << YELLOW << "—————————————————————————\n" << RESET;
#endif
}
void printNoColorLine() {
#ifdef _WIN32
std::cout << "----------------------------------------------" << std::endl;
#else
std::cout << "——————————————————————————————————————————————" << std::endl;
#endif
}
void exit()
{
std::cout << "Exit the program ..." << std::endl;
running = false;
std::string can_channel;
if (channel == COMM_CAN_0) can_channel = "can0";
if (channel == COMM_CAN_1) can_channel = "can1";
// system(std::string("sudo /usr/sbin/ip link set " + can_channel + " down").c_str());
exit(0);
}
// 辅助函数:将字节向量转换为十六进制字符串
std::string bytesToHex(const std::vector<uint8_t> &bytes)
{
std::string hexStr;
for (uint8_t byte : bytes)
{
hexStr += std::to_string(byte) + " ";
}
return hexStr;
}
// 辅助函数:将二维字节向量转换为十六进制字符串
std::string bytesToHex(const std::vector<std::vector<uint8_t>> &bytes)
{
std::string hexStr;
for (const auto &vec : bytes)
{
for (uint8_t byte : vec)
{
hexStr += std::to_string(byte) + " ";
}
hexStr += "\n";
}
return hexStr;
}
// 全局变量
int show_count = 0;
int show_count_obj = 0;
int show_step = 0;
std::map<std::string, int> hand = {
{"joint1", 250}, {"joint2", 250}, {"joint3", 250}, {"joint4", 250}, {"joint5", 250},
{"joint6", 250}, {"joint7", 250}, {"joint8", 250}, {"joint9", 250}, {"joint10", 250},
{"joint11", 250}, {"joint12", 0}, {"joint13", 0}, {"joint14", 0}, {"joint15", 0},
{"joint16", 250}, {"joint17", 250}, {"joint18", 250}, {"joint19", 250}, {"joint20", 250},
{"joint21", 250}, {"joint22", 250}, {"joint23", 250}, {"joint24", 250}, {"joint25", 250}
};
// L6 - 执行动作 - 单指
std::vector<std::vector<uint8_t>> L6_POSE_1 = {
{255, 255, 255, 255, 255, 255},
{0, 255, 255, 255, 255, 255},
{255, 0, 255, 255, 255, 255},
{255, 255, 0, 255, 255, 255},
{255, 255, 255, 0, 255, 255},
{255, 255, 255, 255, 0, 255},
{255, 255, 255, 255, 255, 0},
{255, 255, 255, 255, 255, 255}};
// L7 - 执行动作 - 手掌握拳
std::vector<std::vector<uint8_t>> L7_POSE_1 = {
{255, 255, 255, 255, 255, 255, 255},
{255, 255, 0, 255, 255, 255, 255},
{255, 255, 0, 0, 255, 255, 255},
{255, 255, 0, 0, 0, 255, 255},
{255, 255, 0, 0, 0, 0, 255},
{72, 90, 0, 0, 0, 0, 55}};
// L7 - 执行动作 - 张开
std::vector<uint8_t> L7_POSE_OPEN = {255, 255, 255, 255, 255, 255, 255};
// L10 - 执行动作 - 手指循环弯曲
std::vector<std::vector<uint8_t>> L10_POSE_1 = {
{35,140,255,255,255,255,255,255,255,30}, // 拇指弯曲
{255,70,255,255,255,255,255,255,255,255}, // 手掌张开
{255,70,0,255,255,255,255,255,255,255}, // 食指弯曲
{255,70,255,255,255,255,255,255,255,255}, // 手掌张开
{255,70,255,0,255,255,255,255,255,255}, // 中指弯曲
{255,70,255,255,255,255,255,255,255,255}, // 手掌张开
{255,70,255,255,0,255,255,255,255,255}, // 无名指弯曲
{255,70,255,255,255,255,255,255,255,255}, // 手掌张开
{255,70,255,255,255,0,255,255,255,255}, // 小拇指弯曲
{255,70,255,255,255,255,255,255,255,255} // 手掌张开
};
// L10 - 执行动作 - 拇指与其他手指循环对指
std::vector<std::vector<uint8_t>> L10_POSE_2 = {
{255, 70, 255, 255, 255, 255, 255, 255, 255, 255}, // 手掌张开
{145, 128, 146, 255, 255, 255, 255, 255, 255, 90}, // 拇指对食指
{255, 70, 255, 255, 255, 255, 255, 255, 255, 255}, // 手掌张开
{145, 88, 255, 148, 255, 255, 255, 255, 255, 75}, // 拇指对中指
{255, 70, 255, 255, 255, 255, 255, 255, 255, 255}, // 手掌张开
{145, 63, 255, 255, 150, 255, 255, 255, 255, 60}, // 拇指对无名指
{255, 70, 255, 255, 255, 255, 255, 255, 255, 255}, // 手掌张开
{147, 70, 255, 255, 255, 131, 255, 255, 120, 27}, // 拇指对小拇指
{255, 70, 255, 255, 255, 255, 255, 255, 255, 255} // 手掌张开
};
// L10 - 执行动作 - 手指侧摆
std::vector<std::vector<uint8_t>> L10_POSE_3 = {
{255, 255, 255, 255, 255, 255, 40, 88, 80, 63}, // 手掌张开
{255, 0, 255, 255, 255, 255, 40, 88, 80, 63}, // 拇指侧摆
{255, 70, 255, 255, 255, 255, 40, 88, 80, 0}, // 手掌张开
{255, 255, 255, 255, 255, 255, 40, 88, 80, 255}, // 拇指旋转
{255, 255, 255, 255, 255, 255, 40, 88, 80, 63}, // 手掌张开
{255, 255, 255, 255, 255, 255, 255, 88, 80, 63}, // 食指侧摆
{255, 255, 255, 255, 255, 255, 40, 88, 80, 63}, // 手掌张开
{255, 255, 255, 255, 255, 255, 40, 255, 80, 63}, // 无名指侧摆
{255, 255, 255, 255, 255, 255, 40, 88, 80, 63}, // 手掌张开
{255, 255, 255, 255, 255, 255, 40, 88, 255, 63}, // 小拇指侧摆
{255, 255, 255, 255, 255, 255, 40, 88, 80, 63} // 手掌张开
};
// L10 - 执行动作 - 张开
std::vector<uint8_t> L10_POSE_OPEN = {255, 104, 255, 255, 255, 255, 255, 255, 255, 71};
// L10 - 执行动作 - 握拳
std::vector<uint8_t> L10_POSE_CLOSE = {101, 60, 0, 0, 0, 0, 255, 255, 255, 51};
void interactiveMode(LinkerHandApi &hand)
{
int choice;
while (running)
{
// std::cout << YELLOW << "——————————————————————————————————————————————\n" << RESET;
std::cout << GREEN << "Run Choose Task:\n" << RESET;
printColorLine2();
std::cout << BLUE << " 1. Obtain version information\n" << RESET;
std::cout << BLUE << " 2. Obtain temperature\n" << RESET;
std::cout << BLUE << " 3. Obtain fault codes\n" << RESET;
std::cout << BLUE << " 4. Obtain current\n" << RESET;
std::cout << BLUE << " 5. Obtain torque\n" << RESET;
std::cout << BLUE << " 6. Obtain speed\n" << RESET;
std::cout << BLUE << " 7. Obtain pressure sensing information 1\n" << RESET;
std::cout << BLUE << " 8. Obtain pressure sensing information 2\n" << RESET;
std::cout << BLUE << " 9. Clear fault codes\n" << RESET;
std::cout << BLUE << "10. Loop to obtain the current finger joint status 10 times\n" << RESET;
std::cout << BLUE << "11. Execute preset actions\n" << RESET;
std::cout << RED << "0. Exit\n" << RESET;
printColorLine2();
std::cout << GREEN << "Please enter options: " << RESET;
std::cin >> choice;
if (choice != 1)
printNoColorLine();
std::string pose_str;
int arr[7];
std::vector<uint8_t> pose;
switch (choice)
{
case 1:
std::cout << hand.getVersion() << std::endl;
break;
case 2:
std::cout << "Obtain temperature: " << bytesToHex(hand.getTemperature()) << std::endl;
break;
case 3:
std::cout << "Obtain fault codes: " << bytesToHex(hand.getFaultCode()) << std::endl;
break;
case 4:
std::cout << "Obtain current: " << bytesToHex(hand.getCurrent()) << std::endl;
break;
case 5:
std::cout << "Obtain torque: " << std::endl;
for (size_t i = 0; i < 10; i++)
{
std::cout << bytesToHex(hand.getTorque()) << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
break;
case 6:
std::cout << "Obtain speed: " << bytesToHex(hand.getSpeed()) << std::endl;
break;
case 7:
for (size_t i = 0; i < 30; i++)
{
std::vector<std::vector<std::vector<uint8_t>>> touch_mats = hand.getForce();
// 手指名称表,顺序对应 touch_mats[0..4]
const std::array<const char*, 5> finger_name = {
"THUMB_TOUCH", "INDEX_TOUCH", "MIDDLE_TOUCH", "RING_TOUCH", "LITTLE_TOUCH"
};
for (size_t n = 0; n < touch_mats.size(); ++n) {
std::cout << finger_name[n] << ":\n";
for (const auto &row : touch_mats[n])
{
for (uint8_t val : row)
std::cout << std::setw(3) << static_cast<int>(val) << ' ';
std::cout << '\n';
}
std::cout << '\n';
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
break;
case 8:
std::cout << "NULL \n" << std::endl;
break;
case 9:
std::cout << "Clear fault codes\n" << std::endl;
hand.clearFaultCode();
break;
case 10:
for (size_t i = 0; i < 10; i++)
{
std::cout << bytesToHex(hand.getState()) << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
break;
case 11:
if (hand.handModel_ == LINKER_HAND::L6) {
std::cout << "L6 - Execute action" << std::endl;
for (size_t i = 0; i < 10; i++) {
for (const auto &pose : L6_POSE_1) {
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
} else if (hand.handModel_ == LINKER_HAND::L7) {
hand.setSpeed(std::vector<uint8_t>(7, HAND_SPEED)); // L7 need 7 speed
hand.setTorque(std::vector<uint8_t>(7, HAND_TORQUE)); // L7 need 7 torque
//---------------------------------------------------------
std::cout << "L7 - Execute action - Make a fist" << std::endl;
for (const auto &pose : L7_POSE_1)
{
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::seconds(1)); // 等待1秒
}
//---------------------------------------------------------
std::cout << "L7 - Execute action - Open hand" << std::endl;
hand.fingerMove(L7_POSE_OPEN);
std::this_thread::sleep_for(std::chrono::seconds(1));
//---------------------------------------------------------
}
else if (hand.handModel_ == LINKER_HAND::L10)
{
hand.setSpeed(std::vector<uint8_t>(5, HAND_SPEED)); // L10 need 5 speed
hand.setTorque(std::vector<uint8_t>(5, HAND_TORQUE)); // L10 need 5 torque
//---------------------------------------------------------
std::cout << "L10 - Execute action - Finger cycle bending" << std::endl;
for (const auto &pose : L10_POSE_1)
{
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
//---------------------------------------------------------
std::cout << "L10 - Execute action - Thumb and Circular Fingers" << std::endl;
for (const auto &pose : L10_POSE_2)
{
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
//---------------------------------------------------------
std::cout << "L10 - Execute action - Finger side swing" << std::endl;
for (const auto &pose : L10_POSE_3)
{
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
//---------------------------------------------------------
std::cout << "L10 - Execute action - Make a fist" << std::endl;
hand.fingerMove(L10_POSE_CLOSE);
std::this_thread::sleep_for(std::chrono::seconds(1));
//---------------------------------------------------------
std::cout << "L10 - Execute action - Open hand" << std::endl;
hand.fingerMove(L10_POSE_OPEN);
std::this_thread::sleep_for(std::chrono::seconds(1));
//---------------------------------------------------------
}
else if (hand.handModel_ == LINKER_HAND::L20)
{
hand.setSpeed(std::vector<uint8_t>(5, HAND_SPEED)); // L20 need 5 speed
//---------------------------------------------------------
std::cout << "L20 - Execute action - Make a fist" << std::endl;
std::vector<uint8_t> L20_POSE_CLOSE = {69, 0, 0, 0, 0, 32, 10, 100, 180, 240, 145, 255, 255, 255, 255, 0, 0, 0, 0, 0};
hand.fingerMove(L20_POSE_CLOSE);
std::this_thread::sleep_for(std::chrono::seconds(1));
//---------------------------------------------------------
std::cout << "L20 - Execute action - Open hand" << std::endl;
std::vector<uint8_t> L20_POSE_OPEN = {255, 255, 230, 255, 255, 255, 10, 100, 180, 240, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255};
hand.fingerMove(L20_POSE_OPEN);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
else if (hand.handModel_ == LINKER_HAND::L25 || hand.handModel_ == LINKER_HAND::L21)
{
hand.setSpeed(std::vector<uint8_t>(25, HAND_SPEED));
hand.setTorque(std::vector<uint8_t>(25, HAND_TORQUE));
//---------------------------------------------------------
// Open hand
std::vector<uint8_t> pos1_1 = {230, 0, 0, 15, 5, 250, 55, 80, 210, 202, 85, 0, 0, 0, 0, 250, 0, 40, 35, 5, 250, 0, 5, 0, 0};
std::vector<uint8_t> pos1_2 = {80, 255, 255, 255, 255, 180, 51, 51, 72, 202, 202, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
std::vector<uint8_t> pos1_3 = {75, 255, 255, 255, 255, 176, 51, 80, 210, 202, 202, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
// Make a fist
std::vector<uint8_t> pos2_1 = {230, 0, 0, 15, 5, 250, 55, 80, 210, 202, 85, 0, 0, 0, 0, 80, 0, 40, 35, 5, 250, 0, 5, 0, 0};
std::vector<uint8_t> pos2_2 = {230, 0, 0, 15, 5, 42, 55, 80, 210, 202, 85, 0, 0, 0, 0, 90, 0, 40, 35, 5, 120, 0, 5, 0, 0};
std::cout << "L25/L21 - Execute action - Make a fist" << std::endl;
hand.fingerMove(pos2_1);
std::this_thread::sleep_for(std::chrono::seconds(1));
hand.fingerMove(pos2_2);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "L25/L21 - Execute action - Open hand" << std::endl;
hand.fingerMove(pos1_1);
std::this_thread::sleep_for(std::chrono::seconds(1));
// hand.fingerMove(pos1_2);
// std::this_thread::sleep_for(std::chrono::seconds(1));
hand.fingerMove(pos1_3);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
break;
case 12:
hand.setSpeed(std::vector<uint8_t>(7, HAND_SPEED)); // L7 need 7 speed
hand.setTorque(std::vector<uint8_t>(7, HAND_TORQUE)); // L7 need 7 torque
//---------------------------------------------------------
std::cout << "请输入" << 7 << "个整数:" << std::endl;
for (int i = 0; i < 7; ++i) {
std::cin >> arr[i];
pose.push_back(arr[i]);
}
hand.fingerMove(pose);
std::this_thread::sleep_for(std::chrono::seconds(1));
break;
case 0:
exit();
break;
default:
std::cout << "Invalid option, please re-enter!\n";
}
if (choice != 1)
printNoColorLine();
}
}
int main()
{
std::cout << YELLOW << "=========================\n" << RESET;
std::cout << YELLOW << " Example\n" << RESET;
std::cout << YELLOW << "=========================\n" << RESET;
int choice;
LINKER_HAND linkerhand;
while (true)
{
std::cout << GREEN << "\nRun Choose LinkerHand:\n" << RESET;
printColorLine1();
std::cout << BLUE << "[1]: L6/O6\n" << RESET;
printColorLine1();
std::cout << BLUE << "[2]: L7\n" << RESET;
printColorLine1();
std::cout << BLUE << "[3]: L10\n" << RESET;
printColorLine1();
std::cout << BLUE << "[4]: L20\n" << RESET;
printColorLine1();
std::cout << BLUE << "[5]: L21\n" << RESET;
printColorLine1();
std::cout << BLUE << "[6]: L25\n" << RESET;
printColorLine1();
std::cout << RED << "[0]: Exit\n" << RESET;
printColorLine1();
std::cout << GREEN << "Please enter options: " << RESET;
std::cin >> choice;
switch (choice)
{
case 1:
linkerhand = LINKER_HAND::L6;
break;
case 2:
linkerhand = LINKER_HAND::L7;
break;
case 3:
linkerhand = LINKER_HAND::L10;
break;
case 4:
linkerhand = LINKER_HAND::L20;
break;
case 5:
linkerhand = LINKER_HAND::L21;
break;
case 6:
linkerhand = LINKER_HAND::L25;
break;
case 0:
exit();
break;
default:
std::cout << "Invalid option, please re-enter!\n";
continue;
}
break;
}
HAND_TYPE handType;
while (true)
{
printColorLine2();
std::cout << GREEN << "Run Choose Hand Direction:\n" << RESET;
printColorLine1();
std::cout << BLUE << "[1]: Left Hand\n" << RESET;
printColorLine1();
std::cout << BLUE << "[2]: Right Hand\n" << RESET;
printColorLine1();
std::cout << RED << "[0]: Exit\n" << RESET;
printColorLine1();
std::cout << GREEN << "Please enter options: " << RESET;
std::cin >> choice;
switch (choice)
{
case 1:
handType = HAND_TYPE::LEFT;
break;
case 2:
handType = HAND_TYPE::RIGHT;
break;
case 0:
exit();
break;
default:
std::cout << "Invalid option, please re-enter!\n";
continue;
}
break;
}
while (true)
{
printColorLine2();
std::cout << GREEN << "Run Choose CANBus:\n" << RESET;
printColorLine1();
std::cout << BLUE << "[1]: CAN0\n" << RESET;
printColorLine1();
std::cout << BLUE << "[2]: CAN1\n" << RESET;
printColorLine1();
std::cout << BLUE << "[3]: EtherCAT\n" << RESET;
printColorLine1();
std::cout << RED << "[0]: Exit\n" << RESET;
printColorLine1();
std::cout << GREEN << "Please enter options: " << RESET;
std::cin >> choice;
switch (choice)
{
case 1:
channel = COMM_CAN_0;
break;
case 2:
channel = COMM_CAN_1;
break;
case 3:
channel = COMM_ETHERCAT;
break;
case 0:
exit();
break;
default:
std::cout << "Invalid option, please re-enter!\n";
continue;
}
break;
}
// 调用API接口
LinkerHandApi hand(linkerhand, handType, channel);
// LinkerHandApi hand(LINKER_HAND::L10, HAND_TYPE::RIGHT);
printNoColorLine();
// 启动交互模式
interactiveMode(hand);
return 0;
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
#ifdef __linux__
#ifndef LINKERHAND_CAN_BUS_H
#define LINKERHAND_CAN_BUS_H
#include <iostream>
#include <iomanip>
#include <sstream>
#include <unistd.h>
#include <chrono>
#include <thread>
#include <queue>
#include <fcntl.h>
#include <mutex>
#include <atomic>
#include <cstring>
#include <cerrno>
#include "Common.h"
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h> // 包含 ifreq 和 IFNAMSIZ
#include <sys/ioctl.h> // 包含 ioctl
#include "ICanBus.h"
namespace linkerhand {
namespace communication {
/**
* @brief Linux CAN 总线实现
*/
class CanBus : public linkerhand::communication::ICanBus
{
public:
CanBus(const std::string& interface, int bitrate, const LINKER_HAND linkerhand);
~CanBus();
void send(const std::vector<uint8_t>& data, uint32_t can_id, const bool wait = false) override;
CANFrame recv(uint32_t& id) override;
void setReceiveTimeout(int seconds, int microseconds);
void updateSendRate();
void updateReceiveRate();
std::string printMillisecondTime();
private:
int socket_fd;
std::string interface;
int bitrate;
struct sockaddr_can addr;
struct ifreq ifr; // 确保 ifreq 是完整的类型
std::mutex mutex_send; // 互斥锁
std::mutex mutex_send2; // 互斥锁
std::mutex mutex_receive; // 互斥锁
std::mutex send_mutex; // 用于保护发送计数器和时间
std::atomic<int> send_count; // 发送计数器
std::chrono::steady_clock::time_point last_time; // 上一次记录时间
std::mutex receive_mutex; // 用于保护发送计数器和时间
std::atomic<int> receive_count; // 发送计数器
std::chrono::steady_clock::time_point receive_last_time; // 上一次记录时间
std::queue<struct can_frame> send_queue; // 发送队列
LINKER_HAND linker_hand;
};
} // namespace communication
} // namespace linkerhand
// 向后兼容:在全局命名空间中提供别名
namespace Communication = linkerhand::communication;
#endif
#endif // LINKERHAND_CAN_BUS_H
/*
* @Author: liangshaoteng liangshaoteng2012@163.com
* @Date: 2026-01-29 17:01:44
* @LastEditors: liangshaoteng liangshaoteng2012@163.com
* @LastEditTime: 2026-03-09 13:19:16
* @FilePath: /linkerhand/include/CanBusFactory.h
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
#ifndef LINKERHAND_CAN_BUS_FACTORY_H
#define LINKERHAND_CAN_BUS_FACTORY_H
#include "ICanBus.h"
#include "CanBus.h"
#include "PCANBus.h"
#if USE_ETHERCAT
#include "EtherCAT.h"
#endif
#include <stdexcept>
namespace linkerhand {
namespace communication {
class CanBusFactory
{
public:
static std::unique_ptr<ICanBus> createCanBus(
uint32_t handId,
const std::string& interfaceOrChannel,
int bitrate,
const LINKER_HAND linkerHand
)
{
(void)handId; // 标记为未使用,避免警告
#ifdef _WIN32
// Windows 平台
TPCANHandle channel = PCAN_USBBUS1;
TPCANBaudrate baudrate = PCAN_BAUD_1M;
if (interfaceOrChannel == "can1") {
channel = PCAN_USBBUS2;
}
return std::make_unique<linkerhand::communication::PCANBus>(channel, baudrate, linkerHand);
#else
return std::make_unique<linkerhand::communication::CanBus>(interfaceOrChannel, bitrate, linkerHand);
#if USE_ETHERCAT
else if (interfaceOrChannel == "ethercat") {
return std::make_unique<linkerhand::communication::EtherCAT>(handId);
}
#endif
// 默认情况:抛出异常或返回 nullptr
throw std::runtime_error("Unsupported CAN interface: " + interfaceOrChannel);
// 或者返回 nullptr:
// return nullptr;
#endif
}
};
} // namespace communication
} // namespace linkerhand
// 向后兼容:在全局命名空间中提供别名
namespace Communication = linkerhand::communication;
#endif // LINKERHAND_CAN_BUS_FACTORY_H
#ifndef LINKERHAND_CAN_FRAME_H
#define LINKERHAND_CAN_FRAME_H
#include <iostream>
#include <cstdint>
#include <vector>
#ifdef _WIN32
#include "PCANBasic.h"
using CanFrame = TPCANMsg;
#elif defined(__linux__)
#include <linux/can.h>
#include <linux/can/raw.h>
using CanFrame = struct can_frame;
#elif defined(__APPLE__) && defined(__MACH__)
std::cout << "This is macOS!" << std::endl;
#else
#error "Unsupported platform"
#endif
// 公共的 CAN 帧结构体
struct CANFrame
{
uint32_t can_id; // CAN 帧 ID
uint8_t can_dlc; // 数据长度
uint8_t data[8]; // 数据
};
#endif // LINKERHAND_CAN_FRAME_H
\ No newline at end of file
#ifndef LINKERHAND_COMMON_H
#define LINKERHAND_COMMON_H
// 为了与预编译库兼容,保持旧的枚举定义(非枚举类)
enum LINKER_HAND {
O6,
L6,
L7,
L10,
L20,
L21,
L25
};
enum HAND_TYPE {
LEFT = 0x28,
RIGHT = 0x27
};
enum COMM_TYPE {
COMM_CAN_0,
COMM_CAN_1,
COMM_MODBUS,
COMM_ETHERCAT
};
namespace linkerhand {
/**
* @brief 通用配置和版本信息
*/
namespace Common {
inline float current_hand_version = 1.0;
}
/**
* @brief 新的枚举类(用于未来版本,当前保持向后兼容)
*
* 注意:当前库使用旧的枚举类型,这些枚举类用于未来版本
*/
enum class HandModel {
O6,
L6,
L7,
L10,
L20,
L21,
L25
};
enum class HandType {
LEFT = 0x28,
RIGHT = 0x27
};
enum class CommType {
CAN_0,
CAN_1,
MODBUS,
ETHERCAT
};
} // namespace linkerhand
#define SEND_DEBUG 0
#define RECV_DEBUG 0
#endif // LINKERHAND_COMMON_H
#ifndef LINKERHAND_ERROR_CODE_H
#define LINKERHAND_ERROR_CODE_H
#include <system_error>
#include <string>
namespace linkerhand {
/**
* @brief 错误码枚举
*
* 定义 LinkerHand SDK 的所有错误类型
*/
enum class HandError {
Success = 0, ///< 成功
UnsupportedFeature, ///< 不支持的功能
CommunicationError, ///< 通信错误
InvalidParameter, ///< 无效参数
DeviceNotFound, ///< 设备未找到
Timeout, ///< 超时
InvalidState, ///< 无效状态
OperationFailed, ///< 操作失败
NotInitialized, ///< 未初始化
AlreadyInitialized, ///< 已初始化
OutOfRange, ///< 超出范围
UnknownError ///< 未知错误
};
/**
* @brief 错误类别
*
* 实现 std::error_category 接口,用于错误码分类
*/
class HandErrorCategory : public std::error_category {
public:
const char* name() const noexcept override {
return "LinkerHand";
}
std::string message(int ev) const override {
switch (static_cast<HandError>(ev)) {
case HandError::Success:
return "Success";
case HandError::UnsupportedFeature:
return "Unsupported feature";
case HandError::CommunicationError:
return "Communication error";
case HandError::InvalidParameter:
return "Invalid parameter";
case HandError::DeviceNotFound:
return "Device not found";
case HandError::Timeout:
return "Timeout";
case HandError::InvalidState:
return "Invalid state";
case HandError::OperationFailed:
return "Operation failed";
case HandError::NotInitialized:
return "Not initialized";
case HandError::AlreadyInitialized:
return "Already initialized";
case HandError::OutOfRange:
return "Out of range";
case HandError::UnknownError:
default:
return "Unknown error";
}
}
};
/**
* @brief 获取错误类别实例
*/
inline const HandErrorCategory& hand_error_category() {
static HandErrorCategory instance;
return instance;
}
/**
* @brief 将 HandError 转换为 std::error_code
*/
inline std::error_code make_error_code(HandError e) {
return std::error_code(static_cast<int>(e), hand_error_category());
}
/**
* @brief 异常类:LinkerHand 异常基类
*/
class HandException : public std::runtime_error {
public:
HandException(HandError error, const std::string& message)
: std::runtime_error(message), error_code_(error) {}
HandError error_code() const noexcept {
return error_code_;
}
private:
HandError error_code_;
};
/**
* @brief 异常类:不支持的功能
*/
class UnsupportedFeatureException : public HandException {
public:
explicit UnsupportedFeatureException(const std::string& feature_name)
: HandException(HandError::UnsupportedFeature,
"Unsupported feature: " + feature_name),
feature_name_(feature_name) {}
const std::string& feature_name() const noexcept {
return feature_name_;
}
private:
std::string feature_name_;
};
/**
* @brief 异常类:通信错误
*/
class CommunicationException : public HandException {
public:
explicit CommunicationException(const std::string& message)
: HandException(HandError::CommunicationError, message) {}
};
/**
* @brief 异常类:无效参数
*/
class InvalidParameterException : public HandException {
public:
explicit InvalidParameterException(const std::string& message)
: HandException(HandError::InvalidParameter, message) {}
};
} // namespace linkerhand
// 注册错误码到标准库
namespace std {
template<>
struct is_error_code_enum<linkerhand::HandError> : true_type {};
}
#endif // LINKERHAND_ERROR_CODE_H
#ifdef __linux__
#ifndef LINKERHAND_ETHERCAT_H
#define LINKERHAND_ETHERCAT_H
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <atomic>
#include <chrono>
#include <vector>
#include <thread>
#include <signal.h>
#include <mutex>
#include <ecrt.h>
#include "Common.h"
#include "ICanBus.h"
// constexpr uint32_t PERIOD_US = 10000; // 10ms
constexpr uint32_t PERIOD_US = 1000; // 10ms
/* ------------- EtherCAT 常量 ------------- */
constexpr unsigned int MASTER_INDEX = 0;
constexpr uint32_t cycle_ns = 8000000; // 8ms 周期
namespace linkerhand {
namespace communication {
/**
* @brief EtherCAT 通信实现
*/
class EtherCAT : public ICanBus {
public:
EtherCAT(const uint32_t handId);
~EtherCAT();
bool init();
void start();
void stop();
void send_can_data(const unsigned int id, const std::vector<uint8_t> &data);
void send(const std::vector<uint8_t>& data, uint32_t can_id, const bool wait = false) override;
CANFrame recv(uint32_t& id) override;
private:
void configure_dc();
void register_pdo_entries();
void run_cycle();
void ec_write(const uint32_t can_id, const std::vector<uint8_t> &data);
/* ------------- PDO 条目 ------------- */
ec_pdo_entry_info_t slave_pdo_entries[12] = {
// 主站 → 从站(RxPDO)
{0x7000, 0x01, 16}, // Control_cmd
{0x7000, 0x02, 32}, // Position_Target_1
{0x7000, 0x03, 32}, // Velocity_Target_1
{0x7000, 0x04, 32}, // Torque_Target_1
{0x7000, 0x05, 32}, // KP_1
{0x7000, 0x06, 32}, // KD_1
// 从站 → 主站(TxPDO)
{0x6000, 0x01, 16}, // MOTOR_NUM
{0x6000, 0x02, 16}, // MOTOR_ID_1
{0x6000, 0x03, 16}, // State_1
{0x6000, 0x04, 32}, // Position_Actual_1
{0x6000, 0x05, 32}, // Velocity_Actual_1
{0x6000, 0x06, 32}, // Torque_Actual_1
};
ec_pdo_info_t slave_pdos[2] = {
{0x1600, 6, slave_pdo_entries + 0},
{0x1A00, 6, slave_pdo_entries + 6},
};
ec_sync_info_t slave_syncs[5] = {
{0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{2, EC_DIR_OUTPUT, 1, slave_pdos + 0, EC_WD_ENABLE},
{3, EC_DIR_INPUT, 1, slave_pdos + 1, EC_WD_DISABLE},
{0xff}};
/* ------------- PDO 偏移量 ------------- */
unsigned int offset_control_cmd = 0;
unsigned int offset_position_target = 0;
unsigned int offset_velocity_target = 0;
unsigned int offset_torque_target = 0;
unsigned int offset_kp = 0;
unsigned int offset_kd = 0;
unsigned int offset_motor_num = 0;
unsigned int offset_motor_id = 0;
unsigned int offset_state = 0;
unsigned int offset_position_actual = 0;
unsigned int offset_velocity_actual = 0;
unsigned int offset_torque_actual = 0;
/* ------------- EtherCAT 句柄 ------------- */
ec_master_t *master = nullptr;
ec_domain_t *domain = nullptr;
uint8_t *domain_pd = nullptr;
bool running = true;
uint16_t cmd = 0x04;
uint32_t can_id_;
std::vector<uint8_t> can_data;
std::mutex mutex_send; // 互斥锁
uint16_t slave_alias;
uint16_t slave_position;
uint32_t vendor_id;
uint32_t product_code;
bool is_detection_hand;
uint32_t handId_;
};
} // namespace communication
} // namespace linkerhand
// 向后兼容:在全局命名空间中提供别名
namespace Communication = linkerhand::communication;
#endif // LINKERHAND_ETHERCAT_H
#endif
#ifndef LINKERHAND_HAND_FACTORY_H
#define LINKERHAND_HAND_FACTORY_H
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
#include "IHand.h"
#include "LinkerHandL6.h"
#include "LinkerHandL7.h"
#include "LinkerHandL10.h"
#include "LinkerHandL20.h"
#include "LinkerHandL25.h"
#include "ModbusLinkerHandL10.h"
#include "Common.h"
namespace linkerhand {
namespace factory {
/**
* @brief 手型号工厂类
*
* 根据手型号、手类型和通信类型创建对应的手实例
*/
class HandFactory {
public:
/**
* @brief 创建手实例
* @param type 手型号
* @param handId 手ID(左手/右手)
* @param commType 通信类型
* @return 手实例的智能指针
* @throws std::invalid_argument 如果参数无效
*/
static std::unique_ptr<hand::IHand> createHand(LINKER_HAND type, uint32_t handId, COMM_TYPE commType) {
if (handId != static_cast<uint32_t>(LEFT) &&
handId != static_cast<uint32_t>(RIGHT))
{
throw std::invalid_argument("Unsupported hand type");
}
std::string canChannel;
int baudrate = 1000000;
switch (commType)
{
case COMM_CAN_0:
canChannel = "can0";
break;
case COMM_CAN_1:
canChannel = "can1";
break;
case COMM_MODBUS:
canChannel = "modbus";
break;
case COMM_ETHERCAT:
canChannel = "ethercat";
break;
default:
throw std::invalid_argument("Unknown comm type");
break;
}
if (canChannel == "can0" || canChannel == "can1" || canChannel == "ethercat") {
switch (type) {
case O6:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L6Hand>(handId, canChannel, baudrate));
break;
case L6:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L6Hand>(handId, canChannel, baudrate));
break;
case L7:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L7Hand>(handId, canChannel, baudrate));
break;
case L10:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L10Hand>(handId, canChannel, baudrate));
break;
case L20:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L20Hand>(handId, canChannel, baudrate));
break;
case L21:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L25Hand>(handId, canChannel, baudrate, 1));
break;
case L25:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L25Hand>(handId, canChannel, baudrate, 0));
break;
default:
throw std::invalid_argument("Unknown hand type");
}
} else if (canChannel == "modbus") {
#if USE_RMAN
switch (type) {
case L10:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::ModbusL10Hand>(handId));
default:
throw std::invalid_argument("Unknown hand type");
break;
}
#else
throw std::runtime_error("ModBus support is disabled (USE_RMAN=0)");
#endif
}
return nullptr;
}
static std::unique_ptr<hand::IHand> createHand(LINKER_HAND type, uint32_t handId, const std::string canChannel, const int baudrate) {
if (handId != static_cast<uint32_t>(LEFT) &&
handId != static_cast<uint32_t>(RIGHT))
{
throw std::invalid_argument("Unsupported hand type");
}
if (containsIgnoreCase(canChannel, "can")) {
switch (type) {
case O6:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L6Hand>(handId, canChannel, baudrate));
break;
case L6:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L6Hand>(handId, canChannel, baudrate));
break;
case L7:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L7Hand>(handId, canChannel, baudrate));
break;
case L10:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L10Hand>(handId, canChannel, baudrate));
break;
case L20:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L20Hand>(handId, canChannel, baudrate));
break;
case L21:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L25Hand>(handId, canChannel, baudrate, 1));
break;
case L25:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::L25Hand>(handId, canChannel, baudrate, 0));
break;
default:
throw std::invalid_argument("Unknown hand type");
}
} else if (canChannel == "modbus") {
#if USE_RMAN
switch (type) {
case L10:
return std::unique_ptr<hand::IHand>(std::make_unique<hand::ModbusL10Hand>(handId));
default:
throw std::invalid_argument("Unknown hand type");
break;
}
#else
throw std::runtime_error("ModBus support is disabled (USE_RMAN=0)");
#endif
}
return nullptr;
}
private:
static std::string toLower(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}
static bool containsIgnoreCase(const std::string& str, const std::string& target) {
return toLower(str).find(toLower(target)) != std::string::npos;
}
};
} // namespace factory
} // namespace linkerhand
// 向后兼容:在全局命名空间中提供别名
using HandFactory = linkerhand::factory::HandFactory;
#endif // LINKERHAND_HAND_FACTORY_H
#ifndef LINKERHAND_ICANBUS_H
#define LINKERHAND_ICANBUS_H
#include <vector>
#include <cstdint>
#include <string>
#include "Common.h"
#include "CanFrame.h"
namespace linkerhand {
namespace communication {
/**
* @brief CAN 总线接口
*
* 定义 CAN 总线通信的标准接口
*/
class ICanBus {
public:
virtual ~ICanBus() = default;
/**
* @brief 发送 CAN 帧
* @param data 要发送的数据
* @param can_id CAN 帧 ID
* @param wait 是否等待发送完成(默认 false)
*/
virtual void send(const std::vector<uint8_t>& data, uint32_t can_id,
const bool wait = false) = 0;
/**
* @brief 接收 CAN 帧
* @param id CAN 帧 ID(输出参数)
* @return 接收到的 CAN 帧
*/
virtual CANFrame recv(uint32_t& id) = 0;
};
} // namespace communication
} // namespace linkerhand
// 向后兼容的别名
namespace Communication = linkerhand::communication;
#endif // LINKERHAND_ICANBUS_H
#ifndef LINKERHAND_ICOMMUNICATION_H
#define LINKERHAND_ICOMMUNICATION_H
#include <vector>
#include <cstdint>
namespace linkerhand {
namespace communication {
/**
* @brief 通信接口基类
*
* 定义通用的通信接口,支持 ModBus 等协议
*/
class ICommunication {
public:
virtual ~ICommunication() = default;
/**
* @brief 发送数据
* @param data 要发送的数据
* @param id 设备ID(输入输出参数)
* @param start_address 起始地址(默认0)
* @param num 数量(默认0)
*/
virtual void send(const std::vector<uint8_t>& data, uint32_t &id,
const int &start_address = 0, const int &num = 0) = 0;
/**
* @brief 接收数据
* @param id 设备ID(输入输出参数)
* @param start_address 起始地址(默认0)
* @param num 数量(默认0)
* @return 接收到的数据
*/
virtual std::vector<uint8_t> recv(uint32_t& id,
const int &start_address = 0,
const int &num = 0) = 0;
};
} // namespace communication
} // namespace linkerhand
#endif // LINKERHAND_ICOMMUNICATION_H
\ No newline at end of file
#ifndef LINKERHAND_IHAND_H
#define LINKERHAND_IHAND_H
#include <set>
#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <stdexcept>
#include "RangeToArc.h"
#include "Common.h"
#include "ErrorCode.h"
namespace linkerhand {
namespace hand {
/**
* @brief 灵巧手接口基类
*
* 定义所有手型号必须实现的基础接口
* 注意:不支持的方法会抛出异常而不是返回空值
*/
class IHand
{
public:
virtual ~IHand() = default;
// 设置关节位置
virtual void setJointPositions(const std::vector<uint8_t> &jointAngles) = 0;
virtual void setJointPositionArc(const std::vector<double> &jointAngles)
{
(void) jointAngles;
throw UnsupportedFeatureException("setJointPositionArc");
}
// 获取速度数据
virtual std::vector<uint8_t> getSpeed()
{
throw UnsupportedFeatureException("getSpeed");
}
// 设置关节速度
virtual void setSpeed(const std::vector<uint8_t> &speed)
{
(void) speed;
throw UnsupportedFeatureException("setSpeed");
}
// 获取当前关节位置
virtual std::vector<uint8_t> getCurrentStatus()
{
throw UnsupportedFeatureException("getCurrentStatus");
}
virtual std::vector<double> getCurrentStatusArc()
{
throw UnsupportedFeatureException("getCurrentStatusArc");
}
// 获取电机故障码
virtual std::vector<uint8_t> getFaultCode()
{
throw UnsupportedFeatureException("getFaultCode");
}
// 获取电机电流
virtual std::vector<uint8_t> getCurrent()
{
throw UnsupportedFeatureException("getCurrent");
}
// ------------------------------------------------------
// 获取压感数据
virtual std::vector<std::vector<uint8_t>> getForce(const int type)
{
(void)type;
throw UnsupportedFeatureException("getForce");
}
virtual std::vector<std::vector<std::vector<uint8_t>>> getForce()
{
throw UnsupportedFeatureException("getForce");
}
// 获取大拇指压感数据
virtual std::vector<uint8_t> getThumbForce()
{
throw UnsupportedFeatureException("getThumbForce");
}
// 获取食指压感数据
virtual std::vector<uint8_t> getIndexForce()
{
throw UnsupportedFeatureException("getIndexForce");
}
// 获取中指压感数据
virtual std::vector<uint8_t> getMiddleForce()
{
throw UnsupportedFeatureException("getMiddleForce");
}
// 获取无名指压感数据
virtual std::vector<uint8_t> getRingForce()
{
throw UnsupportedFeatureException("getRingForce");
}
// 获取小拇指压感数据
virtual std::vector<uint8_t> getLittleForce()
{
throw UnsupportedFeatureException("getLittleForce");
}
// ------------------------------------------------------
// 获取五指法向力
virtual std::vector<uint8_t> getNormalForce()
{
throw UnsupportedFeatureException("getNormalForce");
}
// 获取五指切向力
virtual std::vector<uint8_t> getTangentialForce()
{
throw UnsupportedFeatureException("getTangentialForce");
}
// 获取五指法向力方向
virtual std::vector<uint8_t> getTangentialForceDir()
{
throw UnsupportedFeatureException("getTangentialForceDir");
}
// 获取五指接近感应
virtual std::vector<uint8_t> getApproachInc()
{
throw UnsupportedFeatureException("getApproachInc");
}
// ------------------------------------------------------
// 设置扭矩 L20暂不支持
virtual void setTorque(const std::vector<uint8_t> &torque)
{
(void)torque;
throw UnsupportedFeatureException("setTorque");
}
// 获取电机扭矩 L20暂不支持
virtual std::vector<uint8_t> getTorque()
{
throw UnsupportedFeatureException("getTorque");
}
// 获取电机温度 L20暂不支持
virtual std::vector<uint8_t> getTemperature()
{
throw UnsupportedFeatureException("getTemperature");
}
// 获取版本号 目前仅支持L10
virtual std::string getVersion()
{
throw UnsupportedFeatureException("getVersion");
}
// 获取设备ID L20协议
virtual std::vector<uint8_t> getUID()
{
throw UnsupportedFeatureException("getUID");
}
// 手指堵转或过流判断计数阀值 L20协议
virtual std::vector<uint8_t> getRotorLockCount()
{
throw UnsupportedFeatureException("getRotorLockCount");
}
// 清除电机故障码 目前仅支持L20
virtual void clearFaultCode(const std::vector<uint8_t> &code)
{
(void)code;
throw UnsupportedFeatureException("clearFaultCode");
}
// 设置电流 目前仅支持L20
virtual void setCurrent(const std::vector<uint8_t> &current)
{
(void)current;
throw UnsupportedFeatureException("setCurrent");
}
// 设置电机使能 目前仅支持L25
virtual void setMotorEnable(const std::vector<uint8_t> &enable)
{
(void)enable;
throw UnsupportedFeatureException("setMotorEnable");
}
// 设置电机使能 目前仅支持L25
virtual void setMotorDisable(const std::vector<uint8_t> &disable)
{
(void)disable;
throw UnsupportedFeatureException("setMotorDisable");
}
// ---------------------------------------------------------------------
virtual std::vector<uint8_t> getSubVector(const std::vector<uint8_t> &vec)
{
std::vector<uint8_t> result;
if (vec.size() > 1) result.insert(result.end(), vec.begin() + 1, vec.end());
return result;
}
virtual std::vector<uint8_t> getSubVector(const std::vector<uint8_t>& vec1, const std::vector<uint8_t>& vec2)
{
std::vector<uint8_t> result;
if (vec1.size() > 1) result.insert(result.end(), vec1.begin() + 1, vec1.end());
if (vec2.size() > 1) result.insert(result.end(), vec2.begin() + 1, vec2.end());
return result;
}
virtual std::string getCurrentTime()
{
// 获取当前时间点
auto now = std::chrono::high_resolution_clock::now();
// 使用std::put_time格式化时间点为字符串
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
// 获取微秒部分并添加到字符串中
auto duration = now.time_since_epoch();
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration % std::chrono::seconds(1)).count();
// 只保留毫秒部分
int milliseconds = microseconds / 1000;
ss << "." << std::setfill('0') << std::setw(3) << milliseconds;
// 微妙
// ss << "." << std::setfill('0') << std::setw(6) << microseconds;
// 打印格式化的时间字符串
// std::cout << "send time: " << ss.str() << std::endl;
return ss.str();
}
};
} // namespace hand
} // namespace linkerhand
#endif // LINKERHAND_IHAND_H
#ifndef LINKERHAND_API_H
#define LINKERHAND_API_H
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include "HandFactory.h"
#include "Common.h"
#include "IHand.h"
/**
* @brief LinkerHand API 主类
*
* 提供统一的接口用于控制各种型号的灵巧手设备
*
* 注意:为了与预编译库兼容,此类保持在全局命名空间
*/
class LinkerHandApi
{
public:
/**
* @brief 构造函数
* @param handModel 手型号(LINKER_HAND 枚举)
* @param handType 手类型(左手/右手)
* @param commType 通信类型(默认 CAN_0)
*/
LinkerHandApi(const LINKER_HAND &handModel, const HAND_TYPE &handType,
const COMM_TYPE commType = COMM_CAN_0);
LinkerHandApi(const LINKER_HAND &handModel, const HAND_TYPE &handType,
const std::string canChannel, const int baudrate);
~LinkerHandApi();
// 设置关节位置
void fingerMove(const std::vector<uint8_t> &pose);
void fingerMoveArc(const std::vector<double> &pose);
// 设置速度
void setSpeed(const std::vector<uint8_t> &speed);
// 设置扭矩
void setTorque(const std::vector<uint8_t> &torque);
// 获取压感
std::vector<std::vector<std::vector<uint8_t>>> getForce();
// 获取速度
std::vector<uint8_t> getSpeed();
// 获取当前关节状态
std::vector<uint8_t> getState();
std::vector<double> getStateArc();
// 获取版本号
std::string getVersion();
// ----------------------------------------------------------
// 获取电机温度
std::vector<uint8_t> getTemperature();
// 获取电机故障码
std::vector<uint8_t> getFaultCode();
// 获取当前电流
std::vector<uint8_t> getCurrent();
// 获取当前最大扭矩
std::vector<uint8_t> getTorque();
// ------------------------- 待开发 --------------------------
// 设置电流 目前仅支持L20
void setCurrent(const std::vector<uint8_t> &current);
// 清除电机故障码 目前仅支持L20
void clearFaultCode(const std::vector<uint8_t> &torque = std::vector<uint8_t>(5, 1));
// 设置电机使能 目前仅支持L25
void setEnable(const std::vector<uint8_t> &enable = std::vector<uint8_t>(5, 0));
// 设置电机使能 目前仅支持L25
void setDisable(const std::vector<uint8_t> &disable = std::vector<uint8_t>(5, 1));
private:
// 获取法向压力
void getNormalForce();
// 获取切向压力
void getTangentialForce();
// 获取切向压力方向
void getTangentialForceDir();
// 获取接近感应
void getApproachInc();
private:
std::unique_ptr<linkerhand::hand::IHand> hand;
uint32_t handId;
public:
LINKER_HAND handModel_; // 手型号(L6, L7, L10, L20, L21, L25 等)
HAND_TYPE handType_;
};
// 在新命名空间中提供类型别名(用于未来版本)
namespace linkerhand {
namespace api {
using LinkerHandApi = ::LinkerHandApi;
} // namespace api
} // namespace linkerhand
#endif // LINKERHAND_API_H
#ifndef LINKERHAND_L10_H
#define LINKERHAND_L10_H
#include <thread>
#include <mutex>
#include <queue>
#include <iostream>
#include <sstream>
#include <chrono>
#include <condition_variable>
#include "IHand.h"
#include "CanBusFactory.h"
namespace linkerhand {
namespace hand {
// L10 型号的帧属性枚举
enum class L10FrameProperty
{
// INVALID_FRAME_PROPERTY = 0x00, // 无效的can帧属性
JOINT_POSITION_RCO = 0x01, // 关节1-6的关节位置
TORQUE_LIMIT = 0x02, // 五根手指的转矩限制
TORQUE_LIMIT_2 = 0x03, // 五根手指的转矩限制2
JOINT_POSITION2_RCO = 0x04, // 关节7-10的关节位置
JOINT_SPEED = 0x05, // 五根手指的速度
JOINT_SPEED_2 = 0x06, // 五根手指的速度2
REQUEST_DATA_RETURN = 0x09, // 获取所有关节位置和压力
// JOINT_POSITION_N = 0x11,
// MAX_PRESS_N = 0x12,
HAND_NORMAL_FORCE = 0X20, // 五个手指的法向压力
HAND_TANGENTIAL_FORCE = 0X21, // 五个手指的切向压力
HAND_TANGENTIAL_FORCE_DIR = 0X22, // 五个手指的切向方向
HAND_APPROACH_INC = 0X23, // 五个手指指接近感应
THUMB_ALL_DATA = 0x28, // 大拇指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
INDEX_FINGER_ALL_DATA = 0x29, // 食指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
MIDDLE_FINGER_ALL_DATA = 0x30, // 中指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
RING_FINGER_ALL_DATA = 0x31, // 无名指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
LITTLE_FINGER_ALL_DATA = 0x32, // 小拇指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
MOTOR_TEMPERATURE_1 = 0x33, // 电机温度1
MOTOR_TEMPERATURE_2 = 0x34, // 电机温度2
MOTOR_FAULT_CODE_1 = 0x35, // 电机故障码1
MOTOR_FAULT_CODE_2 = 0x36, // 电机故障码2
LINKER_HAND_VERSION = 0X64, // 版本号
// 新压感
TOUCH_SENSOR_TYPE = 0xB0, // 触觉传感器类型
THUMB_TOUCH = 0xB1, // 大拇指触觉传感
INDEX_TOUCH = 0xB2, // 食指触觉传感
MIDDLE_TOUCH = 0xB3, // 中指触觉传感
RING_TOUCH = 0xB4, // 无名指触觉传感
LITTLE_TOUCH = 0xB5, // 小拇指触觉传感
PALM_TOUCH = 0xB6, // 手掌指触觉传感
};
/**
* @brief L10 型号灵巧手实现类
*
* 提供 L10 型号的所有功能实现
*/
class L10Hand : public IHand
{
public:
L10Hand(uint32_t handId, const std::string &canChannel, int baudrate);
~L10Hand();
// 设置关节位置
void setJointPositions(const std::vector<uint8_t> &jointAngles) override;
void setJointPositionArc(const std::vector<double> &jointAngles) override;
// 设置最大扭矩
void setTorque(const std::vector<uint8_t> &torque) override;
// 设置关节速度
void setSpeed(const std::vector<uint8_t> &speed) override;
// 获取当前速度
std::vector<uint8_t> getSpeed() override;
// 获取当前关节状态
std::vector<uint8_t> getCurrentStatus() override;
std::vector<double> getCurrentStatusArc() override;
//--------------------------------------------------------------------
// 获取所有压感数据
std::vector<std::vector<std::vector<uint8_t>>> getForce() override;
// 获取五个手指的法向压力
std::vector<uint8_t> getNormalForce() override;
// 获取五个手指的切向压力
std::vector<uint8_t> getTangentialForce() override;
// 获取五个手指的切向方向
std::vector<uint8_t> getTangentialForceDir() override;
// 获取五个手指指接近感应
std::vector<uint8_t> getApproachInc() override;
//--------------------------------------------------------------------
// 获取版本信息
std::string getVersion() override;
// 获取电机温度
std::vector<uint8_t> getTemperature() override;
// 获取电机故障码
std::vector<uint8_t> getFaultCode() override;
// 获取电机电流
std::vector<uint8_t> getCurrent() override; // 暂时无用
// 获取所有关节位置和压力
std::vector<uint8_t> requestAllStatus(); // 暂时无用
// 获取当前扭矩
std::vector<uint8_t> getTorque() override;
private:
uint32_t handId;
std::unique_ptr<Communication::ICanBus> bus;
std::thread receiveThread;
bool running;
std::mutex responseMutex;
void receiveResponse();
std::queue<std::vector<uint8_t>> responseQueue; // 通用响应队列
std::condition_variable queueCond; // 通用队列条件变量
std::mutex queueMutex; // 通用队列互斥锁
// 队列和条件变量
std::vector<uint8_t> joint_position;
std::vector<uint8_t> joint_position2;
std::vector<uint8_t> joint_speed;
std::vector<uint8_t> joint_speed_2;
std::vector<uint8_t> normal_force;
std::vector<uint8_t> tangential_force;
std::vector<uint8_t> tangential_force_dir;
std::vector<uint8_t> approach_inc;
std::vector<uint8_t> thumb_pressure;
std::vector<uint8_t> index_finger_pressure;
std::vector<uint8_t> middle_finger_pressure;
std::vector<uint8_t> ring_finger_pressure;
std::vector<uint8_t> little_finger_pressure;
std::vector<std::vector<std::vector<uint8_t>>> touch_mats;
// 最大扭矩
std::vector<uint8_t> max_torque;
std::vector<uint8_t> max_torque_2;
// 电机温度
std::vector<uint8_t> motorTemperature_1;
std::vector<uint8_t> motorTemperature_2;
// 电机故障码
std::vector<uint8_t> motorFaultCode_1;
std::vector<uint8_t> motorFaultCode_2;
// 版本信息
std::vector<uint8_t> version;
uint8_t sensor_type = 0;
};
} // namespace hand
} // namespace linkerhand
// 向后兼容:在旧命名空间中提供别名
namespace LinkerHandL10 {
using FRAME_PROPERTY = linkerhand::hand::L10FrameProperty;
using LinkerHand = linkerhand::hand::L10Hand;
} // namespace LinkerHandL10
#endif // LINKERHAND_L10_H
\ No newline at end of file
#ifndef LINKERHAND_L20_H
#define LINKERHAND_L20_H
#include <thread>
#include <mutex>
#include <queue>
#include <iostream>
#include <sstream>
#include <condition_variable>
#include "IHand.h"
#include "CanBusFactory.h"
namespace linkerhand {
namespace hand {
// L20 型号的帧属性枚举
enum class L20FrameProperty
{
INVALID_FRAME_PROPERTY = 0x00, // 无效的can帧属性 | 无返回
JOINT_PITCH_R = 0x01, // 短帧俯仰角-手指根部弯曲程度 | 返回本类型数据
JOINT_YAW_R = 0x02, // 短帧航向角-手指横摆,控制间隙 | 返回本类型数据
JOINT_ROLL_R = 0x03, // 短帧横滚角-只有大拇指副用到了 | 返回本类型数据
JOINT_TIP_R = 0x04, // 短帧指尖角度弯曲程度 | 返回本类型数据
JOINT_SPEED_R = 0x05, // 短帧速度 电机运行速度控制 | 返回本类型数据
JOINT_CURRENT_R = 0x06, // 短帧电流 电机运行电流 | 返回本类型数据
JOINT_FAULT_R = 0x07, // 短帧故障 电机运行故障 1清除 0查询 | 返回本类型数据
ROTOR_LOCK_COUNT = 0x08, // 手指堵转或过流判断计数阀值 | 返回本类型数据
REQUEST_DATA_RETURN = 0x09, // 请求数据返回 | 返回所有手指控制数据,返回数据会分若干帧发出。
JOINT_PITCH_NR = 0x11, // 俯仰角-手指根部弯曲 | 不返回本类型数据
JOINT_YAW_NR = 0x12, // 航向角-手指横摆,控制间隙 | 不返回本类型数据
JOINT_ROLL_NR = 0x13, // 横滚角-只有大拇指副用到了 | 不返回本类型数据
JOINT_TIP_NR = 0x14, // 指尖角度控制 | 不返回本类型数据
JOINT_SPEED_NR = 0x15, // 速度 电机运行速度控制 | 不返回本类型数据
JOINT_CURRENT_NR = 0x16, // 电流 电机运行电流反馈 | 不返回本类型数据
JOINT_FAULT_NR = 0x17, // 故障 电机运行故障反馈 | 不返回本类型数据
HAND_NORMAL_FORCE = 0X20, // 返回五个手指的法向压力
HAND_TANGENTIAL_FORCE = 0X21, // 返回五个手指的切向压力
HAND_TANGENTIAL_FORCE_DIR = 0X22, // 返回五个手指的切向方向 数值0-127对应实际切向力角度0-359,无切向力保持255
HAND_APPROACH_INC = 0X23, // 返回五个手指指接近感应
THUMB_ALL_DATA = 0x30, // 大拇指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
INDEX_FINGER_ALL_DATA = 0x31, // 食指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
MIDDLE_FINGER_ALL_DATA = 0x32, // 中指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
RING_FINGER_ALL_DATA = 0x33, // 无名指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
LITTLE_FINGER_ALL_DATA = 0x34, // 小拇指所有数据 | 返回 1法向压力 2切向压力 3切向方向 4接近感应
HAND_UID = 0xC0, // 设备唯一标识码 只读 --------
HAND_HARDWARE_VERSION = 0xC1, // 硬件版本 只读 --------
HAND_SOFTWARE_VERSION = 0xC2, // 软件版本 只读 --------
HAND_COMM_ID = 0xC3, // 设备ID 可读写 1字节
HAND_SAVE_PARAMETER = 0xCF, // 保存参数 只写 --------
// 新压感
TOUCH_SENSOR_TYPE = 0xB0, // 触觉传感器类型
THUMB_TOUCH = 0xB1, // 大拇指触觉传感
INDEX_TOUCH = 0xB2, // 食指触觉传感
MIDDLE_TOUCH = 0xB3, // 中指触觉传感
RING_TOUCH = 0xB4, // 无名指触觉传感
LITTLE_TOUCH = 0xB5, // 小拇指触觉传感
PALM_TOUCH = 0xB6 // 手掌指触觉传感
};
/**
* @brief L20 型号灵巧手实现类
*
* 提供 L20 型号的所有功能实现
*/
class L20Hand : public IHand {
public:
L20Hand(uint32_t handId, const std::string& canChannel, int baudrate);
~L20Hand();
// 设置关节位置
void setJointPositions(const std::vector<uint8_t> &jointAngles) override;
void setJointPositionArc(const std::vector<double> &jointAngles) override;
// 设置关节速度
void setSpeed(const std::vector<uint8_t> &speed) override;
// 获取当前速度
std::vector<uint8_t> getSpeed() override;
// 获取当前关节状态
std::vector<uint8_t> getCurrentStatus() override;
std::vector<double> getCurrentStatusArc() override;
//--------------------------------------------------------------------
// 获取所有压感数据
std::vector<std::vector<std::vector<uint8_t>>> getForce() override;
// 获取五个手指的法向压力
std::vector<uint8_t> getNormalForce() override;
// 获取五个手指的切向压力
std::vector<uint8_t> getTangentialForce() override;
// 获取五个手指的切向方向
std::vector<uint8_t> getTangentialForceDir() override;
// 获取五个手指指接近感应
std::vector<uint8_t> getApproachInc() override;
#if 0
// 获取大拇指压感数据
std::vector<uint8_t> getThumbForce() override;
// 获取食指压感数据
std::vector<uint8_t> getIndexForce() override;
// 获取中指压感数据
std::vector<uint8_t> getMiddleForce() override;
// 获取无名指压感数据
std::vector<uint8_t> getRingForce() override;
// 获取小拇指压感数据
std::vector<uint8_t> getLittleForce() override;
#endif
//--------------------------------------------------------------------
// 获取电机故障码
std::vector<uint8_t> getFaultCode() override;
// 获取电机电流
std::vector<uint8_t> getCurrent() override;
// 清除电机故障码
void clearFaultCode(const std::vector<uint8_t> &code = std::vector<uint8_t>(5, 1)) override;
// 设置电流
void setCurrent(const std::vector<uint8_t> &current) override;
// 获取版本号
std::string getVersion() override;
// 获取设备唯一标志
std::vector<uint8_t> getUID() override;
// 获取堵转计数
std::vector<uint8_t> getRotorLockCount() override;
private:
uint32_t handId;
std::unique_ptr<Communication::ICanBus> bus;
std::thread receiveThread;
bool running;
std::mutex responseMutex;
void receiveResponse();
// 故障码
std::vector<uint8_t> motor_fault_code;
// 电流
std::vector<uint8_t> motor_current;
// 速度
std::vector<uint8_t> motor_speed;
// 压感数据
std::vector<std::vector<uint8_t>> force_data;
std::vector<uint8_t> normal_force;
std::vector<uint8_t> tangential_force;
std::vector<uint8_t> tangential_force_dir;
std::vector<uint8_t> approach_inc;
std::vector<uint8_t> thumb_pressure;
std::vector<uint8_t> index_finger_pressure;
std::vector<uint8_t> middle_finger_pressure;
std::vector<uint8_t> ring_finger_pressure;
std::vector<uint8_t> little_finger_pressure;
std::vector<std::vector<std::vector<uint8_t>>> touch_mats;
// 关节位置
std::vector<uint8_t> joint_position1;
std::vector<uint8_t> joint_position2;
std::vector<uint8_t> joint_position3;
std::vector<uint8_t> joint_position4;
// 版本号
std::vector<uint8_t> hand_hardware_version;
std::vector<uint8_t> hand_software_version;
// 设备ID
std::vector<uint8_t> hand_comm_id;
// 设备唯一标志
std::vector<uint8_t> hand_uid;
// 堵转计数
std::vector<uint8_t> rotor_lock_count;
uint8_t sensor_type = 0;
};
} // namespace hand
} // namespace linkerhand
// 向后兼容:在旧命名空间中提供别名
namespace LinkerHandL20 {
using FRAME_PROPERTY = linkerhand::hand::L20FrameProperty;
using LinkerHand = linkerhand::hand::L20Hand;
} // namespace LinkerHandL20
#endif // LINKERHAND_L20_H
\ No newline at end of file
#ifndef LINKERHAND_L25_H
#define LINKERHAND_L25_H
#include <thread>
#include <mutex>
#include <queue>
#include <iostream>
#include <sstream>
#include <condition_variable>
#include <map>
#include <numeric>
#include "IHand.h"
#include "CanBusFactory.h"
namespace linkerhand {
namespace hand {
// L25/L21 型号的帧属性枚举
enum class L25FrameProperty
{
INVALID_FRAME_PROPERTY = 0x00, // 无效的can帧属性 | 无返回
// 并行指令区域
ROLL_POS = 0x01, // 横滚关节位置 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度 [10,11,12,13,14]
YAW_POS = 0x02, // 航向关节位置 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度 [5,6,7,8,9]
ROOT1_POS = 0x03, // 指根1关节位置 | 最接近手掌的指根关节 [0,1,2,3,4]
ROOT2_POS = 0x04, // 指根2关节位置 | 最接近手掌的指根关节 [15, 16,17,18,19]
ROOT3_POS = 0x05, // 指根3关节位置 | 最接近手掌的指根关节 暂无
TIP_POS = 0x06, // 指尖关节位置 | 最接近手掌的指根关节 [20,21,22,23,24]
ROLL_SPEED = 0x09, // 横滚关节速度 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
YAW_SPEED = 0x0A, // 航向关节速度 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
ROOT1_SPEED = 0x0B, // 指根1关节速度 | 最接近手掌的指根关节
ROOT2_SPEED = 0x0C, // 指根2关节速度 | 最接近手掌的指根关节
ROOT3_SPEED = 0x0D, // 指根3关节速度 | 最接近手掌的指根关节
TIP_SPEED = 0x0E, // 指尖关节速度 | 最接近手掌的指根关节
ROLL_TORQUE = 0x11, // 横滚关节扭矩 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
YAW_TORQUE = 0x12, // 航向关节扭矩 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
ROOT1_TORQUE = 0x13, // 指根1关节扭矩 | 最接近手掌的指根关节
ROOT2_TORQUE = 0x14, // 指根2关节扭矩 | 最接近手掌的指根关节
ROOT3_TORQUE = 0x15, // 指根3关节扭矩 | 最接近手掌的指根关节
TIP_TORQUE = 0x16, // 指尖关节扭矩 | 最接近手掌的指根关节
ROLL_FAULT = 0x19, // 横滚关节故障码 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
YAW_FAULT = 0x1A, // 航向关节故障码 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
ROOT1_FAULT = 0x1B, // 指根1关节故障码 | 最接近手掌的指根关节
ROOT2_FAULT = 0x1C, // 指根2关节故障码 | 最接近手掌的指根关节
ROOT3_FAULT = 0x1D, // 指根3关节故障码 | 最接近手掌的指根关节
TIP_FAULT = 0x1E, // 指尖关节故障码 | 最接近手掌的指根关节
ROLL_TEMPERATURE = 0x21, // 横滚关节温度 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
YAW_TEMPERATURE = 0x22, // 航向关节温度 | 坐标系建在每个手指的指根部位,按手指伸直的状态去定义旋转角度
ROOT1_TEMPERATURE = 0x23, // 指根1关节温度 | 最接近手掌的指根关节
ROOT2_TEMPERATURE = 0x24, // 指根2关节温度 | 最接近手掌的指根关节
ROOT3_TEMPERATURE = 0x25, // 指根3关节温度 | 最接近手掌的指根关节
TIP_TEMPERATURE = 0x26, // 指尖关节温度 | 最接近手掌的指根关节
// 并行指令区域
// 串行指令区域
THUMB_POS = 0x41, // 大拇指指关节位置 | 返回本类型数据
INDEX_POS = 0x42, // 食指关节位置 | 返回本类型数据
MIDDLE_POS = 0x43, // 中指关节位置 | 返回本类型数据
RING_POS = 0x44, // 无名指关节位置 | 返回本类型数据
LITTLE_POS = 0x45, // 小拇指关节位置 | 返回本类型数据
THUMB_SPEED = 0x49, // 大拇指速度 | 返回本类型数据
INDEX_SPEED = 0x4A, // 食指速度 | 返回本类型数据
MIDDLE_SPEED = 0x4B, // 中指速度 | 返回本类型数据
RING_SPEED = 0x4C, // 无名指速度 | 返回本类型数据
LITTLE_SPEED = 0x4D, // 小拇指速度 | 返回本类型数据
THUMB_TORQUE = 0x51, // 大拇指扭矩 | 返回本类型数据
INDEX_TORQUE = 0x52, // 食指扭矩 | 返回本类型数据
MIDDLE_TORQUE = 0x53, // 中指扭矩 | 返回本类型数据
RING_TORQUE = 0x54, // 无名指扭矩 | 返回本类型数据
LITTLE_TORQUE = 0x55, // 小拇指扭矩 | 返回本类型数据
THUMB_FAULT = 0x59, // 大拇指故障码 | 返回本类型数据
INDEX_FAULT = 0x5A, // 食指故障码 | 返回本类型数据
MIDDLE_FAULT = 0x5B, // 中指故障码 | 返回本类型数据
RING_FAULT = 0x5C, // 无名指故障码 | 返回本类型数据
LITTLE_FAULT = 0x5D, // 小拇指故障码 | 返回本类型数据
THUMB_TEMPERATURE = 0x61, // 大拇指温度 | 返回本类型数据
INDEX_TEMPERATURE = 0x62, // 食指温度 | 返回本类型数据
MIDDLE_TEMPERATURE = 0x63, // 中指温度 | 返回本类型数据
RING_TEMPERATURE = 0x64, // 无名指温度 | 返回本类型数据
LITTLE_TEMPERATURE = 0x65, // 小拇指温度 | 返回本类型数据
// 串行指令区域
// 合并指令区域,同一手指非必要单控数据合并
FINGER_SPEED = 0x81, // 手指速度 | 返回本类型数据
FINGER_TORQUE = 0x82, // 转矩 | 返回本类型数据
FINGER_FAULT = 0x83, // 手指故障码 | 返回本类型数据
MOTOR_ENABLE = 0x85, // 使能 | 返回本类型数据
// 指尖传感器数据组
HAND_NORMAL_FORCE = 0x90, // 五指法向压力
HAND_TANGENTIAL_FORCE = 0x91, // 五指切向压力
HAND_TANGENTIAL_FORCE_DIR = 0x92, // 五指切向方向
HAND_APPROACH_INC = 0x93, // 五指接近感应
THUMB_ALL_DATA = 0x98, // 大拇指所有数据
INDEX_ALL_DATA = 0x99, // 食指所有数据
MIDDLE_ALL_DATA = 0x9A, // 中指所有数据
RING_ALL_DATA = 0x9B, // 无名指所有数据
LITTLE_ALL_DATA = 0x9C, // 小拇指所有数据
// 动作指令 ·ACTION
ACTION_PLAY = 0xA0, // 动作,预设动作指令
// L21新增
TOUCH_SENSOR_TYPE = 0xB0, // 触觉传感器类型
THUMB_TOUCH = 0xB1, // 大拇指触觉传感
INDEX_TOUCH = 0xB2, // 食指触觉传感
MIDDLE_TOUCH = 0xB3, // 中指触觉传感
RING_TOUCH = 0xB4, // 无名指触觉传感
LITTLE_TOUCH = 0xB5, // 小拇指触觉传感
PALM_TOUCH = 0xB6, // 手掌指触觉传感
// 配置命令·CONFIG
HAND_UID = 0xC0, // 设备唯一标识码
HAND_HARDWARE_VERSION = 0xC1, // 硬件版本
HAND_SOFTWARE_VERSION = 0xC2, // 软件版本
HAND_COMM_ID = 0xC3, // 设备id
HAND_FACTORY_RESET = 0xCE, // 恢复出厂设置
HAND_SAVE_PARAMETER = 0xCF, // 保存参数
WHOLE_FRAME = 0xF0, // 整帧传输 | 返回一字节帧属性+整个结构体485及网络传输专属
};
/**
* @brief L25/L21 型号灵巧手实现类
*
* 提供 L25 和 L21 型号的所有功能实现
*/
class L25Hand : public IHand {
public:
L25Hand(uint32_t handId, const std::string& canChannel, int baudrate, const int currentHandType = 0);
~L25Hand();
// 设置关节位置
void setJointPositions(const std::vector<uint8_t> &jointAngles) override;
void setJointPositionArc(const std::vector<double> &jointAngles) override;
#if 0
// 横滚关节位置
void setRoll(const std::vector<uint8_t> &roll) override;
// 航向关节位置
void setYaw(const std::vector<uint8_t> &yaw) override;
// 指根1关节位置
void setRoot1(const std::vector<uint8_t> &root1) override;
// 指根2关节位置
void setRoot2(const std::vector<uint8_t> &root2) override;
// 指根3关节位置
void setRoot3(const std::vector<uint8_t> &root3) override;
// 指尖关节位置
void setTip(const std::vector<uint8_t> &tip) override;
#endif
std::vector<uint8_t> state_to_cmd(const std::vector<uint8_t>& l25_state);
// 获取当前关节状态
std::vector<uint8_t> getCurrentStatus() override;
std::vector<double> getCurrentStatusArc() override;
#if 0
// 大拇指指关节位置
std::vector<uint8_t> getThumb() override;
// 食指关节位置
std::vector<uint8_t> getIndex() override;
// 中指关节位置
std::vector<uint8_t> getMiddle() override;
// 无名指关节位置
std::vector<uint8_t> getRing() override;
// 小拇指关节位置
std::vector<uint8_t> getLittle() override;
#endif
// 设置关节速度-有合并指令待确认
void setSpeed(const std::vector<uint8_t> &speed) override;
#if 0
// 横滚关节速度
void setRollSpeed(const std::vector<uint8_t> &rollSpeed) override;
// 航向关节速度
void setYawSpeed(const std::vector<uint8_t> &yawSpeed) override;
// 指根1关节速度
void setRoot1Speed(const std::vector<uint8_t> &root1Speed) override;
// 指根2关节速度
void setRoot2Speed(const std::vector<uint8_t> &root2Speed) override;
// 指根3关节速度
void setRoot3Speed(const std::vector<uint8_t> &root3Speed) override;
// 指尖关节速度
void setTipSpeed(const std::vector<uint8_t> &tipSpeed) override;
#endif
// 获取当前速度-有合并指令待确认
std::vector<uint8_t> getSpeed() override;
#if 0
// 大拇指速度
std::vector<uint8_t> getThumbSpeed() override;
// 食指速度
std::vector<uint8_t> getIndexSpeed() override;
// 中指速度
std::vector<uint8_t> getMiddleSpeed() override;
// 无名指速度
std::vector<uint8_t> getRingSpeed() override;
// 小拇指速度
std::vector<uint8_t> getLittleSpeed() override;
#endif
// 设置扭矩-有合并指令待确认
void setTorque(const std::vector<uint8_t> &torque) override;
#if 0
// 横滚关节扭矩
void setRollTorque(const std::vector<uint8_t> &rollTorque) override;
// 航向关节扭矩
void setYawTorque(const std::vector<uint8_t> &yawTorque) override;
// 指根1关节扭矩
void setRoot1Torque(const std::vector<uint8_t> &root1Torque) override;
// 指根2关节扭矩
void setRoot2Torque(const std::vector<uint8_t> &root2Torque) override;
// 指根3关节扭矩
void setRoot3Torque(const std::vector<uint8_t> &root3Torque) override;
// 指尖关节扭矩
void setTipTorque(const std::vector<uint8_t> &tipTorque) override;
#endif
// 获取当前扭矩-有合并指令待确认
std::vector<uint8_t> getTorque() override;
#if 0
// 大拇指扭矩
std::vector<uint8_t> getThumbTorque() override;
// 食指扭矩
std::vector<uint8_t> getIndexTorque() override;
// 中指扭矩
std::vector<uint8_t> getMiddleTorque() override;
// 无名指扭矩
std::vector<uint8_t> getRingTorque() override;
// 小拇指扭矩
std::vector<uint8_t> getLittleTorque() override;
#endif
// 获取故障码-有合并指令待确认
std::vector<uint8_t> getFaultCode() override;
#if 0
// 清除电机故障码
void clearFaultCode(const std::vector<uint8_t> &torque = std::vector<uint8_t>(5, 0)) override;
// 大拇指故障码
std::vector<uint8_t> getThumbFaultCode() override;
// 食指故障码
std::vector<uint8_t> getIndexFaultCode() override;
// 中指故障码
std::vector<uint8_t> getMiddleFaultCode() override;
// 无名指故障码
std::vector<uint8_t> getRingFaultCode() override;
// 小拇指故障码
std::vector<uint8_t> getLittleFaultCode() override;
// ------------------------------------------------以下函数待确认
// 横滚关节故障码
std::vector<uint8_t> getRollFaultCode() override;
// 航向关节故障码
std::vector<uint8_t> getYawFaultCode() override;
// 指根1关节故障码
std::vector<uint8_t> getRoot1FaultCode() override;
// 指根2关节故障码
std::vector<uint8_t> getRoot2FaultCode() override;
// 指根3关节故障码
std::vector<uint8_t> getRoot3FaultCode() override;
// 指尖关节故障码
std::vector<uint8_t> getTipFaultCode() override;
#endif
//--------------------------------------------------------------------
// 获取温度
std::vector<uint8_t> getTemperature() override;
#if 0
// 大拇指温度
std::vector<uint8_t> getThumbTemperature() override;
// 食指温度
std::vector<uint8_t> getIndexTemperature() override;
// 中指温度
std::vector<uint8_t> getMiddleTemperature() override;
// 无名指温度
std::vector<uint8_t> getRingTemperature() override;
// 小拇指温度
std::vector<uint8_t> getLittleTemperature() override;
//----------------------------------------------------以下函数待确认
// 获取横滚关节温度
std::vector<uint8_t> getRollTemperature() override;
// 获取航向关节温度
std::vector<uint8_t> getYawTemperature() override;
// 获取指根1关节温度
std::vector<uint8_t> getRoot1Temperature() override;
// 获取指根2关节温度
std::vector<uint8_t> getRoot2Temperature() override;
// 获取指根3关节温度
std::vector<uint8_t> getRoot3Temperature() override;
// 获取指尖关节温度
std::vector<uint8_t> getTipTemperature() override;
#endif
//--------------------------------------------------------------------
// 获取所有压感数据
std::vector<std::vector<uint8_t>> getForce(const int type = 0) override;
std::vector<std::vector<std::vector<uint8_t>>> getForce() override;
#if 1
// 获取大拇指压感数据
std::vector<uint8_t> getThumbForce() override;
// 获取食指压感数据
std::vector<uint8_t> getIndexForce() override;
// 获取中指压感数据
std::vector<uint8_t> getMiddleForce() override;
// 获取无名指压感数据
std::vector<uint8_t> getRingForce() override;
// 获取小拇指压感数据
std::vector<uint8_t> getLittleForce() override;
//-----------------------------------------------
// 获取五个手指的法向压力
std::vector<uint8_t> getNormalForce() override;
// 获取五个手指的切向压力
std::vector<uint8_t> getTangentialForce() override;
// 获取五个手指的切向方向
std::vector<uint8_t> getTangentialForceDir() override;
// 获取五个手指指接近感应
std::vector<uint8_t> getApproachInc() override;
#endif
//--------------------------------------------------------------------
// 获取版本号
std::string getVersion() override;
// 设置电机使能 目前仅支持L25
void setMotorEnable(const std::vector<uint8_t> &enable = std::vector<uint8_t>(5, 0));
// 设置电机使能 目前仅支持L25
void setMotorDisable(const std::vector<uint8_t> &disable = std::vector<uint8_t>(5, 1));
// 设备唯一标识码
std::vector<uint8_t> getUID();
// 设备id
std::vector<uint8_t> getCommID();
// 恢复出厂设置
void factoryReset();
// 保存参数
void saveParameter();
#if 0
// 动作,预设动作指令
void playAction(const std::vector<uint8_t> &action) override;
//--------------------------------------------------------------------
// 整帧传输
void setWholeFrame(bool wholeFrame) override;
#endif
private:
uint32_t handId;
std::unique_ptr<Communication::ICanBus> bus;
std::thread receiveThread;
bool running;
std::mutex responseMutex;
void receiveResponse();
// 故障码
std::vector<uint8_t> motor_fault_code;
// 电流
std::vector<uint8_t> motor_current;
// 速度
// std::vector<uint8_t> motor_speed;
std::vector<uint8_t> thumb_speed; // 大拇指速度
std::vector<uint8_t> index_speed; // 食指速度
std::vector<uint8_t> middle_speed; // 中指速度
std::vector<uint8_t> ring_speed; // 无名指速度
std::vector<uint8_t> little_speed; // 小拇指速度
// 关节位置
// std::vector<uint8_t> joint_pos;
std::vector<uint8_t> thumb_pos; // 大拇指位置
std::vector<uint8_t> index_pos; // 食指位置
std::vector<uint8_t> middle_pos; // 中指位置
std::vector<uint8_t> ring_pos; // 无名指位置
std::vector<uint8_t> little_pos; // 小拇指位置
// 温度
// std::vector<uint8_t> motor_temperature;
std::vector<uint8_t> thumb_temperature; // 大拇指温度
std::vector<uint8_t> index_temperature; // 食指温度
std::vector<uint8_t> middle_temperature; // 中指温度
std::vector<uint8_t> ring_temperature; // 无名指温度
std::vector<uint8_t> little_temperature; // 小拇指温度
// 扭矩
std::vector<uint8_t> thumb_torque; // 大拇指扭矩
std::vector<uint8_t> index_torque; // 食指扭矩
std::vector<uint8_t> middle_torque; // 中指扭矩
std::vector<uint8_t> ring_torque; // 无名指扭矩
std::vector<uint8_t> little_torque; // 小拇指扭矩
// 故障
std::vector<uint8_t> thumb_fault; // 大拇指故障
std::vector<uint8_t> index_fault; // 食指故障
std::vector<uint8_t> middle_fault; // 中指故障
std::vector<uint8_t> ring_fault; // 无名指故障
std::vector<uint8_t> little_fault; // 小拇指故障
std::vector<uint8_t> normal_force;
std::vector<uint8_t> tangential_force;
std::vector<uint8_t> tangential_force_dir;
std::vector<uint8_t> approach_inc;
std::vector<uint8_t> thumb_pressure;
std::vector<uint8_t> index_finger_pressure;
std::vector<uint8_t> middle_finger_pressure;
std::vector<uint8_t> ring_finger_pressure;
std::vector<uint8_t> little_finger_pressure;
std::vector<uint8_t> palm_force_data;
// std::vector<uint8_t> joint_position2;
// std::vector<uint8_t> joint_position3;
// std::vector<uint8_t> joint_position4;
// std::vector<uint8_t> joint_position5;
// 版本号
std::vector<uint8_t> hand_hardware_version;
std::vector<uint8_t> hand_software_version;
// 设备唯一标志
std::vector<uint8_t> hand_uid;
std::vector<uint8_t> hand_comm_id;
// 堵转计数
std::vector<uint8_t> rotor_lock_count;
// 手型
int current_hand_type = 0; // 0:L25 1:L21
uint8_t sensor_type = 0;
std::vector<std::vector<std::vector<uint8_t>>> touch_mats;
};
} // namespace hand
} // namespace linkerhand
// 向后兼容:在旧命名空间中提供别名
namespace LinkerHandL25 {
using FRAME_PROPERTY = linkerhand::hand::L25FrameProperty;
using LinkerHand = linkerhand::hand::L25Hand;
} // namespace LinkerHandL25
#endif // LINKERHAND_L25_H
\ No newline at end of file
#ifndef LINKERHAND_L6_H
#define LINKERHAND_L6_H
#include <thread>
#include <mutex>
#include <queue>
#include <chrono>
#include <iostream>
#include <sstream>
#include <condition_variable>
#include "IHand.h"
#include "CanBusFactory.h"
namespace linkerhand {
namespace hand {
// L6/O6 型号的帧属性枚举
enum class L6FrameProperty
{
// 指令码 指令功能 数据长度 CAN发送DLC CAN接收DLC 数据范围
JOINT_POSITION = 0x01, // 关节1-6的关节位置 6 7 7 0-0xFF
TORQUE_LIMIT = 0x02, // 关节1-6的转矩限制 6 7 7 0-0xFF
JOINT_SPEED = 0x05, // 关节1-6的速度 6 7 7 0-0xFF
JOINT_ACCELERATION = 0x07, // 关节1-6的加速度 6 7 7 0-0xFE
MOTOR_TEMPERATURE = 0x33, // 关节1-6的温度信息 7 1 8 0-0xFF
MOTOR_ERROR_CODE = 0x35, // 关节1-6的错误码 7 1 8 0-0xFF
CLEAR_FAULT_CODE = 0x83, // 清除关节1-6的错误码 6 7 7 0-0xFF
RE_HOME_COMMAND = 0x38, // 重新调零点命令 8 8 2
// 设备信息指令
DEVICE_SERIAL_NUMBER = 0xC0, // 设备出厂编码 24 1 3帧8字节
DEVICE_HARDWARE_VERSION = 0xC1, // 设备硬件PCB版本号 3 1 4
DEVICE_SOFTWARE_VERSION = 0xC2, // 设备软件版本号 3 1 4
DEVICE_MECHANICAL_VERSION = 0xC4, // 设备机械结构版本号 3 1 4
MODIFY_CAN_ID = 0xC3, // 修改CANID指令 3
STALL_THRESHOLD = 0xC5, // 堵转阈值
STALL_TIME = 0xC6, // 堵转时间
STALL_TORQUE = 0xC7, // 堵转扭矩
FACTORY_RESET = 0xCE, // 恢复出厂设置
SAVE_PARAMETERS = 0xCF, // 保存参数
// 触觉传感器指令
TOUCH_SENSOR_TYPE = 0xB0, // 触觉传感器类型
THUMB_TOUCH = 0xB1, // 大拇指触觉传感
INDEX_TOUCH = 0xB2, // 食指触觉传感
MIDDLE_TOUCH = 0xB3, // 中指触觉传感
RING_TOUCH = 0xB4, // 无名指触觉传感
LITTLE_TOUCH = 0xB5, // 小拇指触觉传感
PALM_TOUCH = 0xB6 // 手掌触觉传感
};
// 协议辅助常量
static constexpr uint8_t TOUCH_TYPE_MATRIX = 0x02; // 矩阵型触觉类型值
static constexpr uint8_t TOUCH_PAGE_REQ = 0xC6; // 触觉分页读取的请求子命令
/**
* @brief L6/O6 型号灵巧手实现类
*
* 提供 L6 和 O6 型号的所有功能实现
*/
class L6Hand : public IHand
{
public:
L6Hand(uint32_t handId, const std::string &canChannel, int baudrate);
~L6Hand();
// 设置关节位置
void setJointPositions(const std::vector<uint8_t> &jointAngles) override;
void setJointPositionArc(const std::vector<double> &jointAngles) override;
void setSpeed(const std::vector<uint8_t> &speed) override;
void setTorque(const std::vector<uint8_t> &torque);
void setAcceleration(const std::vector<uint8_t> &acceleration);
// 重新调零
void reHome();
// 获取当前关节状态
std::vector<uint8_t> getCurrentStatus() override;
std::vector<double> getCurrentStatusArc() override;
// 获取当前速度
std::vector<uint8_t> getSpeed() override;
// 获取当前扭矩
std::vector<uint8_t> getTorque() override;
// 获取当前加速度
std::vector<uint8_t> getAcceleration();
// 获取电机错误码
std::vector<uint8_t> getFaultCode() override;
void clearFaultCode(const std::vector<uint8_t> &code);
// 获取压感数据
std::vector<std::vector<std::vector<uint8_t>>> getForce() override;
// 获取电机温度
std::vector<uint8_t> getTemperature() override;
// 获取版本信息
std::string getVersion() override;
// 获取设备序列号
std::string getSerialNumber();
// 获取硬件版本
std::string getHardwareVersion();
// 获取机械版本
std::string getMechanicalVersion();
// 系统功能
void factoryReset();
void saveParameters();
private:
uint32_t handId;
std::unique_ptr<Communication::ICanBus> bus;
std::thread receiveThread;
bool running;
std::mutex data_mutex_;
void receiveResponse();
// 数据存储
std::vector<uint8_t> joint_position;
std::vector<uint8_t> joint_speeds;
std::vector<uint8_t> joint_torques;
std::vector<uint8_t> joint_accelerations;
std::vector<uint8_t> motor_temperature;
std::vector<uint8_t> error_codes;
std::vector<uint8_t> device_serial;
std::vector<uint8_t> hardware_version;
std::vector<uint8_t> software_version;
std::vector<uint8_t> mechanical_version;
std::vector<std::vector<std::vector<uint8_t>>> touch_mats;
uint8_t sensor_type = 0;
// 辅助方法
void requestDeviceInfo();
void parseSerialNumber(const std::vector<uint8_t>& data);
std::string getErrorDescription(uint8_t error_code);
};
} // namespace hand
} // namespace linkerhand
// 向后兼容:在旧命名空间中提供别名
namespace LinkerHandL6 {
using FRAME_PROPERTY = linkerhand::hand::L6FrameProperty;
using LinkerHand = linkerhand::hand::L6Hand;
} // namespace LinkerHandL6
#endif // LINKERHAND_L6_H
#ifndef LINKERHAND_L7_H
#define LINKERHAND_L7_H
#include <thread>
#include <mutex>
#include <queue>
#include <chrono>
#include <iostream>
#include <sstream>
#include <condition_variable>
#include "IHand.h"
#include "CanBusFactory.h"
namespace linkerhand {
namespace hand {
// L7 型号的帧属性枚举
enum class L7FrameProperty
{
// 指令码 指令功能 数据长度 CAN发送DLC CAN接收DLC 数据范围
JOINT_POSITION = 0x01, // 关节1-7的关节位置 7 8 8 0-0xFF
TORQUE_LIMIT = 0x02, // 关节1-7的转矩限制 7 8 8 0-0xFF
JOINT_SPEED = 0x05, // 关节1-7的速度 7 8 8 0-0xFF
HAND_NORMAL_FORCE = 0x20, // 五个手指的法向压力 5 1 6 0-0xFF
HAND_TANGENTIAL_FORCE = 0x21, // 五个手指的切向压力 5 1 6 0-0xFF
HAND_TANGENTIAL_FORCE_DIR = 0x22, // 五个手指的切向方向 5 1 6 0-0x7F 0xFF
HAND_APPROACH_INC = 0x23, // 五个手指指接近感应 5 1 6 0-0xFF
THUMB_ALL_DATA = 0x28, // 大拇指所有压力数据 4 1 5 0-0xFF
INDEX_FINGER_ALL_DATA = 0x29, // 食指所有压力数据 4 1 5 0-0xFF
MIDDLE_FINGER_ALL_DATA = 0x30, // 中指所有压力数据 4 1 5 0-0xFF
RING_FINGER_ALL_DATA = 0x31, // 无名指所有压力数据 4 1 5 0-0xFF
LITTLE_FINGER_ALL_DATA = 0x32, // 小拇指所有压力数据 4 1 5 0-0xFF
MOTOR_TEMPERATURE = 0x33, // 关节1-7的温度信息 7 1 8 0-0xFF
MOTOR_FAULT_CODE = 0x35, // 关节1-7的错误码 7 1 8 0-0xFF
RESET_ZERO_COMMAND = 0x38, // 重新调零点命令 1 1 2
LINKER_HAND_VERSION = 0x64, // 版本号 8 1 8 0-0xFF
// 新压感
TOUCH_SENSOR_TYPE = 0xB0, // 触觉传感器类型
THUMB_TOUCH = 0xB1, // 大拇指触觉传感
INDEX_TOUCH = 0xB2, // 食指触觉传感
MIDDLE_TOUCH = 0xB3, // 中指触觉传感
RING_TOUCH = 0xB4, // 无名指触觉传感
LITTLE_TOUCH = 0xB5, // 小拇指触觉传感
PALM_TOUCH = 0xB6 // 手掌指触觉传感
};
/**
* @brief L7 型号灵巧手实现类
*
* 提供 L7 型号的所有功能实现
*/
class L7Hand : public IHand
{
public:
L7Hand(uint32_t handId, const std::string &canChannel, int baudrate);
~L7Hand();
// 设置关节位置
void setJointPositions(const std::vector<uint8_t> &jointAngles) override;
void setJointPositionArc(const std::vector<double> &jointAngles) override;
// 设置最大扭矩
void setTorque(const std::vector<uint8_t> &torque) override;
// 设置关节速度
void setSpeed(const std::vector<uint8_t> &speed) override;
// 获取当前速度
std::vector<uint8_t> getSpeed() override;
// 获取当前扭矩
std::vector<uint8_t> getTorque() override;
// 获取当前关节状态
std::vector<uint8_t> getCurrentStatus() override;
std::vector<double> getCurrentStatusArc() override;
//--------------------------------------------------------------------
// 获取所有压感数据
std::vector<std::vector<std::vector<uint8_t>>> getForce() override;
#if 1
// 获取五个手指的法向压力
std::vector<uint8_t> getNormalForce() override;
// 获取五个手指的切向压力
std::vector<uint8_t> getTangentialForce() override;
// 获取五个手指的切向方向
std::vector<uint8_t> getTangentialForceDir() override;
// 获取五个手指指接近感应
std::vector<uint8_t> getApproachInc() override;
#endif
//--------------------------------------------------------------------
// 获取电机温度
std::vector<uint8_t> getTemperature() override;
// 获取电机故障码
std::vector<uint8_t> getFaultCode() override;
// 获取版本信息
std::string getVersion() override;
private:
uint32_t handId;
std::unique_ptr<Communication::ICanBus> bus;
std::thread receiveThread;
bool running;
void receiveResponse();
// 队列和条件变量
std::vector<uint8_t> joint_position;
std::vector<uint8_t> joint_position2;
std::vector<uint8_t> joint_speed;
std::vector<uint8_t> normal_force;
std::vector<uint8_t> tangential_force;
std::vector<uint8_t> tangential_force_dir;
std::vector<uint8_t> approach_inc;
std::vector<uint8_t> thumb_pressure;
std::vector<uint8_t> index_finger_pressure;
std::vector<uint8_t> middle_finger_pressure;
std::vector<uint8_t> ring_finger_pressure;
std::vector<uint8_t> little_finger_pressure;
std::vector<std::vector<std::vector<uint8_t>>> touch_mats;
// 最大扭矩
std::vector<uint8_t> max_torque;
// 电机温度
std::vector<uint8_t> motorTemperature_1;
std::vector<uint8_t> motorTemperature_2;
// 电机故障码
std::vector<uint8_t> motorFaultCode_1;
std::vector<uint8_t> motorFaultCode_2;
// 版本信息
std::vector<uint8_t> version;
uint8_t sensor_type = 0;
};
} // namespace hand
} // namespace linkerhand
// 向后兼容:在旧命名空间中提供别名
namespace LinkerHandL7 {
using FRAME_PROPERTY = linkerhand::hand::L7FrameProperty;
using LinkerHand = linkerhand::hand::L7Hand;
} // namespace LinkerHandL7
#endif // LINKERHAND_L7_H
\ No newline at end of file
#ifndef LINKERHAND_LOGGER_H
#define LINKERHAND_LOGGER_H
#include <iostream>
#include <string>
#include <sstream>
#include <mutex>
#include <memory>
namespace linkerhand {
namespace logging {
/**
* @brief 日志级别枚举
*/
enum class LogLevel {
TRACE = 0,
DEBUG,
INFO,
WARN,
ERROR,
CRITICAL,
OFF
};
/**
* @brief 日志接口
*
* 定义日志系统的接口,可以替换为 spdlog 或其他日志库
*/
class ILogger {
public:
virtual ~ILogger() = default;
virtual void log(LogLevel level, const std::string& message) = 0;
virtual void setLevel(LogLevel level) = 0;
virtual LogLevel getLevel() const = 0;
void trace(const std::string& message) { log(LogLevel::TRACE, message); }
void debug(const std::string& message) { log(LogLevel::DEBUG, message); }
void info(const std::string& message) { log(LogLevel::INFO, message); }
void warn(const std::string& message) { log(LogLevel::WARN, message); }
void error(const std::string& message) { log(LogLevel::ERROR, message); }
void critical(const std::string& message) { log(LogLevel::CRITICAL, message); }
};
/**
* @brief 简单控制台日志实现
*
* 使用 std::cout 和 std::cerr 输出日志
* 可以后续替换为 spdlog
*/
class ConsoleLogger : public ILogger {
public:
explicit ConsoleLogger(LogLevel level = LogLevel::INFO)
: currentLevel_(level) {}
void log(LogLevel level, const std::string& message) override {
if (level < currentLevel_ || level == LogLevel::OFF) {
return;
}
std::lock_guard<std::mutex> lock(mutex_);
const char* levelStr = levelToString(level);
std::ostream& stream = (level >= LogLevel::ERROR) ? std::cerr : std::cout;
stream << "[" << levelStr << "] " << message << std::endl;
}
void setLevel(LogLevel level) override {
std::lock_guard<std::mutex> lock(mutex_);
currentLevel_ = level;
}
LogLevel getLevel() const override {
return currentLevel_;
}
private:
static const char* levelToString(LogLevel level) {
switch (level) {
case LogLevel::TRACE: return "TRACE";
case LogLevel::DEBUG: return "DEBUG";
case LogLevel::INFO: return "INFO";
case LogLevel::WARN: return "WARN";
case LogLevel::ERROR: return "ERROR";
case LogLevel::CRITICAL: return "CRITICAL";
default: return "UNKNOWN";
}
}
LogLevel currentLevel_;
mutable std::mutex mutex_;
};
/**
* @brief 空日志实现(禁用日志)
*/
class NullLogger : public ILogger {
public:
void log(LogLevel, const std::string&) override {}
void setLevel(LogLevel) override {}
LogLevel getLevel() const override { return LogLevel::OFF; }
};
/**
* @brief 全局日志管理器
*/
class Logger {
public:
/**
* @brief 获取默认日志实例
*/
static ILogger& get() {
static std::unique_ptr<ILogger> instance =
std::make_unique<ConsoleLogger>(LogLevel::INFO);
return *instance;
}
/**
* @brief 设置日志实例
*/
static void setLogger(std::unique_ptr<ILogger> logger) {
static std::unique_ptr<ILogger> instance = std::move(logger);
get() = *instance;
}
/**
* @brief 便捷方法:记录 TRACE 日志
*/
static void trace(const std::string& message) {
get().trace(message);
}
/**
* @brief 便捷方法:记录 DEBUG 日志
*/
static void debug(const std::string& message) {
get().debug(message);
}
/**
* @brief 便捷方法:记录 INFO 日志
*/
static void info(const std::string& message) {
get().info(message);
}
/**
* @brief 便捷方法:记录 WARN 日志
*/
static void warn(const std::string& message) {
get().warn(message);
}
/**
* @brief 便捷方法:记录 ERROR 日志
*/
static void error(const std::string& message) {
get().error(message);
}
/**
* @brief 便捷方法:记录 CRITICAL 日志
*/
static void critical(const std::string& message) {
get().critical(message);
}
/**
* @brief 设置日志级别
*/
static void setLevel(LogLevel level) {
get().setLevel(level);
}
/**
* @brief 获取日志级别
*/
static LogLevel getLevel() {
return get().getLevel();
}
};
} // namespace logging
} // namespace linkerhand
// 便捷宏定义
#define LINKERHAND_LOG_TRACE(msg) linkerhand::logging::Logger::trace(msg)
#define LINKERHAND_LOG_DEBUG(msg) linkerhand::logging::Logger::debug(msg)
#define LINKERHAND_LOG_INFO(msg) linkerhand::logging::Logger::info(msg)
#define LINKERHAND_LOG_WARN(msg) linkerhand::logging::Logger::warn(msg)
#define LINKERHAND_LOG_ERROR(msg) linkerhand::logging::Logger::error(msg)
#define LINKERHAND_LOG_CRITICAL(msg) linkerhand::logging::Logger::critical(msg)
#endif // LINKERHAND_LOGGER_H
#ifndef LINKERHAND_MOD_BUS_H
#define LINKERHAND_MOD_BUS_H
#if USE_RMAN
#include <cstdint>
#include <vector>
#include <string>
#include <iostream>
#include <mutex>
#include <atomic>
#include <unistd.h>
#include <chrono>
#include <thread>
#include <queue>
#include <unistd.h>
#include <fcntl.h>
#include <iomanip>
#include <sstream>
#include "rm_service.h"
#include "Common.h"
#include "ICommunication.h"
namespace linkerhand {
namespace communication {
/**
* @brief ModBus 通信实现
*/
class ModBus : public ICommunication
{
public:
ModBus(uint32_t handId);
~ModBus();
void send(const std::vector<uint8_t>& data, uint32_t &id, const int &start_address = 0, const int &num = 0) override;
std::vector<uint8_t> recv(uint32_t& id, const int &start_address = 0, const int &num = 0) override;
bool writeHoldingRegister(const int &id, const int &start_address, const int &num, const std::vector<uint8_t> &data);
std::vector<uint8_t> readHoldingRegister(const int &id, const int &start_address, const int &num);
private:
uint32_t handId;
int result = -1;
rm_robot_handle *robot_handle;
RM_Service robotic_arm;
std::mutex send_mutex;
};
} // namespace communication
} // namespace linkerhand
// 向后兼容:在全局命名空间中提供别名
namespace Communication = linkerhand::communication;
#endif
#endif // LINKERHAND_MOD_BUS_H
#ifndef LINKERHAND_MODBUS_L10_H
#define LINKERHAND_MODBUS_L10_H
#if USE_RMAN
#include <thread>
#include <mutex>
#include <queue>
#include <iostream>
#include <sstream>
#include <vector>
#include <condition_variable>
#include "ModBus.h"
#include "IHand.h"
namespace linkerhand {
namespace hand {
/**
* @brief Modbus L10 型号灵巧手实现类
*
* 提供通过 Modbus 协议通信的 L10 型号功能实现
*/
class ModbusL10Hand : public IHand
{
public:
LinkerHand(uint32_t handId);
~LinkerHand();
// 设置关节位置
void setJointPositions(const std::vector<uint8_t> &jointAngles) override;
void setJointPositionArc(const std::vector<double> &jointAngles) override;
// 设置最大扭矩
void setTorque(const std::vector<uint8_t> &torque) override;
// 设置关节速度
void setSpeed(const std::vector<uint8_t> &speed) override;
// 获取当前速度
std::vector<uint8_t> getSpeed() override;
// 获取当前扭矩
std::vector<uint8_t> getTorque() override;
// 获取当前关节状态
std::vector<uint8_t> getCurrentStatus() override;
std::vector<double> getCurrentStatusArc() override;
private:
uint32_t handId;
std::thread receiveThread;
Communication::ModBus bus;
bool running;
void receiveResponse();
std::vector<uint8_t> joints;
std::vector<uint8_t> speed;
std::vector<uint8_t> torque;
};
} // namespace hand
} // namespace linkerhand
// 向后兼容:在旧命名空间中提供别名
namespace ModbusLinkerHandL10 {
using LinkerHand = linkerhand::hand::ModbusL10Hand;
} // namespace ModbusLinkerHandL10
#endif
#endif // LINKERHAND_MODBUS_L10_H
#ifdef _WIN32
#ifndef LINKERHAND_PCAN_BUS_H
#define LINKERHAND_PCAN_BUS_H
#include <iostream>
#include <windows.h>
#include <PCANBasic.h>
#include <vector>
#include <mutex>
#include <atomic>
#include <chrono>
#include <thread>
#include <queue>
#include <sstream>
#include <iomanip>
#include <thread>
#include "ICanBus.h"
namespace linkerhand {
namespace communication {
/**
* @brief Windows PCAN 总线实现
*/
class PCANBus : public ICanBus
{
public:
PCANBus(TPCANHandle channel, TPCANBaudrate bitrate, const LINKER_HAND linkerhand);
~PCANBus();
std::string printMillisecondTime();
void send(const std::vector<uint8_t>& data, uint32_t can_id, const bool wait = false) override;
CANFrame recv(uint32_t &id) override;
void updateSendRate();
void updateReceiveRate();
private:
TPCANHandle channel;
LINKER_HAND linker_hand;
std::mutex mutex_send;
std::mutex mutex_receive;
std::mutex send_mutex;
std::atomic<int> send_count;
std::chrono::steady_clock::time_point last_time;
std::mutex receive_mutex;
std::atomic<int> receive_count;
std::chrono::steady_clock::time_point receive_last_time;
std::queue<TPCANMsg> send_queue;
};
} // namespace communication
} // namespace linkerhand
// 向后兼容:在全局命名空间中提供别名
namespace Communication = linkerhand::communication;
#endif // LINKERHAND_PCAN_BUS_H
#endif
#ifndef LINKERHAND_RANGE_TO_ARC_H
#define LINKERHAND_RANGE_TO_ARC_H
#include <vector>
#include <stdexcept>
#include <cmath>
#include <condition_variable>
//---------------------------------------------------------------------------------------------------
// L7 L OK
const std::vector<double> l7_l_min = {0, 0, 0, 0, 0, 0, -0.52};
const std::vector<double> l7_l_max = {0.44, 1.43, 1.62, 1.62, 1.62, 1.62, 1.01};
const std::vector<int> l7_l_derict = {-1, -1, -1, -1, -1, -1, -1};
// L7 R OK (urdf后续会更改!!!)
const std::vector<double> l7_r_min = {0, -1.43, 0, 0, 0, 0, 0};
const std::vector<double> l7_r_max = {0.75, 0, 1.62, 1.62, 1.62, 1.62, 1.54};
const std::vector<int> l7_r_derict = {-1, 0, -1, -1, -1, -1, -1};
//---------------------------------------------------------------------------------------------------
// L10 L OK
const std::vector<double> l10_l_min = {0, 0, 0, 0, 0, 0, 0, -0.26, -0.26, -0.52};
const std::vector<double> l10_l_max = {1.45, 1.43, 1.62, 1.62, 1.62, 1.62, 0.26, 0, 0, 1.01};
const std::vector<int> l10_l_derict = {-1, -1, -1, -1, -1, -1, 0, -1, -1, -1};
// L10 R OK
const std::vector<double> l10_r_min = {0, 0, 0, 0, 0, 0, -0.26, 0, 0, -0.52};
const std::vector<double> l10_r_max = {0.75, 1.43, 1.62, 1.62, 1.62, 1.62, 0, 0.13, 0.26, 1.01};
const std::vector<int> l10_r_derict = {-1, -1, -1, -1, -1, -1, -1, 0, 0, -1};
//---------------------------------------------------------------------------------------------------
// L20 L OK
const std::vector<double> l20_l_min = {0, 0, 0, 0, 0, -0.297, -0.26, -0.26, -0.26, -0.26, 0.122, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const std::vector<double> l20_l_max = {0.87, 1.4, 1.4, 1.4, 1.4, 0.683, 0.26, 0.26, 0.26, 0.26, 1.78, 0, 0, 0, 0, 1.29, 1.08, 1.08, 1.08, 1.08};
const std::vector<int> l20_l_derict = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1};
// L20 R OK
const std::vector<double> l20_r_min = {0, 0, 0, 0, 0, -0.297, -0.26, -0.26, -0.26, -0.26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const std::vector<double> l20_r_max = {0.87, 1.4, 1.4, 1.4, 1.4, 0.683, 0.26, 0.26, 0.26, 0.26, 1.78, 0, 0, 0, 0, 1.29, 1.08, 1.08, 1.08, 1.08};
const std::vector<int> l20_r_derict = {-1, -1, -1, -1, -1, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1};
//---------------------------------------------------------------------------------------------------
// L21 L OK
const std::vector<double> l21_l_min = {0, 0, 0, 0, 0, 0, 0, -0.18, -0.18, 0, -0.6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const std::vector<double> l21_l_max = {1, 1.57, 1.57, 1.57, 1.57, 1.6, 0.18, 0.18, 0.18, 0.18, 0.6, 0, 0, 0, 0, 1.57, 0, 0, 0, 0, 1.57, 1.57, 1.57, 1.57, 1.57};
const std::vector<int> l21_l_derict = {-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1};
// L21 R OK
const std::vector<double> l21_r_min = {0, 0, 0, 0, 0, 0, -0.18, -0.18, -0.18, -0.18, -0.6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const std::vector<double> l21_r_max = {1, 1.57, 1.57, 1.57, 1.57, 1.6, 0.18, 0.18, 0.18, 0.18, 0.6, 0, 0, 0, 0, 1.57, 0, 0, 0, 0, 1.57, 1.57, 1.57, 1.57, 1.57};
const std::vector<int> l21_r_derict = {-1, -1, -1, -1, -1, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1};
//---------------------------------------------------------------------------------------------------
// L25 L OK
const std::vector<double> l25_l_min = {0, 0, 0, 0, 0, 0, -0.26, -0.26, -0.26, -0.26, -0.26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const std::vector<double> l25_l_max = {0.9, 1.57, 1.57, 1.57, 1.57, 1.3, 0.26, 0.26, 0.26, 0.26, 0.61, 0, 0, 0, 0, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57};
const std::vector<int> l25_l_derict = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
// L25 R OK
const std::vector<double> l25_r_min = {0, 0, 0, 0, 0, 0, -0.26, -0.26, -0.26, -0.26, -0.26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const std::vector<double> l25_r_max = {0.9, 1.57, 1.57, 1.57, 1.57, 1.3, 0.26, 0.26, 0.26, 0.26, 0.61, 0, 0, 0, 0, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57, 1.57};
const std::vector<int> l25_r_derict = {-1, -1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
//---------------------------------------------------------------------------------------------------
double is_within_range(double value, double min_value, double max_value);
double scale_value(double original_value, double a_min, double a_max, double b_min, double b_max);
bool should_skip_joint(int joints_type, int joint_index);
bool initialize_params(int joints_type, const std::string& left_or_right, std::vector<double>& min_limits, std::vector<double>& max_limits, std::vector<int>& derict);
std::vector<double> range_to_arc(const int &joints_type, const std::string &left_or_right, const std::vector<uint8_t> &hand_range);
std::vector<uint8_t> arc_to_range(const int &joints_type, const std::string &left_or_right, const std::vector<double> &hand_arc);
#endif // LINKERHAND_RANGE_TO_ARC_H
This diff was suppressed by a .gitattributes entry.
liblinkerhand_cpp_sdk.so.1.5.8
\ No newline at end of file
This diff was suppressed by a .gitattributes entry.
liblinkerhand_cpp_sdk.so.1.5.8
\ No newline at end of file
#!/bin/bash
# 从 CMakeLists.txt 读取版本号
VERSION=$(grep -E "^\s*VERSION\s+" CMakeLists.txt | head -1 | sed 's/.*VERSION\s\+\([0-9.]*\).*/\1/')
if [ -z "$VERSION" ]; then
# 如果无法读取,使用默认版本
VERSION="1.1.7"
fi
# 确定系统架构
ARCH=$(uname -m)
# 设置安装目录
INSTALL_PREFIX="/usr/local"
function LoadedColor_information()
{
# 文本颜色
BLACK='\033[0;30m'
# 黑色
RED='\033[0;31m'
# 红色
GREEN='\033[0;32m'
# 绿色
YELLOW='\033[0;33m'
# 黄色
BLUE='\033[0;34m'
# 蓝色
PURPLE='\033[0;35m'
# 紫色
CYAN='\033[0;36m'
# 青色
WHITE='\033[0;37m'
# 白色
RED_WHITE='\033[47;31m'
# 红色
GREEN_WHITE='\033[47;32m'
# 绿色
WHITE_BLACK='\033[40;37m'
# 白色+黑色
YELLOW_WHITE='\033[47;33m'
# 黄色+白色
# 背景颜色
BLACK_B='\033[40m'
# 黑色
RED_B='\033[41m'
# 红色
GREEN_B='\033[42m'
# 绿色
yellow_B='\033[43m'
# 黄色
blue_B='\033[44m'
# 蓝色
purple_B='\033[45m'
# 紫色
Cyan_B='\033[46m'
# 青色
White_B='\033[47m'
# 白色
# 文本样式
RESET='\033[0m'
# 重置所有属性
BOLD='\033[1m'
# 粗体
underline='\033[4m'
# 下划线
Blinking='\033[5m'
# 闪烁
Invert='\033[7m'
# 反显
Hidden='\033[8m'
# 隐藏
# echo "========================================================="
# echo -e "${GREEN}Successfully loaded color information !${RESET}"
# echo "========================================================="
}
CLOSE_RESERVE="exce bash" # exce bash
RUN() {
local launch=$1
gnome-terminal -- bash -c "source devel/setup.sh; $launch; $CLOSE_RESERVE"
sleep 3
}
RUN1() {
local launch=$1
local command package launch_file
IFS=' ' read -r command package launch_file <<< "$launch"
gnome-terminal -- bash -c "source devel/setup.sh; $launch; $CLOSE_RESERVE" > /dev/null 2>&1
echo "Node: $package"
while ! rosnode list | grep -q $package; do
echo -e " starting..."
sleep 1
done
echo -e " Startup completed"
}
function build_sdk(){
mkdir build; cd build; cmake ..; make; cd ..
}
function install_sdk(){
# 安装脚本
set -e
echo "检测到系统架构: $ARCH"
echo "正在安装 linkerhand-cpp-sdk 到系统..."
# 安装头文件
echo "安装头文件到 $INSTALL_PREFIX/include/linkerhand-cpp-sdk..."
sudo mkdir -p $INSTALL_PREFIX/include/linkerhand-cpp-sdk
sudo cp -r include/* $INSTALL_PREFIX/include/linkerhand-cpp-sdk/
# 安装库文件
if [ "$ARCH" = "x86_64" ]; then
echo "安装 x86_64 库文件..."
sudo mkdir -p $INSTALL_PREFIX/lib/linkerhand-cpp-sdk/x86_64
sudo cp -r lib/x86_64/* $INSTALL_PREFIX/lib/linkerhand-cpp-sdk/x86_64/
# 创建符号链接到标准库目录
for lib_file in lib/x86_64/*.so*; do
lib_name=$(basename $lib_file)
sudo ln -sf $INSTALL_PREFIX/lib/linkerhand-cpp-sdk/x86_64/$lib_name $INSTALL_PREFIX/lib/
done
elif [ "$ARCH" = "aarch64" ]; then
echo "安装 aarch64 库文件..."
sudo mkdir -p $INSTALL_PREFIX/lib/linkerhand-cpp-sdk/aarch64
sudo cp -r lib/aarch64/* $INSTALL_PREFIX/lib/linkerhand-cpp-sdk/aarch64/
# 创建符号链接到标准库目录
for lib_file in lib/aarch64/*.so*; do
lib_name=$(basename $lib_file)
sudo ln -sf $INSTALL_PREFIX/lib/linkerhand-cpp-sdk/aarch64/$lib_name $INSTALL_PREFIX/lib/
done
else
echo "不支持的架构: $ARCH"
exit 1
fi
# 更新动态链接库缓存
echo "更新动态链接库缓存..."
sudo ldconfig
echo "安装完成!"
echo ""
echo "使用示例:"
echo " 编译: g++ -o test test.cpp -llinkerhand_cpp_sdk -I/usr/local/include/linkerhand-cpp-sdk"
echo " 运行: LD_LIBRARY_PATH=/usr/local/lib ./test"
}
function uninstall_sdk(){
sudo rm -rf $INSTALL_PREFIX/lib/linkerhand-cpp-sdk
sudo rm -rf $INSTALL_PREFIX/include/linkerhand-cpp-sdk
sudo rm -rf $INSTALL_PREFIX/lib/liblinkerhand_cpp_sdk.so*
}
function run_example(){
cd build; ./toolset_example
}
#------------------------------------------------ Select Menu ------------------------------------------
function select_menu(){
cd $current_dir
echo -e "${GREEN}Please enter options: ${RESET}"
read -p "" select_num
case $select_num in
1)
echo "Build SDK"
build_sdk
;;
2)
echo "Install SDK"
build_sdk
install_sdk
;;
3)
echo "Uninstall SDK"
uninstall_sdk
;;
6)
echo "Execution Example"
run_example
;;
0)
echo "Exit"
exit
;;
*)
echo -e "${RED}Input error, please re-enter!${RESET}"
sleep 1
;;
esac
}
#------------------------------------------------ Menu ------------------------------------------
function show_Info(){
echo -e "${YELLOW}"
echo "================================================"
echo -e "${YELLOW} LinkerHand CPP-SDK Version:${VERSION} ${RESET}"
echo -e "${YELLOW}================================================${RESET}"
echo -e "${GREEN}"
echo "RUN Choose Task:"
echo -e "${YELLOW}————————————————————————————————————————————————${RESET}"
echo -e "${BLUE}[1]: Build SDK${RESET}"
echo -e "${YELLOW}————————————————————————————————————————————————${RESET}"
echo -e "${BLUE}[2]: Install SDK${RESET}"
echo -e "${YELLOW}————————————————————————————————————————————————${RESET}"
echo -e "${BLUE}[3]: Uninstall SDK${RESET}"
echo -e "${YELLOW}————————————————————————————————————————————————${RESET}"
echo -e "${RED}[0]: Exit${RESET}"
echo -e "${YELLOW}————————————————————————————————————————————————${RESET}"
# sudo make DESTDIR=/home/lst/Desktop/install install
}
#------------------------------------------------ Init ------------------------------------------
function Init()
{
LoadedColor_information
current_dir=$(pwd)
sleep 1
}
#------------------------------------------------ Main ------------------------------------------
Init
while true
do
show_Info
select_menu
done
---
name: linkerhand-sdk-quickread
description: Use when working in the linkerhand-cpp-sdk repository and you need to quickly understand the project framework, locate the correct API layer, identify model-specific capabilities such as L6/L7/L10/L20/L25, or prepare for fast vibe-coding changes without rereading the whole repo.
---
# LinkerHand SDK Quick Read
Use this skill when the task is to understand, modify, document, or extend this repository efficiently.
## Goal
Build a fast and accurate mental model of the SDK before editing code or writing docs.
## Quick workflow
1. Read the framework entry points first:
- `README.md`
- `CMakeLists.txt`
- `include/Common.h`
- `include/LinkerHandApi.h`
- `include/HandFactory.h`
2. Identify the target model header:
- `include/LinkerHandL6.h`
- `include/LinkerHandL7.h`
- `include/LinkerHandL10.h`
- `include/LinkerHandL20.h`
- `include/LinkerHandL25.h`
- `include/ModbusLinkerHandL10.h`
3. Read `include/IHand.h` to see which methods are truly common and which ones can throw `UnsupportedFeatureException`.
4. Read usage examples:
- `src/main.cpp`
- `examples/toolset_example.cpp`
- `examples/action_group_show_l10.cpp`
5. Read docs only as needed:
- `docs/API-Reference.md`
- `docs/TROUBLESHOOTING.md`
- `docs/FAQ.md`
- `docs/L6-Application-Development-Manual.md`
- `docs/L6-API-Development-Guide.md`
6. If you need a compact structure map, read `references/project-map.md`.
## What to conclude early
Before making claims, answer these points:
- Is the user asking about the public API layer or a model-specific layer?
- Is the capability exposed by `LinkerHandApi`, or only by a concrete hand class?
- Is the behavior visible in headers/docs/examples, or hidden inside the prebuilt `.so`?
- Is the task about SDK usage, repository structure, or extending the SDK itself?
## Repository facts that matter
- The main public entry point is `LinkerHandApi`.
- The factory layer is `HandFactory`.
- Cross-model behavior is defined by `IHand`.
- Model-specific features live in model headers.
- A large part of the implementation is shipped as prebuilt libraries under `lib/x86_64/` and `lib/aarch64/`.
- Tests mostly cover utility and framework pieces, not all device behaviors.
## Working rules
- Prefer `rg --files` and `rg -n` to locate structure and APIs quickly.
- For API claims, trust headers first, examples second, docs third.
- If a behavior is inferred from factory logic or declarations rather than implementation, label it as an inference.
- When documenting or changing L6 behavior, explicitly separate:
- generic API behavior
- `L6Hand`-only behavior
- If a task concerns communication setup, inspect both `HandFactory.h` and the relevant docs before editing.
## Common command pattern
Use fast reads instead of broad scans:
```bash
rg --files
rg -n "LinkerHandApi|HandFactory|IHand|L6Hand|fingerMove|getForce"
sed -n '1,220p' include/LinkerHandApi.h
```
## Output expectation
When summarizing the repo, keep the summary in this order:
1. Public API entry
2. Factory and abstraction layers
3. Model-specific headers
4. Examples and docs
5. Build/test layout
6. Any relevant limitation or ambiguity
# LinkerHand-CPP-SDK 项目框架速查
## 1. 顶层结构
| 路径 | 作用 |
|---|---|
| `include/` | 对外头文件、类型声明、各型号接口 |
| `examples/` | 示例程序,最适合确认典型调用方式 |
| `docs/` | 使用文档、FAQ、故障排查、API 参考 |
| `tests/` | 工具类与框架级测试 |
| `lib/x86_64/` | x86_64 预编译动态库 |
| `lib/aarch64/` | aarch64 预编译动态库 |
| `src/main.cpp` | 最小示例入口 |
| `CMakeLists.txt` | 构建、示例、安装、测试入口 |
## 2. 代码分层
```text
LinkerHandApi
-> HandFactory
-> IHand
-> L6Hand / L7Hand / L10Hand / L20Hand / L25Hand / ModbusL10Hand
```
## 3. 关键文件优先级
### 第一批必读
- `README.md`
- `CMakeLists.txt`
- `include/Common.h`
- `include/LinkerHandApi.h`
- `include/HandFactory.h`
### 第二批按任务读
- 型号问题:读对应 `include/LinkerHandL*.h`
- 能力边界问题:读 `include/IHand.h`
- 使用问题:读 `examples/toolset_example.cpp`
- 构建/排错问题:读 `docs/TROUBLESHOOTING.md`
## 4. L6 相关速记
- 型号头文件:`include/LinkerHandL6.h`
- 6 个关节位置值
- 支持速度、扭矩、加速度、故障、温度、触觉矩阵、版本信息
- `L6Hand` 还声明了 `reHome`、版本读取、参数保存等专有能力
- `LinkerHandApi` 是更高层的统一封装,不会暴露所有型号专有方法
## 5. 仓库约束
- 很多核心实现不在源码中,而在 `lib/*/liblinkerhand_cpp_sdk.so*`
- 因此“接口存在”与“内部实现细节可见”是两件事
- 对行为判断,优先级建议:
1. 头文件声明
2. 示例代码
3. 文档说明
4. 推断
## 6. 常用定位命令
```bash
rg --files
rg -n "LinkerHandApi|HandFactory|IHand|L6Hand"
rg -n "fingerMove|getState|getForce|setAcceleration|reHome"
sed -n '1,220p' include/LinkerHandL6.h
```
## 7. 构建与测试
构建:
```bash
mkdir build
cd build
cmake ..
make
```
测试:
```bash
cmake .. -DBUILD_TESTING=ON
ctest --output-on-failure
```
注意:测试依赖 `googletest`,由 `tests/CMakeLists.txt` 通过 `FetchContent` 拉取。
#include "LinkerHandApi.h"
#include "ErrorCode.h"
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <exception>
#include <iostream>
#include <thread>
#include <vector>
namespace {
constexpr size_t kThumbFingerIndex = 0;
constexpr size_t kIndexFingerIndex = 1;
constexpr size_t kNormalForceSensorIndex = 0;
constexpr uint8_t kReleaseForceThreshold = 80;
constexpr auto kForcePollInterval = std::chrono::milliseconds(100);
constexpr auto kForceWaitTimeout = std::chrono::seconds(8);
uint8_t maxSensorValue(const std::vector<std::vector<std::vector<uint8_t>>> &force_data,
size_t finger_index,
size_t sensor_type_index) {
if (finger_index >= force_data.size()) {
return 0;
}
if (sensor_type_index >= force_data[finger_index].size()) {
return 0;
}
const auto &sensor_values = force_data[finger_index][sensor_type_index];
if (sensor_values.empty()) {
return 0;
}
return *std::max_element(sensor_values.begin(), sensor_values.end());
}
} // namespace
int main() {
// 调用API接口
LinkerHandApi hand(LINKER_HAND::O6, HAND_TYPE::RIGHT, "can0", 1000000);
// 获取版本信息
std::cout << hand.getVersion() << std::endl;
// // 握拳
// std::vector<uint8_t> fist_pose = {255, 255, 0, 0, 0, 0};
// hand.fingerMove(fist_pose);
// std::this_thread::sleep_for(std::chrono::seconds(1));
//
// // 张开
// std::vector<uint8_t> open_pose = {255, 255, 255, 255, 255, 255};
// hand.fingerMove(open_pose);
// std::this_thread::sleep_for(std::chrono::seconds(1));
// O6/L6 关节常用映射(6 维关节向量):
// joint1: 拇指对掌/侧摆
// joint2: 拇指根部弯曲
// joint3: 食指弯曲
// joint4: 中指弯曲
// joint5: 无名指弯曲
// joint6: 小指弯曲
//
// 你说的“五个”一般指五指通道:拇/食/中/无名/小指。
// 在 O6 中,拇指通常有 2 个关节自由度,所以关节总数是 6。
// 仅使用拇指和食指: 让中/无名/小指始终保持收拢(joint4~6 固定较小值)
// 注意: 0~255 的方向可能因机械装配有差异,以下值是可调模板。
std::vector<uint8_t> pre_grasp = {220, 170, 230, 20, 20, 20}; // 接近前,拇食张开
std::vector<uint8_t> pinch = {120, 90, 80, 20, 20, 20}; // 拇食闭合夹住
std::vector<uint8_t> hold = {120, 90, 90, 20, 20, 20}; // 保持抓取
std::vector<uint8_t> release = {220, 170, 230, 20, 20, 20}; // 松开
std::vector<uint8_t> safe_open = {255, 255, 255, 255, 255, 255};
// 可选:速度/力矩(如果你的固件支持该型号)
// 对 O6/L6 推荐使用 6 维;若你的设备固件要求 5 维,请按实际固件改。
std::vector<uint8_t> speed = {90, 90, 90, 90, 90, 90};
std::vector<uint8_t> torque = {255, 255, 255, 255, 255, 255};
hand.setSpeed(speed);
hand.setTorque(torque);
// 1) 预抓取:拇指+食指张开,其他三指保持收拢
hand.fingerMove(pre_grasp);
std::this_thread::sleep_for(std::chrono::seconds(1));
// if (hasFault(hand.getFaultCode())) return 1;
// 2) 闭合夹取“水平盖”形状物体(两指对夹)
hand.fingerMove(pinch);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// if (hasFault(hand.getFaultCode())) return 1;
// 3) 保持并持续检测拇指/食指法向压力,超过阈值立即松手
hand.fingerMove(hold);
bool released_by_force = false;
const auto wait_deadline = std::chrono::steady_clock::now() + kForceWaitTimeout;
while (std::chrono::steady_clock::now() < wait_deadline) {
try {
const auto force_data = hand.getForce();
const uint8_t thumb_force = maxSensorValue(force_data, kThumbFingerIndex, kNormalForceSensorIndex);
const uint8_t index_force = maxSensorValue(force_data, kIndexFingerIndex, kNormalForceSensorIndex);
std::cout << "Thumb normal force: " << static_cast<int>(thumb_force)
<< ", index normal force: " << static_cast<int>(index_force) << std::endl;
if (thumb_force >= kReleaseForceThreshold || index_force >= kReleaseForceThreshold) {
std::cout << "Force threshold reached, releasing object." << std::endl;
hand.fingerMove(release);
released_by_force = true;
break;
}
} catch (const linkerhand::UnsupportedFeatureException &e) {
std::cerr << "Force feedback is not supported on this hand: " << e.what() << std::endl;
break;
} catch (const std::exception &e) {
std::cerr << "Failed to read force data: " << e.what() << std::endl;
break;
}
std::this_thread::sleep_for(kForcePollInterval);
}
if (!released_by_force) {
std::cout << "Force threshold was not reached before timeout, releasing object." << std::endl;
hand.fingerMove(release);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
// 4) 回到安全张开位
hand.fingerMove(safe_open);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Done: thumb-index pick and force-triggered release sequence finished." << std::endl;
return 0;
}
# 测试配置
# 只有在启用测试时才构建测试
if(BUILD_TESTING)
# 查找或下载 Google Test
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
# GIT_REPOSITORY https://github.com/google/googletest.git
# GIT_TAG v1.17.0
)
# 对于 Windows: 防止覆盖父项目的编译器/链接器设置
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
# 启用测试
enable_testing()
# 包含目录
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../include
${LINKER_HAND_INCLUDE_DIR}
)
# 测试可执行文件列表
set(TEST_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/unit/test_Common.cpp
${CMAKE_CURRENT_SOURCE_DIR}/unit/test_RangeToArc.cpp
${CMAKE_CURRENT_SOURCE_DIR}/unit/test_IHand_Utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/unit/test_CanFrame.cpp
)
# 为每个测试文件创建可执行文件
foreach(TEST_SOURCE ${TEST_SOURCES})
# 获取测试名称(从路径中提取)
get_filename_component(TEST_NAME ${TEST_SOURCE} NAME_WE)
# 创建测试可执行文件
add_executable(${TEST_NAME} ${TEST_SOURCE})
# 链接库
target_link_libraries(${TEST_NAME}
PRIVATE
gtest
gtest_main
pthread
)
# 如果测试需要 SDK 库,链接它
# RangeToArc 函数在 SDK 库中实现
if(TEST_SOURCE MATCHES "test_RangeToArc|test_LinkerHandApi|test_Hand")
target_link_libraries(${TEST_NAME}
PRIVATE
${LINKER_HAND_LIB}
)
endif()
# 注册测试
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
# 设置测试属性
set_tests_properties(${TEST_NAME} PROPERTIES
TIMEOUT 60
)
endforeach()
# 创建运行所有测试的便捷目标
add_custom_target(run_tests
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS ${TEST_SOURCES}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running all tests"
)
endif()
# 测试说明
本目录包含 LinkerHand-CPP-SDK 的单元测试。本文档介绍如何构建、运行测试,以及如何添加新测试。
## 目录
- [测试结构](#测试结构)
- [构建测试](#构建测试)
- [运行测试](#运行测试)
- [测试覆盖范围](#测试覆盖范围)
- [测试用例详解](#测试用例详解)
- [添加新测试](#添加新测试)
- [测试最佳实践](#测试最佳实践)
- [故障排查](#故障排查)
- [更多信息](#更多信息)
---
## 测试结构
```
tests/
├── unit/ # 单元测试
│ ├── test_Common.cpp # Common.h 的测试
│ ├── test_RangeToArc.cpp # RangeToArc.h 的测试
│ ├── test_IHand_Utils.cpp # IHand 工具函数的测试
│ └── test_CanFrame.cpp # CanFrame 的测试
├── CMakeLists.txt # 测试构建配置
└── README.md # 本文件
```
---
## 构建测试
### 方法一:使用 CMake 构建(推荐)
```bash
# 在项目根目录
mkdir build && cd build
cmake .. -DBUILD_TESTING=ON
make
```
**说明**:
- `-DBUILD_TESTING=ON` 启用测试构建(默认已启用)
- CMake 会自动下载 Google Test 框架(如果未安装)
- 确保网络连接正常,以便下载依赖
- **注意**: 项目要求 CMake 3.15 或更高版本
### 方法二:禁用测试
如果不想构建测试:
```bash
cmake .. -DBUILD_TESTING=OFF
```
或者不设置 `BUILD_TESTING` 选项(默认为 ON)。
### 方法三:仅构建测试(不构建主项目)
```bash
cd build
cmake .. -DBUILD_TESTING=ON
make test_Common test_RangeToArc test_IHand_Utils test_CanFrame
```
---
## 运行测试
### 运行所有测试
```bash
cd build
ctest
```
**输出示例**:
```
Test project /path/to/build
Start 1: test_Common
1/4 Test #1: test_Common ................... Passed 0.01 sec
Start 2: test_RangeToArc
2/4 Test #2: test_RangeToArc ............... Passed 0.02 sec
Start 3: test_IHand_Utils
3/4 Test #3: test_IHand_Utils .............. Passed 0.01 sec
Start 4: test_CanFrame
4/4 Test #4: test_CanFrame .................. Passed 0.01 sec
100% tests passed, 0 tests failed out of 4
```
### 运行所有测试(显示详细输出)
```bash
cd build
ctest --output-on-failure
```
**说明**: 仅当测试失败时显示详细输出,成功时不显示。
### 运行所有测试(详细模式)
```bash
cd build
ctest -V
# 或
ctest --verbose
```
**说明**: 显示所有测试的详细输出,包括成功的测试。
### 运行特定测试
```bash
cd build
# 运行 test_Common
ctest -R test_Common
# 运行多个测试(使用正则表达式)
ctest -R "test_Common|test_RangeToArc"
```
### 并行运行测试
```bash
cd build
# 使用 4 个并行任务
ctest -j4
# 使用所有可用 CPU 核心
ctest -j$(nproc)
```
**说明**: 并行运行可以加快测试速度,特别是测试较多时。
### 直接运行测试可执行文件
```bash
cd build
./test_Common
./test_RangeToArc
./test_IHand_Utils
./test_CanFrame
```
**说明**: 直接运行可执行文件可以看到更详细的输出,包括 Google Test 的详细日志。
### 使用便捷目标
```bash
cd build
make run_tests
```
**说明**: 如果 CMakeLists.txt 中定义了 `run_tests` 目标,可以使用此命令。
---
## 测试覆盖范围
### test_Common.cpp
**测试内容**: Common.h 中的枚举和类型定义
**测试用例**:
- ✅ `LINKER_HAND` 枚举值测试
- 验证所有型号枚举值(O6, L6, L7, L10, L20, L21, L25)
- ✅ `HAND_TYPE` 枚举值测试
- 验证左手和右手枚举值
- ✅ `COMM_TYPE` 枚举值测试
- 验证所有通信类型枚举值
- ✅ `Common` 命名空间版本号测试
- 验证版本号定义
- ✅ 参数化测试
- 使用 Google Test 参数化测试测试多个值
**示例测试**:
```cpp
TEST(CommonTest, LinkerHandEnum) {
EXPECT_EQ(LINKER_HAND::O6, 0);
EXPECT_EQ(LINKER_HAND::L6, 1);
// ...
}
```
---
### test_RangeToArc.cpp
**测试内容**: RangeToArc.h 中的转换函数
**测试用例**:
- ✅ `is_within_range()` 函数测试
- 测试值是否在有效范围内
- 边界值测试
- ✅ `scale_value()` 函数测试
- 测试值缩放功能
- 边界情况测试
- ✅ `should_skip_joint()` 函数测试
- 测试关节跳过逻辑
- ✅ `initialize_params()` 函数测试
- 测试参数初始化
- ✅ `range_to_arc()` 函数测试
- 测试从 0-255 范围转换为弧度
- 不同型号的转换测试
- ✅ `arc_to_range()` 函数测试
- 测试从弧度转换为 0-255 范围
- ✅ 往返转换测试
- 测试 `range_to_arc()` 和 `arc_to_range()` 的往返一致性
- ✅ 边界值测试
- 测试最小值(0)、最大值(255)、中间值(128)
- ✅ 不同型号测试
- 测试 L10、L20、L21、L25 等不同型号的转换
**示例测试**:
```cpp
TEST(RangeToArcTest, RangeToArcConversion) {
double arc = range_to_arc(128, LINKER_HAND::L10, 0);
EXPECT_NEAR(arc, expected_value, 0.001);
}
```
---
### test_IHand_Utils.cpp
**测试内容**: IHand 工具函数
**测试用例**:
- ✅ `getSubVector()` 单参数版本测试
- 测试从向量中提取子向量
- 边界情况测试(空向量、越界等)
- ✅ `getSubVector()` 双参数版本测试
- 测试指定起始和结束位置的子向量提取
- ✅ `getCurrentTime()` 函数测试
- 测试时间获取功能
- 时间格式验证
- ✅ 边界情况测试
- 空向量、单元素向量、越界访问等
**示例测试**:
```cpp
TEST(IHandUtilsTest, GetSubVector) {
std::vector<uint8_t> vec = {1, 2, 3, 4, 5};
auto sub = getSubVector(vec, 1, 3);
EXPECT_EQ(sub.size(), 2);
EXPECT_EQ(sub[0], 2);
EXPECT_EQ(sub[1], 3);
}
```
---
### test_CanFrame.cpp
**测试内容**: CanFrame.h 中的 CAN 帧结构
**测试用例**:
- ✅ CANFrame 结构体测试
- 结构体大小和布局验证
- ✅ 数据设置和读取测试
- 测试数据的设置和读取功能
- ✅ 边界值测试
- 测试最小值和最大值
- ✅ ID 范围测试
- 测试有效的 CAN ID 范围
- ✅ 数据复制测试
- 测试数据复制和移动语义
**示例测试**:
```cpp
TEST(CanFrameTest, DataSetting) {
CanFrame frame;
frame.setData({0x01, 0x02, 0x03, 0x04});
auto data = frame.getData();
EXPECT_EQ(data.size(), 4);
EXPECT_EQ(data[0], 0x01);
}
```
---
## 测试用例详解
### 测试命名规范
测试用例使用 Google Test 的命名规范:
- 测试套件名:描述被测试的模块(如 `CommonTest`、`RangeToArcTest`)
- 测试用例名:描述具体的测试内容(如 `LinkerHandEnum`、`RangeToArcConversion`)
### 测试类型
1. **单元测试**: 测试单个函数或类的功能
2. **参数化测试**: 使用 `TEST_P` 测试多个输入值
3. **边界测试**: 测试边界值和极端情况
4. **集成测试**: 测试多个组件的交互(当前未包含)
### 测试覆盖率
当前测试覆盖:
- ✅ 核心工具函数(Common、RangeToArc、IHand Utils)
- ✅ 数据结构(CanFrame)
- ⚠️ API 函数(部分覆盖,需要硬件支持)
- ❌ 通信层(需要硬件支持)
- ❌ 端到端测试(需要硬件支持)
---
## 添加新测试
### 步骤 1: 创建测试文件
在 `tests/unit/` 目录下创建新的测试文件,例如 `test_NewFeature.cpp`:
```cpp
#include <gtest/gtest.h>
#include "NewFeature.h"
TEST(NewFeatureTest, BasicFunctionality) {
// 测试代码
EXPECT_EQ(expected, actual);
}
```
### 命名规范说明
在编写测试时,请注意以下命名规范:
1. **使用新的命名空间**(推荐):
```cpp
#include "LinkerHandL10.h"
#include "HandFactory.h"
TEST(HandTest, L10HandCreation) {
using namespace linkerhand;
auto hand = factory::HandFactory::createHand(
LINKER_HAND::L10,
HAND_TYPE::RIGHT,
COMM_CAN_0
);
// 测试代码
}
```
2. **向后兼容的旧命名**(可用但不推荐):
```cpp
#include "LinkerHandL10.h"
TEST(HandTest, L10HandCreation) {
// 旧命名仍然可用,但建议使用新命名
LinkerHandL10::LinkerHand hand(0x27, "can0", 1000000);
// 测试代码
}
```
3. **接口测试**:
```cpp
#include "IHand.h"
TEST(IHandTest, InterfaceTest) {
// 使用正确的命名空间
class TestHand : public linkerhand::hand::IHand {
// 实现接口
};
// 测试代码
}
```
更多关于命名规范的详细信息,请参考 [命名规范改进文档](../docs/NAMING_IMPROVEMENTS.md)。
### 步骤 2: 更新 CMakeLists.txt
在 `tests/CMakeLists.txt` 的 `TEST_SOURCES` 列表中添加新文件:
```cmake
set(TEST_SOURCES
unit/test_Common.cpp
unit/test_RangeToArc.cpp
unit/test_IHand_Utils.cpp
unit/test_CanFrame.cpp
unit/test_NewFeature.cpp # 添加新文件
)
```
### 步骤 3: 配置链接(如需要)
如果测试需要链接 SDK 库或其他库,在 CMakeLists.txt 中添加:
```cmake
target_link_libraries(test_NewFeature
${LINKER_HAND_LIB} # 如果需要链接 SDK 库
pthread
)
```
### 步骤 4: 重新构建和运行
```bash
cd build
cmake ..
make
ctest -R test_NewFeature
```
---
## 测试最佳实践
### 1. 测试独立性
每个测试应该独立,不依赖其他测试:
```cpp
// ✅ 好的做法
TEST(MyTest, Test1) {
// 独立的测试代码
}
// ❌ 不好的做法
TEST(MyTest, Test2) {
// 依赖 Test1 的结果
}
```
### 2. 描述性命名
使用描述性的测试名称:
```cpp
// ✅ 好的做法
TEST(RangeToArcTest, ConvertsZeroToMinimumArc)
// ❌ 不好的做法
TEST(RangeToArcTest, Test1)
```
### 3. 测试多种情况
测试正常情况、边界情况和错误情况:
```cpp
TEST(MyTest, NormalCase) {
// 正常情况
}
TEST(MyTest, BoundaryCase) {
// 边界值(0, 255, 最大值等)
}
TEST(MyTest, ErrorCase) {
// 错误情况(无效输入等)
}
```
### 4. 使用参数化测试
对于需要测试多个输入值的情况,使用参数化测试:
```cpp
class RangeToArcParamTest : public ::testing::TestWithParam<int> {};
TEST_P(RangeToArcParamTest, ConvertsCorrectly) {
int input = GetParam();
// 测试代码
}
INSTANTIATE_TEST_SUITE_P(
RangeValues,
RangeToArcParamTest,
::testing::Values(0, 128, 255)
);
```
### 5. 保持测试简洁
测试代码应该简洁、可读:
```cpp
// ✅ 好的做法
TEST(MyTest, SimpleTest) {
int result = function(5);
EXPECT_EQ(result, 10);
}
// ❌ 不好的做法
TEST(MyTest, ComplexTest) {
// 100 行复杂的测试代码
}
```
### 6. 使用适当的断言
选择合适的断言:
```cpp
EXPECT_EQ(a, b); // 相等
EXPECT_NE(a, b); // 不相等
EXPECT_NEAR(a, b, 0.001); // 浮点数近似相等
EXPECT_TRUE(condition); // 为真
EXPECT_FALSE(condition); // 为假
EXPECT_THROW(statement, ExceptionType); // 抛出异常
```
---
## 故障排查
### 问题 1: 找不到 Google Test
**错误信息**:
```
Could not find gtest
```
**解决方案**:
1. CMake 会自动下载 Google Test,确保网络连接正常
2. 如果网络有问题,可以手动安装 Google Test:
```bash
# Ubuntu/Debian
sudo apt-get install libgtest-dev
```
3. 检查 CMake 版本(需要 3.15+)
---
### 问题 2: 链接错误
**错误信息**:
```
undefined reference to `...`
```
**解决方案**:
1. **检查 SDK 库是否正确找到**:
```bash
ls -la lib/x86_64/liblinkerhand_cpp_sdk.so
```
2. **检查测试是否需要链接 SDK 库**:
- 如果测试需要链接 SDK 库,在 `tests/CMakeLists.txt` 中添加:
```cmake
target_link_libraries(test_name ${LINKER_HAND_LIB} pthread)
```
3. **检查库路径**:
```cmake
find_library(LINKER_HAND_LIB
NAMES linkerhand_cpp_sdk
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../lib/x86_64
)
```
---
### 问题 3: 测试失败
**错误信息**:
```
Test failed: ...
```
**解决方案**:
1. **查看详细输出**:
```bash
ctest --output-on-failure
```
2. **直接运行测试可执行文件**:
```bash
./test_Common
```
这样可以查看更详细的错误信息。
3. **检查测试代码**:
- 验证测试逻辑是否正确
- 检查期望值是否正确
4. **检查 SDK 库版本**:
- 确保使用的 SDK 库版本与测试代码匹配
- 检查是否有 API 变更
5. **检查环境**:
- 确保测试环境正确配置
- 检查依赖项是否完整
---
### 问题 4: 测试运行缓慢
**可能原因**:
- 测试数量多
- 测试包含耗时操作
- 系统负载高
**解决方案**:
1. **并行运行测试**:
```bash
ctest -j4
```
2. **优化测试代码**:
- 减少不必要的操作
- 使用 mock 对象替代真实对象
3. **选择性运行测试**:
```bash
ctest -R test_Common # 只运行特定测试
```
---
### 问题 5: CMake 配置错误
**错误信息**:
```
CMake Error: ...
```
**解决方案**:
1. **清理构建目录**:
```bash
rm -rf build
mkdir build && cd build
```
2. **检查 CMake 版本**:
```bash
cmake --version # 需要 3.15+
```
3. **检查 CMakeLists.txt 语法**:
- 确保语法正确
- 检查变量名和路径
---
## 更多信息
### 相关文档
- **详细测试文档**: [测试文档](../docs/TESTING.md)(如果存在)
- **API 参考**: [API 参考文档](../docs/API-Reference.md)
- **故障排查**: [故障排查指南](../docs/TROUBLESHOOTING.md)
- **常见问题**: [常见问题解答](../docs/FAQ.md)
- **命名规范**: [命名规范改进文档](../docs/NAMING_IMPROVEMENTS.md)
### Google Test 文档
- [Google Test 官方文档](https://google.github.io/googletest/)
- [Google Test Primer](https://google.github.io/googletest/primer.html)
- [Google Test Advanced](https://google.github.io/googletest/advanced.html)
### 测试工具
- **ctest**: CMake 测试运行器
- **gtest**: Google Test 框架
- **valgrind**: 内存检查工具(可选)
- **gcov/lcov**: 代码覆盖率工具(可选)
---
## 贡献测试
欢迎贡献新的测试用例!在添加新测试时,请:
1. 遵循测试最佳实践
2. 确保测试独立且可重复
3. 添加适当的注释和文档
4. 运行所有测试确保没有破坏现有功能
5. 提交 Pull Request
如有问题,请参考 [故障排查指南](../docs/TROUBLESHOOTING.md) 或联系技术支持。
\ No newline at end of file
#!/bin/bash
# 测试运行脚本
# 用法: ./run_tests.sh [build_dir]
set -e
# 获取构建目录,默认为 ../build
BUILD_DIR=${1:-../build}
# 检查构建目录是否存在
if [ ! -d "$BUILD_DIR" ]; then
echo "错误: 构建目录 '$BUILD_DIR' 不存在"
echo "请先运行: mkdir build && cd build && cmake .. -DBUILD_TESTING=ON && make"
exit 1
fi
# 进入构建目录
cd "$BUILD_DIR"
# 检查是否启用了测试
if [ ! -f "CMakeCache.txt" ]; then
echo "错误: CMakeCache.txt 不存在,请先运行 cmake"
exit 1
fi
# 运行测试
echo "运行所有测试..."
echo "=========================================="
ctest --output-on-failure
echo ""
echo "=========================================="
echo "测试完成!"
#include <gtest/gtest.h>
#include "CanFrame.h"
#include <cstring>
// 测试 CANFrame 结构体
TEST(CanFrameTest, CANFrameStructure) {
CANFrame frame;
// 初始化测试
frame.can_id = 0x123;
frame.can_dlc = 8;
memset(frame.data, 0, sizeof(frame.data));
// 验证结构体成员
EXPECT_EQ(frame.can_id, 0x123);
EXPECT_EQ(frame.can_dlc, 8);
// 验证数据数组大小
EXPECT_EQ(sizeof(frame.data), 8);
}
// 测试 CANFrame 数据设置和读取
TEST(CanFrameTest, CANFrameData) {
CANFrame frame;
frame.can_id = 0x456;
frame.can_dlc = 4;
// 设置数据
frame.data[0] = 0x01;
frame.data[1] = 0x02;
frame.data[2] = 0x03;
frame.data[3] = 0x04;
// 验证数据
EXPECT_EQ(frame.data[0], 0x01);
EXPECT_EQ(frame.data[1], 0x02);
EXPECT_EQ(frame.data[2], 0x03);
EXPECT_EQ(frame.data[3], 0x04);
// 验证 can_dlc 与实际数据长度一致
EXPECT_EQ(frame.can_dlc, 4);
}
// 测试 CANFrame 边界值
TEST(CanFrameTest, CANFrameBoundaries) {
CANFrame frame;
// 测试最大 can_dlc
frame.can_dlc = 8;
for (int i = 0; i < 8; ++i) {
frame.data[i] = static_cast<uint8_t>(i);
}
EXPECT_EQ(frame.can_dlc, 8);
for (int i = 0; i < 8; ++i) {
EXPECT_EQ(frame.data[i], static_cast<uint8_t>(i));
}
// 测试最小 can_dlc
frame.can_dlc = 0;
EXPECT_EQ(frame.can_dlc, 0);
// 测试 can_dlc = 1
frame.can_dlc = 1;
frame.data[0] = 0xFF;
EXPECT_EQ(frame.can_dlc, 1);
EXPECT_EQ(frame.data[0], 0xFF);
}
// 测试 CANFrame 的 can_id 范围
TEST(CanFrameTest, CANFrameIdRange) {
CANFrame frame;
// 测试标准 CAN ID (11位,0-0x7FF)
frame.can_id = 0x000;
EXPECT_EQ(frame.can_id, 0x000);
frame.can_id = 0x7FF;
EXPECT_EQ(frame.can_id, 0x7FF);
// 测试扩展 CAN ID (29位,可以更大)
frame.can_id = 0x1FFFFFFF;
EXPECT_EQ(frame.can_id, 0x1FFFFFFF);
// 测试常见 ID 值
frame.can_id = 0x123;
EXPECT_EQ(frame.can_id, 0x123);
}
// 测试 CANFrame 数据清零
TEST(CanFrameTest, CANFrameDataZero) {
CANFrame frame;
frame.can_id = 0x789;
frame.can_dlc = 8;
// 设置一些数据
memset(frame.data, 0xFF, sizeof(frame.data));
// 清零数据
memset(frame.data, 0, sizeof(frame.data));
// 验证所有数据都是 0
for (int i = 0; i < 8; ++i) {
EXPECT_EQ(frame.data[i], 0);
}
}
// 测试 CANFrame 数据复制
TEST(CanFrameTest, CANFrameDataCopy) {
CANFrame frame1, frame2;
// 设置 frame1
frame1.can_id = 0xABC;
frame1.can_dlc = 5;
for (int i = 0; i < 5; ++i) {
frame1.data[i] = static_cast<uint8_t>(0x10 + i);
}
// 复制到 frame2
frame2.can_id = frame1.can_id;
frame2.can_dlc = frame1.can_dlc;
memcpy(frame2.data, frame1.data, frame1.can_dlc);
// 验证复制结果
EXPECT_EQ(frame2.can_id, frame1.can_id);
EXPECT_EQ(frame2.can_dlc, frame1.can_dlc);
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(frame2.data[i], frame1.data[i]);
}
}
// 测试 CANFrame 结构体大小
TEST(CanFrameTest, CANFrameSize) {
CANFrame frame;
// 验证结构体大小合理(can_id + can_dlc + data[8] + 可能的填充)
size_t expected_min_size = sizeof(uint32_t) + sizeof(uint8_t) + 8;
EXPECT_GE(sizeof(frame), expected_min_size);
// 验证数据数组确实是 8 字节
EXPECT_EQ(sizeof(frame.data), 8);
}
#include <gtest/gtest.h>
#include "Common.h"
// 测试 LINKER_HAND 枚举值
TEST(CommonTest, LinkerHandEnumValues) {
// 验证枚举值是否正确定义
EXPECT_EQ(static_cast<int>(O6), 0);
EXPECT_EQ(static_cast<int>(L6), 1);
EXPECT_EQ(static_cast<int>(L7), 2);
EXPECT_EQ(static_cast<int>(L10), 3);
EXPECT_EQ(static_cast<int>(L20), 4);
EXPECT_EQ(static_cast<int>(L21), 5);
EXPECT_EQ(static_cast<int>(L25), 6);
}
// 测试 HAND_TYPE 枚举值
TEST(CommonTest, HandTypeEnumValues) {
EXPECT_EQ(static_cast<uint32_t>(LEFT), 0x28);
EXPECT_EQ(static_cast<uint32_t>(RIGHT), 0x27);
// 验证左右手类型不同
EXPECT_NE(LEFT, RIGHT);
}
// 测试 COMM_TYPE 枚举值
TEST(CommonTest, CommTypeEnumValues) {
EXPECT_EQ(static_cast<int>(COMM_CAN_0), 0);
EXPECT_EQ(static_cast<int>(COMM_CAN_1), 1);
EXPECT_EQ(static_cast<int>(COMM_MODBUS), 2);
EXPECT_EQ(static_cast<int>(COMM_ETHERCAT), 3);
}
// 测试 Common 命名空间中的版本号
TEST(CommonTest, CurrentHandVersion) {
EXPECT_GT(linkerhand::Common::current_hand_version, 0.0f);
EXPECT_LE(linkerhand::Common::current_hand_version, 10.0f); // 合理的版本号范围
}
// 测试枚举值的类型转换
TEST(CommonTest, EnumTypeConversions) {
LINKER_HAND hand = L10;
HAND_TYPE type = RIGHT;
COMM_TYPE comm = COMM_CAN_0;
EXPECT_EQ(hand, L10);
EXPECT_EQ(type, RIGHT);
EXPECT_EQ(comm, COMM_CAN_0);
}
// 参数化测试:测试所有 LINKER_HAND 类型
class LinkerHandTypeTest : public ::testing::TestWithParam<LINKER_HAND> {};
TEST_P(LinkerHandTypeTest, ValidHandTypes) {
LINKER_HAND hand = GetParam();
// 验证是有效的枚举值
EXPECT_GE(static_cast<int>(hand), 0);
EXPECT_LE(static_cast<int>(hand), 6);
}
INSTANTIATE_TEST_SUITE_P(
AllHandTypes,
LinkerHandTypeTest,
::testing::Values(O6, L6, L7, L10, L20, L21, L25)
);
// 参数化测试:测试所有 COMM_TYPE 类型
class CommTypeTest : public ::testing::TestWithParam<COMM_TYPE> {};
TEST_P(CommTypeTest, ValidCommTypes) {
COMM_TYPE comm = GetParam();
// 验证是有效的枚举值
EXPECT_GE(static_cast<int>(comm), 0);
EXPECT_LE(static_cast<int>(comm), 3);
}
INSTANTIATE_TEST_SUITE_P(
AllCommTypes,
CommTypeTest,
::testing::Values(COMM_CAN_0, COMM_CAN_1, COMM_MODBUS, COMM_ETHERCAT)
);
#include <gtest/gtest.h>
#include "IHand.h"
#include <vector>
#include <chrono>
#include <thread>
// 创建一个测试用的 IHand 实现类
class TestHand : public linkerhand::hand::IHand {
public:
void setJointPositions(const std::vector<uint8_t> &jointAngles) override {
(void)jointAngles;
}
};
// 测试 getSubVector 函数(单参数版本)
TEST(IHandUtilsTest, GetSubVectorSingleArg) {
TestHand hand;
// 测试正常情况
std::vector<uint8_t> vec = {0, 1, 2, 3, 4, 5};
std::vector<uint8_t> result = hand.getSubVector(vec);
EXPECT_EQ(result.size(), 5);
EXPECT_EQ(result[0], 1);
EXPECT_EQ(result[1], 2);
EXPECT_EQ(result[4], 5);
// 测试只有一个元素的情况
std::vector<uint8_t> vec_single = {0};
std::vector<uint8_t> result_single = hand.getSubVector(vec_single);
EXPECT_TRUE(result_single.empty());
// 测试空向量
std::vector<uint8_t> vec_empty = {};
std::vector<uint8_t> result_empty = hand.getSubVector(vec_empty);
EXPECT_TRUE(result_empty.empty());
// 测试两个元素的情况
std::vector<uint8_t> vec_two = {0, 1};
std::vector<uint8_t> result_two = hand.getSubVector(vec_two);
EXPECT_EQ(result_two.size(), 1);
EXPECT_EQ(result_two[0], 1);
}
// 测试 getSubVector 函数(双参数版本)
TEST(IHandUtilsTest, GetSubVectorDoubleArg) {
TestHand hand;
// 测试正常情况
std::vector<uint8_t> vec1 = {0, 1, 2, 3};
std::vector<uint8_t> vec2 = {0, 4, 5, 6};
std::vector<uint8_t> result = hand.getSubVector(vec1, vec2);
EXPECT_EQ(result.size(), 6); // 3 + 3
EXPECT_EQ(result[0], 1);
EXPECT_EQ(result[1], 2);
EXPECT_EQ(result[2], 3);
EXPECT_EQ(result[3], 4);
EXPECT_EQ(result[4], 5);
EXPECT_EQ(result[5], 6);
// 测试一个向量只有一个元素
std::vector<uint8_t> vec_single = {0};
std::vector<uint8_t> vec_normal = {0, 1, 2};
std::vector<uint8_t> result_mixed = hand.getSubVector(vec_single, vec_normal);
EXPECT_EQ(result_mixed.size(), 2); // 0 + 2
EXPECT_EQ(result_mixed[0], 1);
EXPECT_EQ(result_mixed[1], 2);
// 测试两个向量都只有一个元素
std::vector<uint8_t> vec1_single = {0};
std::vector<uint8_t> vec2_single = {0};
std::vector<uint8_t> result_both_single = hand.getSubVector(vec1_single, vec2_single);
EXPECT_TRUE(result_both_single.empty());
// 测试空向量
std::vector<uint8_t> vec_empty = {};
std::vector<uint8_t> vec_normal2 = {0, 1, 2};
std::vector<uint8_t> result_empty = hand.getSubVector(vec_empty, vec_normal2);
EXPECT_EQ(result_empty.size(), 2);
}
// 测试 getCurrentTime 函数
TEST(IHandUtilsTest, GetCurrentTime) {
TestHand hand;
// 获取时间字符串
std::string time1 = hand.getCurrentTime();
// 验证时间字符串不为空
EXPECT_FALSE(time1.empty());
// 验证时间字符串格式(应该包含日期和时间)
// 格式应该是 "YYYY-MM-DD HH:MM:SS.mmm"
EXPECT_GT(time1.length(), 19); // 至少包含日期和时间部分
// 验证包含日期分隔符
EXPECT_NE(time1.find('-'), std::string::npos);
// 验证包含时间分隔符
EXPECT_NE(time1.find(':'), std::string::npos);
// 等待一小段时间后再次获取时间
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::string time2 = hand.getCurrentTime();
// 验证两次获取的时间不同(或至少格式相同)
EXPECT_EQ(time1.length(), time2.length());
// 验证时间字符串格式一致
// 都应该是 "YYYY-MM-DD HH:MM:SS.mmm" 格式
size_t space_pos1 = time1.find(' ');
size_t space_pos2 = time2.find(' ');
EXPECT_NE(space_pos1, std::string::npos);
EXPECT_NE(space_pos2, std::string::npos);
// 验证日期部分格式
std::string date1 = time1.substr(0, space_pos1);
std::string date2 = time2.substr(0, space_pos2);
EXPECT_EQ(date1.length(), 10); // "YYYY-MM-DD"
EXPECT_EQ(date2.length(), 10);
// 验证日期部分包含两个连字符
size_t dash_count1 = 0;
size_t dash_count2 = 0;
for (char c : date1) {
if (c == '-') dash_count1++;
}
for (char c : date2) {
if (c == '-') dash_count2++;
}
EXPECT_EQ(dash_count1, 2);
EXPECT_EQ(dash_count2, 2);
}
// 测试 getCurrentTime 的时间递增
TEST(IHandUtilsTest, GetCurrentTimeIncrement) {
TestHand hand;
std::string time1 = hand.getCurrentTime();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::string time2 = hand.getCurrentTime();
// 由于我们等待了 100ms,时间应该不同
// 注意:由于时间格式包含毫秒,两次时间应该不同
// 但由于时间精度问题,我们只验证格式正确
EXPECT_FALSE(time1.empty());
EXPECT_FALSE(time2.empty());
}
// 测试 getSubVector 的边界情况
TEST(IHandUtilsTest, GetSubVectorEdgeCases) {
TestHand hand;
// 测试大向量
std::vector<uint8_t> large_vec(1000, 0);
for (size_t i = 0; i < large_vec.size(); ++i) {
large_vec[i] = static_cast<uint8_t>(i % 256);
}
std::vector<uint8_t> result = hand.getSubVector(large_vec);
// 验证大小:跳过第一个元素,所以应该是 999
EXPECT_EQ(result.size(), 999);
// 验证第一个元素:应该是原始向量的第二个元素 (1)
EXPECT_EQ(result[0], 1);
// 修复:result[998] 对应 large_vec[999]
// large_vec[999] = 999 % 256 = 231
EXPECT_EQ(static_cast<int>(result[998]), 231);
// 附加验证:确保理解正确
// result[254] 对应 large_vec[255] = 255
EXPECT_EQ(static_cast<int>(result[254]), 255);
}
#include <gtest/gtest.h>
#include "RangeToArc.h"
#include <cmath>
#include <vector>
// 测试 is_within_range 函数
TEST(RangeToArcTest, IsWithinRange) {
// 值在范围内
EXPECT_DOUBLE_EQ(is_within_range(5.0, 0.0, 10.0), 5.0);
EXPECT_DOUBLE_EQ(is_within_range(0.0, 0.0, 10.0), 0.0); // 边界值
EXPECT_DOUBLE_EQ(is_within_range(10.0, 0.0, 10.0), 10.0); // 边界值
// 值小于最小值
EXPECT_DOUBLE_EQ(is_within_range(-5.0, 0.0, 10.0), 0.0);
// 值大于最大值
EXPECT_DOUBLE_EQ(is_within_range(15.0, 0.0, 10.0), 10.0);
// 负值范围
EXPECT_DOUBLE_EQ(is_within_range(-2.0, -5.0, -1.0), -2.0);
EXPECT_DOUBLE_EQ(is_within_range(-6.0, -5.0, -1.0), -5.0);
EXPECT_DOUBLE_EQ(is_within_range(0.0, -5.0, -1.0), -1.0);
}
// 测试 scale_value 函数
TEST(RangeToArcTest, ScaleValue) {
// 基本缩放测试
EXPECT_NEAR(scale_value(5.0, 0.0, 10.0, 0.0, 100.0), 50.0, 0.001);
EXPECT_NEAR(scale_value(0.0, 0.0, 10.0, 0.0, 100.0), 0.0, 0.001);
EXPECT_NEAR(scale_value(10.0, 0.0, 10.0, 0.0, 100.0), 100.0, 0.001);
// 负值范围缩放
EXPECT_NEAR(scale_value(-2.0, -5.0, 0.0, 0.0, 100.0), 60.0, 0.001);
// 不同范围的缩放
EXPECT_NEAR(scale_value(128, 0, 255, 0.0, 1.57), 0.785, 0.01);
}
// 测试 should_skip_joint 函数
TEST(RangeToArcTest, ShouldSkipJoint) {
// 测试不同的关节类型和索引
// 注意:这个函数的具体实现需要查看源代码
// 这里假设一些基本行为
bool result1 = should_skip_joint(0, 0);
bool result2 = should_skip_joint(0, 1);
// 验证函数不会崩溃
EXPECT_TRUE(result1 == true || result1 == false);
EXPECT_TRUE(result2 == true || result2 == false);
}
// 测试 initialize_params 函数
TEST(RangeToArcTest, InitializeParams) {
std::vector<double> min_limits;
std::vector<double> max_limits;
std::vector<int> derict;
// 测试 L10 左手参数初始化
bool result = initialize_params(static_cast<int>(10), "left", min_limits, max_limits, derict);
EXPECT_TRUE(result);
EXPECT_FALSE(min_limits.empty());
EXPECT_FALSE(max_limits.empty());
EXPECT_FALSE(derict.empty());
EXPECT_EQ(min_limits.size(), max_limits.size());
EXPECT_EQ(min_limits.size(), derict.size());
// 验证 L10 左手应该有 10 个关节
EXPECT_EQ(min_limits.size(), 10);
// 验证每个关节的最小值小于等于最大值
for (size_t i = 0; i < min_limits.size(); ++i) {
EXPECT_LE(min_limits[i], max_limits[i]);
}
}
// 测试 range_to_arc 函数
TEST(RangeToArcTest, RangeToArc) {
// 测试 L10 左手的转换
std::vector<uint8_t> hand_range = {128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
std::vector<double> result = range_to_arc(static_cast<int>(10), "left", hand_range);
EXPECT_FALSE(result.empty());
EXPECT_EQ(result.size(), hand_range.size());
// 验证结果在合理范围内(对于 L10 左手)
for (size_t i = 0; i < result.size(); ++i) {
// L10 左手的范围应该在定义的 min/max 之间
EXPECT_GE(result[i], l10_l_min[i] - 0.1); // 允许小的误差
EXPECT_LE(result[i], l10_l_max[i] + 0.1);
}
}
// 测试 arc_to_range 函数
TEST(RangeToArcTest, ArcToRange) {
// 测试 L10 左手的转换
// 使用中间值进行测试
std::vector<double> hand_arc(10, 0.5);
std::vector<uint8_t> result = arc_to_range(static_cast<int>(10), "left", hand_arc);
EXPECT_FALSE(result.empty());
EXPECT_EQ(result.size(), hand_arc.size());
// 验证结果在 0-255 范围内
for (uint8_t value : result) {
EXPECT_GE(value, 0);
EXPECT_LE(value, 255);
}
}
// 测试 range_to_arc 和 arc_to_range 的往返转换
TEST(RangeToArcTest, RoundTripConversion) {
// 测试往返转换的精度
std::vector<uint8_t> original = {0, 64, 128, 192, 255, 100, 150, 200, 50, 75};
std::vector<double> arc = range_to_arc(static_cast<int>(10), "left", original);
std::vector<uint8_t> converted_back = arc_to_range(static_cast<int>(10), "left", arc);
EXPECT_EQ(original.size(), converted_back.size());
// 由于浮点数精度和范围限制,允许一定的误差
for (size_t i = 0; i < original.size(); ++i) {
int diff = std::abs(static_cast<int>(original[i]) - static_cast<int>(converted_back[i]));
EXPECT_LE(diff, 2); // 允许最多 2 的误差
}
}
// 测试边界值
TEST(RangeToArcTest, BoundaryValues) {
// 测试最小值
std::vector<uint8_t> min_range(10, 0);
std::vector<double> min_arc = range_to_arc(static_cast<int>(10), "left", min_range);
EXPECT_FALSE(min_arc.empty());
// 测试最大值
std::vector<uint8_t> max_range(10, 255);
std::vector<double> max_arc = range_to_arc(static_cast<int>(10), "left", max_range);
EXPECT_FALSE(max_arc.empty());
// 测试中间值
std::vector<uint8_t> mid_range(10, 128);
std::vector<double> mid_arc = range_to_arc(static_cast<int>(10), "left", mid_range);
EXPECT_FALSE(mid_arc.empty());
}
// 测试不同型号的转换
TEST(RangeToArcTest, DifferentHandTypes) {
// 只测试代码中支持的手型
// 测试 L7 - 支持
std::vector<uint8_t> l7_range = {128, 128, 128, 128, 128, 128, 128};
std::vector<double> l7_arc = range_to_arc(7, "left", l7_range);
EXPECT_FALSE(l7_arc.empty());
EXPECT_EQ(l7_arc.size(), 7);
// 测试 L10 - 支持
std::vector<uint8_t> l10_range = {128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
std::vector<double> l10_arc = range_to_arc(10, "left", l10_range);
EXPECT_FALSE(l10_arc.empty());
EXPECT_EQ(l10_arc.size(), 10);
// 测试 L20 - 支持
std::vector<uint8_t> l20_range(20, 128);
std::vector<double> l20_arc = range_to_arc(20, "left", l20_range);
EXPECT_FALSE(l20_arc.empty());
EXPECT_EQ(l20_arc.size(), 20);
// 测试 L21 - 支持
std::vector<uint8_t> l21_range(25, 128);
std::vector<double> l21_arc = range_to_arc(21, "left", l21_range);
EXPECT_FALSE(l21_arc.empty());
EXPECT_EQ(l21_arc.size(), 25);
// 测试 L25 - 支持
std::vector<uint8_t> l25_range(25, 128);
std::vector<double> l25_arc = range_to_arc(25, "left", l25_range);
EXPECT_FALSE(l25_arc.empty());
EXPECT_EQ(l25_arc.size(), 25);
// 注意:不要测试不支持的手型,如 L6 (6)
// std::vector<uint8_t> l6_range = {128, 128, 128, 128, 128, 128};
// std::vector<double> l6_arc = range_to_arc(6, "left", l6_range);
// EXPECT_FALSE(l6_arc.empty()); // 这会失败!
}
Attribute VB_Name = "PCANBasic"
' PCANBasic.bas
'
' ~~~~~~~~~~~~
'
' PCAN-Basic API
'
' ~~~~~~~~~~~~
'
' ------------------------------------------------------------------
' Author : Keneth Wagner
' Last change: 2022-07-06
'
' Language: Visual Basic 6.0
' ------------------------------------------------------------------
'
' Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
' more Info at http://www.peak-system.com
'
'///////////////////////////////////////////////////////////
'/ Value definitions
'///////////////////////////////////////////////////////////
' Currently defined and supported PCAN channels
'
Public Const PCAN_NONEBUS As Long = &H0 ' Undefined/default value for a PCAN bus
Public Const PCAN_ISABUS1 As Long = &H21 ' PCAN-ISA interface, channel 1
Public Const PCAN_ISABUS2 As Long = &H22 ' PCAN-ISA interface, channel 2
Public Const PCAN_ISABUS3 As Long = &H23 ' PCAN-ISA interface, channel 3
Public Const PCAN_ISABUS4 As Long = &H24 ' PCAN-ISA interface, channel 4
Public Const PCAN_ISABUS5 As Long = &H25 ' PCAN-ISA interface, channel 5
Public Const PCAN_ISABUS6 As Long = &H26 ' PCAN-ISA interface, channel 6
Public Const PCAN_ISABUS7 As Long = &H27 ' PCAN-ISA interface, channel 7
Public Const PCAN_ISABUS8 As Long = &H28 ' PCAN-ISA interface, channel 8
Public Const PCAN_DNGBUS1 As Long = &H31 ' PCAN-Dongle/LPT interface, channel 1
Public Const PCAN_PCIBUS1 As Long = &H41 ' PCAN-PCI interface, channel 1
Public Const PCAN_PCIBUS2 As Long = &H42 ' PCAN-PCI interface, channel 2
Public Const PCAN_PCIBUS3 As Long = &H43 ' PCAN-PCI interface, channel 3
Public Const PCAN_PCIBUS4 As Long = &H44 ' PCAN-PCI interface, channel 4
Public Const PCAN_PCIBUS5 As Long = &H45 ' PCAN-PCI interface, channel 5
Public Const PCAN_PCIBUS6 As Long = &H46 ' PCAN-PCI interface, channel 6
Public Const PCAN_PCIBUS7 As Long = &H47 ' PCAN-PCI interface, channel 7
Public Const PCAN_PCIBUS8 As Long = &H48 ' PCAN-PCI interface, channel 8
Public Const PCAN_PCIBUS9 As Long = &H409 ' PCAN-PCI interface, channel 9
Public Const PCAN_PCIBUS10 As Long = &H40A ' PCAN-PCI interface, channel 10
Public Const PCAN_PCIBUS11 As Long = &H40B ' PCAN-PCI interface, channel 11
Public Const PCAN_PCIBUS12 As Long = &H40C ' PCAN-PCI interface, channel 12
Public Const PCAN_PCIBUS13 As Long = &H40D ' PCAN-PCI interface, channel 13
Public Const PCAN_PCIBUS14 As Long = &H40E ' PCAN-PCI interface, channel 14
Public Const PCAN_PCIBUS15 As Long = &H40F ' PCAN-PCI interface, channel 15
Public Const PCAN_PCIBUS16 As Long = &H410 ' PCAN-PCI interface, channel 16
Public Const PCAN_USBBUS1 As Long = &H51 ' PCAN-USB interface, channel 1
Public Const PCAN_USBBUS2 As Long = &H52 ' PCAN-USB interface, channel 2
Public Const PCAN_USBBUS3 As Long = &H53 ' PCAN-USB interface, channel 3
Public Const PCAN_USBBUS4 As Long = &H54 ' PCAN-USB interface, channel 4
Public Const PCAN_USBBUS5 As Long = &H55 ' PCAN-USB interface, channel 5
Public Const PCAN_USBBUS6 As Long = &H56 ' PCAN-USB interface, channel 6
Public Const PCAN_USBBUS7 As Long = &H57 ' PCAN-USB interface, channel 7
Public Const PCAN_USBBUS8 As Long = &H58 ' PCAN-USB interface, channel 8
Public Const PCAN_USBBUS9 As Long = &H509 ' PCAN-USB interface, channel 9
Public Const PCAN_USBBUS10 As Long = &H50A ' PCAN-USB interface, channel 10
Public Const PCAN_USBBUS11 As Long = &H50B ' PCAN-USB interface, channel 11
Public Const PCAN_USBBUS12 As Long = &H50C ' PCAN-USB interface, channel 12
Public Const PCAN_USBBUS13 As Long = &H50D ' PCAN-USB interface, channel 13
Public Const PCAN_USBBUS14 As Long = &H50E ' PCAN-USB interface, channel 14
Public Const PCAN_USBBUS15 As Long = &H50F ' PCAN-USB interface, channel 15
Public Const PCAN_USBBUS16 As Long = &H510 ' PCAN-USB interface, channel 16
Public Const PCAN_PCCBUS1 As Long = &H61 ' PCAN-PC Card interface, channel 1
Public Const PCAN_PCCBUS2 As Long = &H62 ' PCAN-PC Card interface, channel 2
Public Const PCAN_LANBUS1 As Long = &H801 ' PCAN-LAN interface, channel 1
Public Const PCAN_LANBUS2 As Long = &H802 ' PCAN-LAN interface, channel 2
Public Const PCAN_LANBUS3 As Long = &H803 ' PCAN-LAN interface, channel 3
Public Const PCAN_LANBUS4 As Long = &H804 ' PCAN-LAN interface, channel 4
Public Const PCAN_LANBUS5 As Long = &H805 ' PCAN-LAN interface, channel 5
Public Const PCAN_LANBUS6 As Long = &H806 ' PCAN-LAN interface, channel 6
Public Const PCAN_LANBUS7 As Long = &H807 ' PCAN-LAN interface, channel 7
Public Const PCAN_LANBUS8 As Long = &H808 ' PCAN-LAN interface, channel 8
Public Const PCAN_LANBUS9 As Long = &H809 ' PCAN-LAN interface, channel 9
Public Const PCAN_LANBUS10 As Long = &H80A ' PCAN-LAN interface, channel 10
Public Const PCAN_LANBUS11 As Long = &H80B ' PCAN-LAN interface, channel 11
Public Const PCAN_LANBUS12 As Long = &H80C ' PCAN-LAN interface, channel 12
Public Const PCAN_LANBUS13 As Long = &H80D ' PCAN-LAN interface, channel 13
Public Const PCAN_LANBUS14 As Long = &H80E ' PCAN-LAN interface, channel 14
Public Const PCAN_LANBUS15 As Long = &H80F ' PCAN-LAN interface, channel 15
Public Const PCAN_LANBUS16 As Long = &H810 ' PCAN-LAN interface, channel 16
' Represent the PCAN error and status codes
'
Public Const PCAN_ERROR_OK As Long = &H0 ' No error
Public Const PCAN_ERROR_XMTFULL As Long = &H1 ' Transmit buffer in CAN controller is full
Public Const PCAN_ERROR_OVERRUN As Long = &H2 ' CAN controller was read too late
Public Const PCAN_ERROR_BUSLIGHT As Long = &H4 ' Bus error: an error counter reached the 'light' limit [Not used with the *FD functions]
Public Const PCAN_ERROR_BUSHEAVY As Long = &H8 ' Bus error: an error counter reached the 'heavy' limit
Public Const PCAN_ERROR_BUSWARNING = PCAN_ERROR_BUSHEAVY ' An error counter reached the 'warning' limit [ONLY used with the *FD functions]
Public Const PCAN_ERROR_BUSPASSIVE As Long = &H40000 ' Bus error: the CAN controller is in bus-off state
Public Const PCAN_ERROR_BUSOFF As Long = &H10 ' Bus error: the CAN controller is in bus-off state
Public Const PCAN_ERROR_ANYBUSERR = (PCAN_ERROR_BUSWARNING Or PCAN_ERROR_BUSLIGHT Or PCAN_ERROR_BUSHEAVY Or PCAN_ERROR_BUSOFF Or PCAN_ERROR_BUSPASSIVE) ' Mask for all bus errors
Public Const PCAN_ERROR_QRCVEMPTY As Long = &H20 ' Receive queue is empty
Public Const PCAN_ERROR_QOVERRUN As Long = &H40 ' Receive queue was read too late
Public Const PCAN_ERROR_QXMTFULL As Long = &H80 ' Transmit queue is full
Public Const PCAN_ERROR_REGTEST As Long = &H100 ' Test of the CAN controller hardware registers failed (no hardware found)
Public Const PCAN_ERROR_NODRIVER As Long = &H200 ' Driver not loaded
Public Const PCAN_ERROR_HWINUSE As Long = &H400 ' Hardware already in use by a Net
Public Const PCAN_ERROR_NETINUSE As Long = &H800 ' A Client is already connected to the Net
Public Const PCAN_ERROR_ILLHW As Long = &H1400 ' Hardware handle is invalid
Public Const PCAN_ERROR_ILLNET As Long = &H1800 ' Net handle is invalid
Public Const PCAN_ERROR_ILLCLIENT As Long = &H1C00 ' Client handle is invalid
Public Const PCAN_ERROR_ILLHANDLE = (PCAN_ERROR_ILLHW Or PCAN_ERROR_ILLNET Or PCAN_ERROR_ILLCLIENT) ' Mask for all handle errors
Public Const PCAN_ERROR_RESOURCE As Long = &H2000 ' Resource (FIFO, Client, timeout) cannot be created
Public Const PCAN_ERROR_ILLPARAMTYPE As Long = &H4000 ' Invalid parameter
Public Const PCAN_ERROR_ILLPARAMVAL As Long = &H8000 ' Invalid parameter value
Public Const PCAN_ERROR_UNKNOWN As Long = &H10000 ' Unknown error
Public Const PCAN_ERROR_ILLDATA As Long = &H20000 ' Invalid data, function, or action
Public Const PCAN_ERROR_ILLMODE As Long = &H80000 ' Driver object state is wrong for the attempted operation
Public Const PCAN_ERROR_CAUTION As Long = &H2000000 ' An operation was successfully carried out, however, irregularities were registered
Public Const PCAN_ERROR_INITIALIZE As Long = &H4000000 ' Channel is not initialized [Value was changed from &H40000 to &H4000000]
Public Const PCAN_ERROR_ILLOPERATION As Long = &H8000000 ' Invalid operation [Value was changed from &H80000 to &H8000000]
' PCAN devices
'
Public Const PCAN_NONE = &H0 ' Undefined, unknown or not selected PCAN device value
Public Const PCAN_PEAKCAN = &H1 ' PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
Public Const PCAN_ISA = &H2 ' PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
Public Const PCAN_DNG = &H3 ' PCAN-Dongle
Public Const PCAN_PCI = &H4 ' PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
Public Const PCAN_USB = &H5 ' PCAN-USB and PCAN-USB Pro
Public Const PCAN_PCC = &H6 ' PCAN-PC Card
Public Const PCAN_VIRTUAL = &H7 ' PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
Public Const PCAN_LAN = &H8 ' PCAN Gateway devices
' PCAN parameters
'
Public Const PCAN_DEVICE_ID = &H1 ' Device identifier parameter
Public Const PCAN_5VOLTS_POWER = &H2 ' 5-Volt power parameter
Public Const PCAN_RECEIVE_EVENT = &H3 ' PCAN receive event handler parameter
Public Const PCAN_MESSAGE_FILTER = &H4 ' PCAN message filter parameter
Public Const PCAN_API_VERSION = &H5 ' PCAN-Basic API version parameter
Public Const PCAN_CHANNEL_VERSION = &H6 ' PCAN device channel version parameter
Public Const PCAN_BUSOFF_AUTORESET = &H7 ' PCAN Reset-On-Busoff parameter
Public Const PCAN_LISTEN_ONLY = &H8 ' PCAN Listen-Only parameter
Public Const PCAN_LOG_LOCATION = &H9 ' Directory path for log files
Public Const PCAN_LOG_STATUS = &HA ' Debug-Log activation status
Public Const PCAN_LOG_CONFIGURE = &HB ' Configuration of the debugged information (LOG_FUNCTION_***)
Public Const PCAN_LOG_TEXT = &HC ' Custom insertion of text into the log file
Public Const PCAN_CHANNEL_CONDITION = &HD ' Availability status of a PCAN-Channel
Public Const PCAN_HARDWARE_NAME = &HE ' PCAN hardware name parameter
Public Const PCAN_RECEIVE_STATUS = &HF ' Message reception status of a PCAN-Channel
Public Const PCAN_CONTROLLER_NUMBER = &H10 ' CAN-Controller number of a PCAN-Channel
Public Const PCAN_TRACE_LOCATION = &H11 ' Directory path for PCAN trace files
Public Const PCAN_TRACE_STATUS = &H12 ' CAN tracing activation status
Public Const PCAN_TRACE_SIZE = &H13 ' Configuration of the maximum file size of a CAN trace.
Public Const PCAN_TRACE_CONFIGURE = &H14 ' Configuration of the trace file storing mode (TRACE_FILE_***)
Public Const PCAN_CHANNEL_IDENTIFYING = &H15 ' Physical identification of a USB based PCAN-Channel by blinking its associated LED
Public Const PCAN_CHANNEL_FEATURES = &H16 ' Capabilities of a PCAN device (FEATURE_***)
Public Const PCAN_BITRATE_ADAPTING = &H17 ' Using of an existing bit rate (PCAN-View connected to a channel)
Public Const PCAN_BITRATE_INFO = &H18 ' Configured bit rate as Btr0Btr1 value
Public Const PCAN_BITRATE_INFO_FD = &H19 ' Configured bit rate as TPCANBitrateFD string
Public Const PCAN_BUSSPEED_NOMINAL = &H1A ' Configured nominal CAN Bus speed as Bits per seconds
Public Const PCAN_BUSSPEED_DATA = &H1B ' Configured CAN data speed as Bits per seconds
Public Const PCAN_IP_ADDRESS = &H1C ' Remote address of a LAN channel as string in IPv4 format
Public Const PCAN_LAN_SERVICE_STATUS = &H1D ' Status of the Virtual PCAN-Gateway Service
Public Const PCAN_ALLOW_STATUS_FRAMES = &H1E ' Status messages reception status within a PCAN-Channel
Public Const PCAN_ALLOW_RTR_FRAMES = &H1F ' RTR messages reception status within a PCAN-Channel
Public Const PCAN_ALLOW_ERROR_FRAMES = &H20 ' Error messages reception status within a PCAN-Channel
Public Const PCAN_INTERFRAME_DELAY = &H21 ' Delay, in microseconds, between sending frames
Public Const PCAN_ACCEPTANCE_FILTER_11BIT = &H22 ' Filter over code and mask patterns for 11-Bit messages
Public Const PCAN_ACCEPTANCE_FILTER_29BIT = &H23 ' Filter over code and mask patterns for 29-Bit messages
Public Const PCAN_IO_DIGITAL_CONFIGURATION = &H24 ' Output mode Of 32 digital I/O pin Of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
Public Const PCAN_IO_DIGITAL_VALUE = &H25 ' Value assigned To a 32 digital I/O pins Of a PCAN-USB Chip
Public Const PCAN_IO_DIGITAL_SET = &H26 ' Value assigned To a 32 digital I/O pins Of a PCAN-USB Chip - Multiple digital I/O pins To 1 = High
Public Const PCAN_IO_DIGITAL_CLEAR = &H27 ' Clear multiple digital I/O pins To 0
Public Const PCAN_IO_ANALOG_VALUE = &H28 ' Get value Of a Single analog input pin
Public Const PCAN_FIRMWARE_VERSION = &H29 ' Get the version of the firmware used by the device associated With a PCAN-Channel
Public Const PCAN_ATTACHED_CHANNELS_COUNT = &H2A ' Get the amount of PCAN channels attached to a system
Public Const PCAN_ATTACHED_CHANNELS = &H2B ' Get information about PCAN channels attached to a system
Public Const PCAN_ALLOW_ECHO_FRAMES = &H2C ' Echo messages reception status within a PCAN-Channel
Public Const PCAN_DEVICE_PART_NUMBER = &H2D ' Get the part number associated To a device
' DEPRECATED parameters
'
Public Const PCAN_DEVICE_NUMBER = PCAN_DEVICE_ID ' Deprecated parameter. Use PCAN_DEVICE_ID instead
' PCAN parameter values
'
Public Const PCAN_PARAMETER_OFF = &H0 ' The PCAN parameter is not set (inactive)
Public Const PCAN_PARAMETER_ON = &H1 ' The PCAN parameter is set (active)
Public Const PCAN_FILTER_CLOSE = &H0 ' The PCAN filter is closed. No messages will be received
Public Const PCAN_FILTER_OPEN = &H1 ' The PCAN filter is fully opened. All messages will be received
Public Const PCAN_FILTER_CUSTOM = &H2 ' The PCAN filter is custom configured. Only registered messages will be received
Public Const PCAN_CHANNEL_UNAVAILABLE = &H0 ' The PCAN-Channel handle is illegal, or its associated hardware is not available
Public Const PCAN_CHANNEL_AVAILABLE = &H1 ' The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
Public Const PCAN_CHANNEL_OCCUPIED = &H2 ' The PCAN-Channel handle is valid, and is already being used
Public Const PCAN_CHANNEL_PCANVIEW = (PCAN_CHANNEL_AVAILABLE Or PCAN_CHANNEL_OCCUPIED) ' The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
Public Const LOG_FUNCTION_DEFAULT = &H0 ' Logs system exceptions / errors
Public Const LOG_FUNCTION_ENTRY = &H1 ' Logs the entries to the PCAN-Basic API functions
Public Const LOG_FUNCTION_PARAMETERS = &H2 ' Logs the parameters passed to the PCAN-Basic API functions
Public Const LOG_FUNCTION_LEAVE = &H4 ' Logs the exits from the PCAN-Basic API functions
Public Const LOG_FUNCTION_WRITE = &H8 ' Logs the CAN messages passed to the CAN_Write function
Public Const LOG_FUNCTION_READ = &H10 ' Logs the CAN messages received within the CAN_Read function
Public Const LOG_FUNCTION_ALL = &HFFFF ' Logs all possible information within the PCAN-Basic API functions
Public Const TRACE_FILE_SINGLE = &H0 ' A single file is written until it size reaches PAN_TRACE_SIZE.
Public Const TRACE_FILE_SEGMENTED = &H1 ' Traced data is distributed in several files with size PAN_TRACE_SIZE.
Public Const TRACE_FILE_DATE = &H2 ' Includes the date into the name of the trace file.
Public Const TRACE_FILE_TIME = &H4 ' Includes the start time into the name of the trace file.
Public Const TRACE_FILE_OVERWRITE = &H80 ' Causes the overwriting of available traces (same name).
Public Const FEATURE_FD_CAPABLE = &H1 ' Device supports flexible data-rate (CAN-FD)
Public Const FEATURE_DELAY_CAPABLE = &H2 ' Device supports a delay between sending frames (FPGA based USB devices)
Public Const FEATURE_IO_CAPABLE = &H4 ' Device supports I/O functionality for electronic circuits (USB-Chip devices)
Public Const SERVICE_STATUS_STOPPED = &H1 ' The service is not running
Public Const SERVICE_STATUS_RUNNING = &H4 ' The service is running
' Other constants
'
Public Const MAX_LENGTH_HARDWARE_NAME = 33 ' Maximum length of the name of a device: 32 characters + terminator
Public Const MAX_LENGTH_VERSION_STRING = 256 ' Maximum length of a version string: 255 characters + terminator
' PCAN message types
'
Public Const PCAN_MESSAGE_STANDARD = &H0 ' The PCAN message is a CAN Standard Frame (11-bit identifier)
Public Const PCAN_MESSAGE_RTR = &H1 ' The PCAN message is a CAN Remote-Transfer-Request Frame
Public Const PCAN_MESSAGE_EXTENDED = &H2 ' The PCAN message is a CAN Extended Frame (29-bit identifier)
Public Const PCAN_MESSAGE_FD = &H4 ' The PCAN message represents a FD frame in terms of CiA Specs
Public Const PCAN_MESSAGE_BRS = &H8 ' The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
Public Const PCAN_MESSAGE_ESI = &H10 ' The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
Public Const PCAN_MESSAGE_ECHO = &H20 ' The PCAN message represents an echo CAN Frame
Public Const PCAN_MESSAGE_ERRFRAME = &H40 ' The PCAN message represents an error frame
Public Const PCAN_MESSAGE_STATUS = &H80 ' The PCAN message represents a PCAN status message
' LookUp Parameters
'
Public Const LOOKUP_DEVICE_TYPE As String = "devicetype" ' Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
Public Const LOOKUP_DEVICE_ID As String = "deviceid" ' Lookup channel by device id
Public Const LOOKUP_CONTROLLER_NUMBER As String = "controllernumber" ' Lookup channel by CAN controller 0-based index
Public Const LOOKUP_IP_ADDRESS As String = "ipaddress" ' Lookup channel by IP address (LAN channels only)
' Frame Type / Initialization Mode
'
Public Const PCAN_MODE_STANDARD = PCAN_MESSAGE_STANDARD
Public Const PCAN_MODE_EXTENDED = PCAN_MESSAGE_EXTENDED
' Baud rate codes = BTR0/BTR1 register values for the CAN controller.
' You can define your own Baud rate with the BTROBTR1 register.
' Take a look at www.peak-system.com for our free software "BAUDTOOL"
' to calculate the BTROBTR1 register for every bit rate and sample point.
'
Public Const PCAN_BAUD_1M = &H14 ' 1 MBit/s
Public Const PCAN_BAUD_800K = &H16 ' 800 kBit/s
Public Const PCAN_BAUD_500K = &H1C ' 500 kBit/s
Public Const PCAN_BAUD_250K = &H11C ' 250 kBit/s
Public Const PCAN_BAUD_125K = &H31C ' 125 kBit/s
Public Const PCAN_BAUD_100K = &H432F ' 100 kBit/s
Public Const PCAN_BAUD_95K = &HC34E ' 95,238 kBit/s
Public Const PCAN_BAUD_83K = &H852B ' 83,333 kBit/s
Public Const PCAN_BAUD_50K = &H472F ' 50 kBit/s
Public Const PCAN_BAUD_47K = &H1414 ' 47,619 kBit/s
Public Const PCAN_BAUD_33K = &H8B2F ' 33,333 kBit/s
Public Const PCAN_BAUD_20K = &H532F ' 20 kBit/s
Public Const PCAN_BAUD_10K = &H672F ' 10 kBit/s
Public Const PCAN_BAUD_5K = &H7F7F ' 5 kBit/s
' Represents the configuration for a CAN bit rate
' Note:
' * Each parameter and its value must be separated with a '='.
' * Each pair of parameter/value must be separated using ','.
'
' Example:
' f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
'
Public Const PCAN_BR_CLOCK As String = "f_clock"
Public Const PCAN_BR_CLOCK_MHZ As String = "f_clock_mhz"
Public Const PCAN_BR_NOM_BRP As String = "nom_brp"
Public Const PCAN_BR_NOM_TSEG1 As String = "nom_tseg1"
Public Const PCAN_BR_NOM_TSEG2 As String = "nom_tseg2"
Public Const PCAN_BR_NOM_SJW As String = "nom_sjw"
Public Const PCAN_BR_NOM_SAMPLE As String = "nom_sam"
Public Const PCAN_BR_DATA_BRP As String = "data_brp"
Public Const PCAN_BR_DATA_TSEG1 As String = "data_tseg1"
Public Const PCAN_BR_DATA_TSEG2 As String = "data_tseg2"
Public Const PCAN_BR_DATA_SJW As String = "data_sjw"
Public Const PCAN_BR_DATA_SAMPLE As String = "data_ssp_offset"
' Type of PCAN (Non-PnP) hardware
'
Public Const PCAN_TYPE_ISA = &H1 ' PCAN-ISA 82C200
Public Const PCAN_TYPE_ISA_SJA = &H9 ' PCAN-ISA SJA1000
Public Const PCAN_TYPE_ISA_PHYTEC = &H4 ' PHYTEC ISA
Public Const PCAN_TYPE_DNG = &H2 ' PCAN-Dongle 82C200
Public Const PCAN_TYPE_DNG_EPP = &H3 ' PCAN-Dongle EPP 82C200
Public Const PCAN_TYPE_DNG_SJA = &H5 ' PCAN-Dongle SJA1000
Public Const PCAN_TYPE_DNG_SJA_EPP = &H6 ' PCAN-Dongle EPP SJA1000
' Represents a PCAN message
'
Public Type TPCANMsg
ID As Long ' 11/29-bit message identifier
MsgType As Byte ' Type of the message
LEN As Byte ' Data Length Code of the message (0..8)
DATA(7) As Byte ' Data of the message (DATA[0]..DATA[7])
End Type
' Represents a timestamp of a received PCAN message
' Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
'
Public Type TPCANTimestamp
millis As Long ' base-value: milliseconds: 0.. 2^32-1
millis_overflow As Integer ' roll-arounds of millis
micros As Integer ' microseconds: 0..999
End Type
' Represents a PCAN message from a FD capable hardware
'
Public Type TPCANMsgFD
ID As Long ' 11/29-bit message identifier
MsgType As Byte ' Type of the message
DLC As Byte ' Data Length Code of the message (0..15)
DATA(63) As Byte ' Data of the message (DATA[0]..DATA[63])
End Type
' Describes an available PCAN channel
'
Public Type TPCANChannelInformation
channel_handle As Integer ' PCAN channel handle
device_type As Byte ' Kind Of PCAN device
controller_number As Byte ' CAN-Controller number
device_features As Long ' Device capabilities flag (see FEATURE_*)
device_name(MAX_LENGTH_HARDWARE_NAME) As Byte ' Device name
device_id As Long ' Device number
channel_condition As Long ' Availability status of a PCAN-Channel
End Type
''' <summary>
''' Initializes a PCAN Channel
''' </summary>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <param name="Btr0Btr1">"The speed for the communication (BTR0BTR1 code)"</param>
''' <param name="HwType">"Non-PnP: The type of hardware and operation mode"</param>
''' <param name="IOPort">"Non-PnP: The I/O address for the parallel port"</param>
''' <param name="Interrupt">"Non-PnP: Interrupt number of the parallel port"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_Initialize Lib "PCANBasic.DLL" _
(ByVal channel As Integer, _
ByVal Btr0Btr1 As Integer, _
Optional ByVal HwType As Byte = 0, _
Optional ByVal IOPort As Long = 0, _
Optional ByVal Interrupt As Integer = 0) As Long
''' <summary>
''' Initializes a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">"The handle of a FD capable PCAN Channel"</param>
''' <param name="BitrateFD">"The speed for the communication (FD bit rate string)"</param>
''' <remarks>See PCAN_BR_* values
''' * parameter and values ust be separated by '='
''' * Couples of Parameter/value must be separated by ','
''' * Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
''' nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
''' * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam
'''</remarks>
''' <example>f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1</example>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_InitializeFD Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByVal BitrateFD As String) As Long
''' <summary>
''' Uninitializes one or all PCAN Channels initialized by CAN_Initialize
''' </summary>
''' <remarks>Giving the TPCANHandle value "PCAN_NONEBUS",
''' uninitialize all initialized channels</remarks>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_Uninitialize Lib "PCANBasic.DLL" _
(ByVal Channel As Integer) As Long
''' <summary>
''' Resets the receive and transmit queues of the PCAN Channel
''' </summary>
''' <remarks>
''' A reset of the CAN controller is not performed.
''' </remarks>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_Reset Lib "PCANBasic.DLL" _
(ByVal Channel As Integer) As Long
''' <summary>
''' Gets the current status of a PCAN Channel
''' </summary>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_GetStatus Lib "PCANBasic.DLL" _
(ByVal Channel As Integer) As Long
''' <summary>
''' Reads a CAN message from the receive queue of a PCAN Channel
''' </summary>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <param name="MessageBuffer">"A TPCANMsg structure buffer to store the CAN message"</param>
''' <param name="TimestampBuffer">"A TPCANTimestamp structure buffer to get
''' the reception time of the message. If this value is not desired, this parameter
''' should be passed as NULL"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_Read Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByRef MessageBuffer As TPCANMsg, _
ByRef TimestampBuffer As TPCANTimestamp) As Long
''' <summary>
''' Reads a CAN message from the receive queue of a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">"The handle of a FD capable PCAN Channel"</param>
''' <param name="MessageBuffer">"A TPCANMsgFD structure buffer to store the CAN message"</param>
''' <param name="TimestampBuffer">"A TPCANTimestampFD buffer to get
''' the reception time of the message. If this value is not desired, this parameter
''' should be passed as NULL"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_ReadFD Lib "PCANBasic.DLL" _
(ByVal Channel As Integer,
ByRef MessageBuffer As TPCANMsgFD,
ByRef TimestampBuffer As Long) As Long
''' <summary>
''' Transmits a CAN message over a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">"The handle of a FD capable PCAN Channel"</param>
''' <param name="MessageBuffer">"A TPCANMsgFD buffer with the message to be sent"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_WriteFD Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByRef MessageBuffer As TPCANMsgFD) As Long
''' <summary>
''' Transmits a CAN message
''' </summary>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <param name="MessageBuffer">"A TPCANMsg buffer with the message to be sent"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_Write Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByRef MessageBuffer As TPCANMsg) As Long
''' <summary>
''' Configures the reception filter.
''' </summary>
''' <remarks>The message filter will be expanded with every call to
''' this function. If it is desired to reset the filter, please use
''' the CAN_SetValue function</remarks>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <param name="FromID">"The lowest CAN ID to be received"</param>
''' <param name="ToID">"The highest CAN ID to be received"</param>
''' <param name="Mode">"Message type, Standard (11-bit identifier) or
''' Extended (29-bit identifier)"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_FilterMessages Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByVal FromID As Long, _
ByVal ToID As Long, _
ByVal Mode As Byte) As Long
''' <summary>
''' Retrieves a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <param name="Parameter">"The TPCANParameter parameter to get"</param>
''' <param name="Buffer">"Buffer for the parameter value"</param>
''' <param name="BufferLength">"Size in bytes of the buffer"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_GetValue Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByVal Parameter As Byte, _
ByRef Buffer As Any, _
ByVal BufferLength As Long) As Long
''' <summary>
''' Configures or sets a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">"The handle of a PCAN Channel"</param>
''' <param name="Parameter">"The TPCANParameter parameter to set"</param>
''' <param name="Buffer">"Buffer with the value to be set"</param>
''' <param name="BufferLength">"Size in bytes of the buffer"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_SetValue Lib "PCANBasic.DLL" _
(ByVal Channel As Integer, _
ByVal Parameter As Byte, _
ByRef Buffer As Any, _
ByVal BufferLength As Long) As Long
''' <summary>
''' Returns a descriptive text of a given TPCANStatus error
''' code, in any desired language
''' </summary>
''' <remarks>The current languages available for translation are:
''' Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
''' Italian (0x10) and French (0x0C)</remarks>
''' <param name="Error">"A TPCANStatus error code"</param>
''' <param name="Language">"Indicates a 'Primary language ID'"</param>
''' <param name="Buffer">"Buffer for a null terminated char array"</param>
''' <returns>"A TPCANStatus error code"</returns>
Public Declare Function CAN_GetErrorText Lib "PCANBasic.DLL" _
(ByVal ErrorCode As Long,
ByVal Language As Integer,
ByVal Buffer As String) As Long
''' <summary>
''' Finds a PCAN-Basic channel that matches with the given parameters
''' </summary>
''' <param name="Parameters">A comma separated string contained pairs of
''' parameter-name/value to be matched within a PCAN-Basic channel</param>
''' <param name="FoundChannel">Buffer for returning the PCAN-Basic channel,
''' when found</param>
''' <returns>A TPCANStatus error code</returns>
Public Declare Function CAN_LookUpChannel Lib "PCANBasic.DLL" _
(ByVal Parameters As String,
ByRef FoundChannel As Integer) As Long
\ No newline at end of file
// PCANBasic.cs
//
// ~~~~~~~~~~~~
//
// PCAN-Basic API
//
// ~~~~~~~~~~~~
//
// ------------------------------------------------------------------
// Author : Keneth Wagner
// Last change: 2022-07-06
//
// Language: C# 1.0
// ------------------------------------------------------------------
//
// Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
// more Info at http://www.peak-system.com
//
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace Peak.Can.Basic
{
using TPCANHandle = System.UInt16;
using TPCANBitrateFD = System.String;
using TPCANTimestampFD = System.UInt64;
#region Enumerations
/// <summary>
/// Represents a PCAN status/error code
/// </summary>
[Flags]
public enum TPCANStatus : uint
{
/// <summary>
/// No error
/// </summary>
PCAN_ERROR_OK = 0x00000,
/// <summary>
/// Transmit buffer in CAN controller is full
/// </summary>
PCAN_ERROR_XMTFULL = 0x00001,
/// <summary>
/// CAN controller was read too late
/// </summary>
PCAN_ERROR_OVERRUN = 0x00002,
/// <summary>
/// Bus error: an error counter reached the 'light' limit
/// </summary>
PCAN_ERROR_BUSLIGHT = 0x00004,
/// <summary>
/// Bus error: an error counter reached the 'heavy' limit
/// </summary>
PCAN_ERROR_BUSHEAVY = 0x00008,
/// <summary>
/// Bus error: an error counter reached the 'warning' limit
/// </summary>
PCAN_ERROR_BUSWARNING = PCAN_ERROR_BUSHEAVY,
/// <summary>
/// Bus error: the CAN controller is error passive
/// </summary>
PCAN_ERROR_BUSPASSIVE = 0x40000,
/// <summary>
/// Bus error: the CAN controller is in bus-off state
/// </summary>
PCAN_ERROR_BUSOFF = 0x00010,
/// <summary>
/// Mask for all bus errors
/// </summary>
PCAN_ERROR_ANYBUSERR = (PCAN_ERROR_BUSWARNING | PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY | PCAN_ERROR_BUSOFF | PCAN_ERROR_BUSPASSIVE),
/// <summary>
/// Receive queue is empty
/// </summary>
PCAN_ERROR_QRCVEMPTY = 0x00020,
/// <summary>
/// Receive queue was read too late
/// </summary>
PCAN_ERROR_QOVERRUN = 0x00040,
/// <summary>
/// Transmit queue is full
/// </summary>
PCAN_ERROR_QXMTFULL = 0x00080,
/// <summary>
/// Test of the CAN controller hardware registers failed (no hardware found)
/// </summary>
PCAN_ERROR_REGTEST = 0x00100,
/// <summary>
/// Driver not loaded
/// </summary>
PCAN_ERROR_NODRIVER = 0x00200,
/// <summary>
/// Hardware already in use by a Net
/// </summary>
PCAN_ERROR_HWINUSE = 0x00400,
/// <summary>
/// A Client is already connected to the Net
/// </summary>
PCAN_ERROR_NETINUSE = 0x00800,
/// <summary>
/// Hardware handle is invalid
/// </summary>
PCAN_ERROR_ILLHW = 0x01400,
/// <summary>
/// Net handle is invalid
/// </summary>
PCAN_ERROR_ILLNET = 0x01800,
/// <summary>
/// Client handle is invalid
/// </summary>
PCAN_ERROR_ILLCLIENT = 0x01C00,
/// <summary>
/// Mask for all handle errors
/// </summary>
PCAN_ERROR_ILLHANDLE = (PCAN_ERROR_ILLHW | PCAN_ERROR_ILLNET | PCAN_ERROR_ILLCLIENT),
/// <summary>
/// Resource (FIFO, Client, timeout) cannot be created
/// </summary>
PCAN_ERROR_RESOURCE = 0x02000,
/// <summary>
/// Invalid parameter
/// </summary>
PCAN_ERROR_ILLPARAMTYPE = 0x04000,
/// <summary>
/// Invalid parameter value
/// </summary>
PCAN_ERROR_ILLPARAMVAL = 0x08000,
/// <summary>
/// Unknown error
/// </summary>
PCAN_ERROR_UNKNOWN = 0x10000,
/// <summary>
/// Invalid data, function, or action.
/// </summary>
PCAN_ERROR_ILLDATA = 0x20000,
/// <summary>
/// Driver object state is wrong for the attempted operation
/// </summary>
PCAN_ERROR_ILLMODE = 0x80000,
/// <summary>
/// An operation was successfully carried out, however, irregularities were registered
/// </summary>
PCAN_ERROR_CAUTION = 0x2000000,
/// <summary>
/// Channel is not initialized
/// <remarks>Value was changed from 0x40000 to 0x4000000</remarks>
/// </summary>
PCAN_ERROR_INITIALIZE = 0x4000000,
/// <summary>
/// Invalid operation
/// <remarks>Value was changed from 0x80000 to 0x8000000</remarks>
/// </summary>
PCAN_ERROR_ILLOPERATION = 0x8000000,
}
/// <summary>
/// Represents a PCAN device
/// </summary>
public enum TPCANDevice : byte
{
/// <summary>
/// Undefined, unknown or not selected PCAN device value
/// </summary>
PCAN_NONE = 0,
/// <summary>
/// PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
/// </summary>
PCAN_PEAKCAN = 1,
/// <summary>
/// PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
/// </summary>
PCAN_ISA = 2,
/// <summary>
/// PCAN-Dongle
/// </summary>
PCAN_DNG = 3,
/// <summary>
/// PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
/// </summary>
PCAN_PCI = 4,
/// <summary>
/// PCAN-USB and PCAN-USB Pro
/// </summary>
PCAN_USB = 5,
/// <summary>
/// PCAN-PC Card
/// </summary>
PCAN_PCC = 6,
/// <summary>
/// PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
/// </summary>
PCAN_VIRTUAL = 7,
/// <summary>
/// PCAN Gateway devices
/// </summary>
PCAN_LAN = 8
}
/// <summary>
/// Represents a PCAN parameter to be read or set
/// </summary>
public enum TPCANParameter : byte
{
/// <summary>
/// Device identifier parameter
/// </summary>
PCAN_DEVICE_ID = 1,
/// <summary>
/// DEPRECATED parameter. Use PCAN_DEVICE_ID instead
/// </summary>
[Obsolete]
PCAN_DEVICE_NUMBER = PCAN_DEVICE_ID,
/// <summary>
/// 5-Volt power parameter
/// </summary>
PCAN_5VOLTS_POWER = 2,
/// <summary>
/// PCAN receive event handler parameter
/// </summary>
PCAN_RECEIVE_EVENT = 3,
/// <summary>
/// PCAN message filter parameter
/// </summary>
PCAN_MESSAGE_FILTER = 4,
/// <summary>
/// PCAN-Basic API version parameter
/// </summary>
PCAN_API_VERSION = 5,
/// <summary>
/// PCAN device channel version parameter
/// </summary>
PCAN_CHANNEL_VERSION = 6,
/// <summary>
/// PCAN Reset-On-Busoff parameter
/// </summary>
PCAN_BUSOFF_AUTORESET = 7,
/// <summary>
/// PCAN Listen-Only parameter
/// </summary>
PCAN_LISTEN_ONLY = 8,
/// <summary>
/// Directory path for log files
/// </summary>
PCAN_LOG_LOCATION = 9,
/// <summary>
/// Debug-Log activation status
/// </summary>
PCAN_LOG_STATUS = 10,
/// <summary>
/// Configuration of the debugged information (LOG_FUNCTION_***)
/// </summary>
PCAN_LOG_CONFIGURE = 11,
/// <summary>
/// Custom insertion of text into the log file
/// </summary>
PCAN_LOG_TEXT = 12,
/// <summary>
/// Availability status of a PCAN-Channel
/// </summary>
PCAN_CHANNEL_CONDITION = 13,
/// <summary>
/// PCAN hardware name parameter
/// </summary>
PCAN_HARDWARE_NAME = 14,
/// <summary>
/// Message reception status of a PCAN-Channel
/// </summary>
PCAN_RECEIVE_STATUS = 15,
/// <summary>
/// CAN-Controller number of a PCAN-Channel
/// </summary>
PCAN_CONTROLLER_NUMBER = 16,
/// <summary>
/// Directory path for PCAN trace files
/// </summary>
PCAN_TRACE_LOCATION = 17,
/// <summary>
/// CAN tracing activation status
/// </summary>
PCAN_TRACE_STATUS = 18,
/// <summary>
/// Configuration of the maximum file size of a CAN trace
/// </summary>
PCAN_TRACE_SIZE = 19,
/// <summary>
/// Configuration of the trace file storing mode (TRACE_FILE_***)
/// </summary>
PCAN_TRACE_CONFIGURE = 20,
/// <summary>
/// Physical identification of a USB based PCAN-Channel by blinking its associated LED
/// </summary>
PCAN_CHANNEL_IDENTIFYING = 21,
/// <summary>
/// Capabilities of a PCAN device (FEATURE_***)
/// </summary>
PCAN_CHANNEL_FEATURES = 22,
/// <summary>
/// Using of an existing bit rate (PCAN-View connected to a channel)
/// </summary>
PCAN_BITRATE_ADAPTING = 23,
/// <summary>
/// Configured bit rate as Btr0Btr1 value
/// </summary>
PCAN_BITRATE_INFO = 24,
/// <summary>
/// Configured bit rate as TPCANBitrateFD string
/// </summary>
PCAN_BITRATE_INFO_FD = 25,
/// <summary>
/// Configured nominal CAN Bus speed as Bits per seconds
/// </summary>
PCAN_BUSSPEED_NOMINAL = 26,
/// <summary>
/// Configured CAN data speed as Bits per seconds
/// </summary>
PCAN_BUSSPEED_DATA = 27,
/// <summary>
/// Remote address of a LAN channel as string in IPv4 format
/// </summary>
PCAN_IP_ADDRESS = 28,
/// <summary>
/// Status of the Virtual PCAN-Gateway Service
/// </summary>
PCAN_LAN_SERVICE_STATUS = 29,
/// <summary>
/// Status messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_STATUS_FRAMES = 30,
/// <summary>
/// RTR messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_RTR_FRAMES = 31,
/// <summary>
/// Error messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_ERROR_FRAMES = 32,
/// <summary>
/// Delay, in microseconds, between sending frames
/// </summary>
PCAN_INTERFRAME_DELAY = 33,
/// <summary>
/// Filter over code and mask patterns for 11-Bit messages
/// </summary>
PCAN_ACCEPTANCE_FILTER_11BIT = 34,
/// <summary>
/// Filter over code and mask patterns for 29-Bit messages
/// </summary>
PCAN_ACCEPTANCE_FILTER_29BIT = 35,
/// <summary>
/// Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
/// </summary>
PCAN_IO_DIGITAL_CONFIGURATION = 36,
/// <summary>
/// Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
/// </summary>
PCAN_IO_DIGITAL_VALUE = 37,
/// <summary>
/// Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
/// </summary>
PCAN_IO_DIGITAL_SET = 38,
/// <summary>
/// Clear multiple digital I/O pins to 0
/// </summary>
PCAN_IO_DIGITAL_CLEAR = 39,
/// <summary>
/// Get value of a single analog input pin
/// </summary>
PCAN_IO_ANALOG_VALUE = 40,
/// <summary>
/// Get the version of the firmware used by the device associated with a PCAN-Channel
/// </summary>
PCAN_FIRMWARE_VERSION = 41,
/// <summary>
/// Get the amount of PCAN channels attached to a system
/// </summary>
PCAN_ATTACHED_CHANNELS_COUNT = 42,
/// <summary>
/// Get information about PCAN channels attached to a system
/// </summary>
PCAN_ATTACHED_CHANNELS = 43,
/// <summary>
/// Echo messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_ECHO_FRAMES = 44,
/// <summary>
/// Get the part number associated to a device
/// </summary>
PCAN_DEVICE_PART_NUMBER = 45,
}
/// <summary>
/// Represents the type of a PCAN message
/// </summary>
[Flags]
public enum TPCANMessageType : byte
{
/// <summary>
/// The PCAN message is a CAN Standard Frame (11-bit identifier)
/// </summary>
PCAN_MESSAGE_STANDARD = 0x00,
/// <summary>
/// The PCAN message is a CAN Remote-Transfer-Request Frame
/// </summary>
PCAN_MESSAGE_RTR = 0x01,
/// <summary>
/// The PCAN message is a CAN Extended Frame (29-bit identifier)
/// </summary>
PCAN_MESSAGE_EXTENDED = 0x02,
/// <summary>
/// The PCAN message represents a FD frame in terms of CiA Specs
/// </summary>
PCAN_MESSAGE_FD = 0x04,
/// <summary>
/// The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
/// </summary>
PCAN_MESSAGE_BRS = 0x08,
/// <summary>
/// The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
/// </summary>
PCAN_MESSAGE_ESI = 0x10,
/// <summary>
/// The PCAN message represents an echo CAN Frame
/// </summary>
PCAN_MESSAGE_ECHO = 0x20,
/// <summary>
/// The PCAN message represents an error frame
/// </summary>
PCAN_MESSAGE_ERRFRAME = 0x40,
/// <summary>
/// The PCAN message represents a PCAN status message
/// </summary>
PCAN_MESSAGE_STATUS = 0x80,
}
/// <summary>
/// Represents a PCAN filter mode
/// </summary>
public enum TPCANMode : byte
{
/// <summary>
/// Mode is Standard (11-bit identifier)
/// </summary>
PCAN_MODE_STANDARD = TPCANMessageType.PCAN_MESSAGE_STANDARD,
/// <summary>
/// Mode is Extended (29-bit identifier)
/// </summary>
PCAN_MODE_EXTENDED = TPCANMessageType.PCAN_MESSAGE_EXTENDED,
}
/// <summary>
/// Represents a PCAN Baud rate register value
/// </summary>
public enum TPCANBaudrate : ushort
{
/// <summary>
/// 1 MBit/s
/// </summary>
PCAN_BAUD_1M = 0x0014,
/// <summary>
/// 800 KBit/s
/// </summary>
PCAN_BAUD_800K = 0x0016,
/// <summary>
/// 500 kBit/s
/// </summary>
PCAN_BAUD_500K = 0x001C,
/// <summary>
/// 250 kBit/s
/// </summary>
PCAN_BAUD_250K = 0x011C,
/// <summary>
/// 125 kBit/s
/// </summary>
PCAN_BAUD_125K = 0x031C,
/// <summary>
/// 100 kBit/s
/// </summary>
PCAN_BAUD_100K = 0x432F,
/// <summary>
/// 95,238 KBit/s
/// </summary>
PCAN_BAUD_95K = 0xC34E,
/// <summary>
/// 83,333 KBit/s
/// </summary>
PCAN_BAUD_83K = 0x852B,
/// <summary>
/// 50 kBit/s
/// </summary>
PCAN_BAUD_50K = 0x472F,
/// <summary>
/// 47,619 KBit/s
/// </summary>
PCAN_BAUD_47K = 0x1414,
/// <summary>
/// 33,333 KBit/s
/// </summary>
PCAN_BAUD_33K = 0x8B2F,
/// <summary>
/// 20 kBit/s
/// </summary>
PCAN_BAUD_20K = 0x532F,
/// <summary>
/// 10 kBit/s
/// </summary>
PCAN_BAUD_10K = 0x672F,
/// <summary>
/// 5 kBit/s
/// </summary>
PCAN_BAUD_5K = 0x7F7F,
}
/// <summary>
/// Represents the type of PCAN (Non-PnP) hardware to be initialized
/// </summary>
public enum TPCANType : byte
{
/// <summary>
/// PCAN-ISA 82C200
/// </summary>
PCAN_TYPE_ISA = 0x01,
/// <summary>
/// PCAN-ISA SJA1000
/// </summary>
PCAN_TYPE_ISA_SJA = 0x09,
/// <summary>
/// PHYTEC ISA
/// </summary>
PCAN_TYPE_ISA_PHYTEC = 0x04,
/// <summary>
/// PCAN-Dongle 82C200
/// </summary>
PCAN_TYPE_DNG = 0x02,
/// <summary>
/// PCAN-Dongle EPP 82C200
/// </summary>
PCAN_TYPE_DNG_EPP = 0x03,
/// <summary>
/// PCAN-Dongle SJA1000
/// </summary>
PCAN_TYPE_DNG_SJA = 0x05,
/// <summary>
/// PCAN-Dongle EPP SJA1000
/// </summary>
PCAN_TYPE_DNG_SJA_EPP = 0x06,
}
#endregion
#region Structures
/// <summary>
/// Represents a PCAN message
/// </summary>
public struct TPCANMsg
{
/// <summary>
/// 11/29-bit message identifier
/// </summary>
public uint ID;
/// <summary>
/// Type of the message
/// </summary>
[MarshalAs(UnmanagedType.U1)]
public TPCANMessageType MSGTYPE;
/// <summary>
/// Data Length Code of the message (0..8)
/// </summary>
public byte LEN;
/// <summary>
/// Data of the message (DATA[0]..DATA[7])
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] DATA;
}
/// <summary>
/// Represents a timestamp of a received PCAN message.
/// Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
/// </summary>
public struct TPCANTimestamp
{
/// <summary>
/// Base-value: milliseconds: 0.. 2^32-1
/// </summary>
public uint millis;
/// <summary>
/// Roll-arounds of millis
/// </summary>
public ushort millis_overflow;
/// <summary>
/// Microseconds: 0..999
/// </summary>
public ushort micros;
}
/// <summary>
/// Represents a PCAN message from a FD capable hardware
/// </summary>
public struct TPCANMsgFD
{
/// <summary>
/// 11/29-bit message identifier
/// </summary>
public uint ID;
/// <summary>
/// Type of the message
/// </summary>
[MarshalAs(UnmanagedType.U1)]
public TPCANMessageType MSGTYPE;
/// <summary>
/// Data Length Code of the message (0..15)
/// </summary>
public byte DLC;
/// <summary>
/// Data of the message (DATA[0]..DATA[63])
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] DATA;
}
/// <summary>
/// Describes an available PCAN channel
/// </summary>
public struct TPCANChannelInformation
{
/// <summary>
/// PCAN channel handle
/// </summary>
[MarshalAs(UnmanagedType.U2)]
public TPCANHandle channel_handle;
/// <summary>
/// Kind of PCAN device
/// </summary>
[MarshalAs(UnmanagedType.U1)]
public TPCANDevice device_type;
/// <summary>
/// CAN-Controller number
/// </summary>
public byte controller_number;
/// <summary>
/// Device capabilities flag (see FEATURE_*)
/// </summary>
public uint device_features;
/// <summary>
/// Device name
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = PCANBasic.MAX_LENGTH_HARDWARE_NAME)]
public string device_name;
/// <summary>
/// Device number
/// </summary>
public uint device_id;
/// <summary>
/// Availability status of a PCAN-Channel
/// </summary>
public uint channel_condition;
}
#endregion
#region PCANBasic class
/// <summary>
/// PCAN-Basic API class implementation
/// </summary>
public static class PCANBasic
{
#region PCAN-BUS Handles Definition
/// <summary>
/// Undefined/default value for a PCAN bus
/// </summary>
public const TPCANHandle PCAN_NONEBUS = 0x00;
/// <summary>
/// PCAN-ISA interface, channel 1
/// </summary>
public const TPCANHandle PCAN_ISABUS1 = 0x21;
/// <summary>
/// PCAN-ISA interface, channel 2
/// </summary>
public const TPCANHandle PCAN_ISABUS2 = 0x22;
/// <summary>
/// PCAN-ISA interface, channel 3
/// </summary>
public const TPCANHandle PCAN_ISABUS3 = 0x23;
/// <summary>
/// PCAN-ISA interface, channel 4
/// </summary>
public const TPCANHandle PCAN_ISABUS4 = 0x24;
/// <summary>
/// PCAN-ISA interface, channel 5
/// </summary>
public const TPCANHandle PCAN_ISABUS5 = 0x25;
/// <summary>
/// PCAN-ISA interface, channel 6
/// </summary>
public const TPCANHandle PCAN_ISABUS6 = 0x26;
/// <summary>
/// PCAN-ISA interface, channel 7
/// </summary>
public const TPCANHandle PCAN_ISABUS7 = 0x27;
/// <summary>
/// PCAN-ISA interface, channel 8
/// </summary>
public const TPCANHandle PCAN_ISABUS8 = 0x28;
/// <summary>
/// PPCAN-Dongle/LPT interface, channel 1
/// </summary>
public const TPCANHandle PCAN_DNGBUS1 = 0x31;
/// <summary>
/// PCAN-PCI interface, channel 1
/// </summary>
public const TPCANHandle PCAN_PCIBUS1 = 0x41;
/// <summary>
/// PCAN-PCI interface, channel 2
/// </summary>
public const TPCANHandle PCAN_PCIBUS2 = 0x42;
/// <summary>
/// PCAN-PCI interface, channel 3
/// </summary>
public const TPCANHandle PCAN_PCIBUS3 = 0x43;
/// <summary>
/// PCAN-PCI interface, channel 4
/// </summary>
public const TPCANHandle PCAN_PCIBUS4 = 0x44;
/// <summary>
/// PCAN-PCI interface, channel 5
/// </summary>
public const TPCANHandle PCAN_PCIBUS5 = 0x45;
/// <summary>
/// PCAN-PCI interface, channel 6
/// </summary>
public const TPCANHandle PCAN_PCIBUS6 = 0x46;
/// <summary>
/// PCAN-PCI interface, channel 7
/// </summary>
public const TPCANHandle PCAN_PCIBUS7 = 0x47;
/// <summary>
/// PCAN-PCI interface, channel 8
/// </summary>
public const TPCANHandle PCAN_PCIBUS8 = 0x48;
/// <summary>
/// PCAN-PCI interface, channel 9
/// </summary>
public const TPCANHandle PCAN_PCIBUS9 = 0x409;
/// <summary>
/// PCAN-PCI interface, channel 10
/// </summary>
public const TPCANHandle PCAN_PCIBUS10 = 0x40A;
/// <summary>
/// PCAN-PCI interface, channel 11
/// </summary>
public const TPCANHandle PCAN_PCIBUS11 = 0x40B;
/// <summary>
/// PCAN-PCI interface, channel 12
/// </summary>
public const TPCANHandle PCAN_PCIBUS12 = 0x40C;
/// <summary>
/// PCAN-PCI interface, channel 13
/// </summary>
public const TPCANHandle PCAN_PCIBUS13 = 0x40D;
/// <summary>
/// PCAN-PCI interface, channel 14
/// </summary>
public const TPCANHandle PCAN_PCIBUS14 = 0x40E;
/// <summary>
/// PCAN-PCI interface, channel 15
/// </summary>
public const TPCANHandle PCAN_PCIBUS15 = 0x40F;
/// <summary>
/// PCAN-PCI interface, channel 16
/// </summary>
public const TPCANHandle PCAN_PCIBUS16 = 0x410;
/// <summary>
/// PCAN-USB interface, channel 1
/// </summary>
public const TPCANHandle PCAN_USBBUS1 = 0x51;
/// <summary>
/// PCAN-USB interface, channel 2
/// </summary>
public const TPCANHandle PCAN_USBBUS2 = 0x52;
/// <summary>
/// PCAN-USB interface, channel 3
/// </summary>
public const TPCANHandle PCAN_USBBUS3 = 0x53;
/// <summary>
/// PCAN-USB interface, channel 4
/// </summary>
public const TPCANHandle PCAN_USBBUS4 = 0x54;
/// <summary>
/// PCAN-USB interface, channel 5
/// </summary>
public const TPCANHandle PCAN_USBBUS5 = 0x55;
/// <summary>
/// PCAN-USB interface, channel 6
/// </summary>
public const TPCANHandle PCAN_USBBUS6 = 0x56;
/// <summary>
/// PCAN-USB interface, channel 7
/// </summary>
public const TPCANHandle PCAN_USBBUS7 = 0x57;
/// <summary>
/// PCAN-USB interface, channel 8
/// </summary>
public const TPCANHandle PCAN_USBBUS8 = 0x58;
/// <summary>
/// PCAN-USB interface, channel 9
/// </summary>
public const TPCANHandle PCAN_USBBUS9 = 0x509;
/// <summary>
/// PCAN-USB interface, channel 10
/// </summary>
public const TPCANHandle PCAN_USBBUS10 = 0x50A;
/// <summary>
/// PCAN-USB interface, channel 11
/// </summary>
public const TPCANHandle PCAN_USBBUS11 = 0x50B;
/// <summary>
/// PCAN-USB interface, channel 12
/// </summary>
public const TPCANHandle PCAN_USBBUS12 = 0x50C;
/// <summary>
/// PCAN-USB interface, channel 13
/// </summary>
public const TPCANHandle PCAN_USBBUS13 = 0x50D;
/// <summary>
/// PCAN-USB interface, channel 14
/// </summary>
public const TPCANHandle PCAN_USBBUS14 = 0x50E;
/// <summary>
/// PCAN-USB interface, channel 15
/// </summary>
public const TPCANHandle PCAN_USBBUS15 = 0x50F;
/// <summary>
/// PCAN-USB interface, channel 16
/// </summary>
public const TPCANHandle PCAN_USBBUS16 = 0x510;
/// <summary>
/// PCAN-PC Card interface, channel 1
/// </summary>
public const TPCANHandle PCAN_PCCBUS1 = 0x61;
/// <summary>
/// PCAN-PC Card interface, channel 2
/// </summary>
public const TPCANHandle PCAN_PCCBUS2 = 0x62;
/// <summary>
/// PCAN-LAN interface, channel 1
/// </summary>
public const TPCANHandle PCAN_LANBUS1 = 0x801;
/// <summary>
/// PCAN-LAN interface, channel 2
/// </summary>
public const TPCANHandle PCAN_LANBUS2 = 0x802;
/// <summary>
/// PCAN-LAN interface, channel 3
/// </summary>
public const TPCANHandle PCAN_LANBUS3 = 0x803;
/// <summary>
/// PCAN-LAN interface, channel 4
/// </summary>
public const TPCANHandle PCAN_LANBUS4 = 0x804;
/// <summary>
/// PCAN-LAN interface, channel 5
/// </summary>
public const TPCANHandle PCAN_LANBUS5 = 0x805;
/// <summary>
/// PCAN-LAN interface, channel 6
/// </summary>
public const TPCANHandle PCAN_LANBUS6 = 0x806;
/// <summary>
/// PCAN-LAN interface, channel 7
/// </summary>
public const TPCANHandle PCAN_LANBUS7 = 0x807;
/// <summary>
/// PCAN-LAN interface, channel 8
/// </summary>
public const TPCANHandle PCAN_LANBUS8 = 0x808;
/// <summary>
/// PCAN-LAN interface, channel 9
/// </summary>
public const TPCANHandle PCAN_LANBUS9 = 0x809;
/// <summary>
/// PCAN-LAN interface, channel 10
/// </summary>
public const TPCANHandle PCAN_LANBUS10 = 0x80A;
/// <summary>
/// PCAN-LAN interface, channel 11
/// </summary>
public const TPCANHandle PCAN_LANBUS11 = 0x80B;
/// <summary>
/// PCAN-LAN interface, channel 12
/// </summary>
public const TPCANHandle PCAN_LANBUS12 = 0x80C;
/// <summary>
/// PCAN-LAN interface, channel 13
/// </summary>
public const TPCANHandle PCAN_LANBUS13 = 0x80D;
/// <summary>
/// PCAN-LAN interface, channel 14
/// </summary>
public const TPCANHandle PCAN_LANBUS14 = 0x80E;
/// <summary>
/// PCAN-LAN interface, channel 15
/// </summary>
public const TPCANHandle PCAN_LANBUS15 = 0x80F;
/// <summary>
/// PCAN-LAN interface, channel 16
/// </summary>
public const TPCANHandle PCAN_LANBUS16 = 0x810;
#endregion
#region FD Bit rate parameters
/// <summary>
/// Clock frequency in Herz (80000000, 60000000, 40000000, 30000000, 24000000, 20000000)
/// </summary>
public const string PCAN_BR_CLOCK = "f_clock";
/// <summary>
/// Clock frequency in Megaherz (80, 60, 40, 30, 24, 20)
/// </summary>
public const string PCAN_BR_CLOCK_MHZ = "f_clock_mhz";
/// <summary>
/// Clock prescaler for nominal time quantum
/// </summary>
public const string PCAN_BR_NOM_BRP = "nom_brp";
/// <summary>
/// TSEG1 segment for nominal bit rate in time quanta
/// </summary>
public const string PCAN_BR_NOM_TSEG1 = "nom_tseg1";
/// <summary>
/// TSEG2 segment for nominal bit rate in time quanta
/// </summary>
public const string PCAN_BR_NOM_TSEG2 = "nom_tseg2";
/// <summary>
/// Synchronization Jump Width for nominal bit rate in time quanta
/// </summary>
public const string PCAN_BR_NOM_SJW = "nom_sjw";
/// <summary>
/// Sample point for nominal bit rate
/// </summary>
public const string PCAN_BR_NOM_SAMPLE = "nom_sam";
/// <summary>
/// Clock prescaler for highspeed data time quantum
/// </summary>
public const string PCAN_BR_DATA_BRP = "data_brp";
/// <summary>
/// TSEG1 segment for fast data bit rate in time quanta
/// </summary>
public const string PCAN_BR_DATA_TSEG1 = "data_tseg1";
/// <summary>
/// TSEG2 segment for fast data bit rate in time quanta
/// </summary>
public const string PCAN_BR_DATA_TSEG2 = "data_tseg2";
/// <summary>
/// Synchronization Jump Width for highspeed data bit rate in time quanta
/// </summary>
public const string PCAN_BR_DATA_SJW = "data_sjw";
/// <summary>
/// Secondary sample point delay for highspeed data bit rate in cyles
/// </summary>
public const string PCAN_BR_DATA_SAMPLE = "data_ssp_offset";
#endregion
#region Parameter values definition
/// <summary>
/// The PCAN parameter is not set (inactive)
/// </summary>
public const int PCAN_PARAMETER_OFF = 0;
/// <summary>
/// The PCAN parameter is set (active)
/// </summary>
public const int PCAN_PARAMETER_ON = 1;
/// <summary>
/// The PCAN filter is closed. No messages will be received
/// </summary>
public const int PCAN_FILTER_CLOSE = 0;
/// <summary>
/// The PCAN filter is fully opened. All messages will be received
/// </summary>
public const int PCAN_FILTER_OPEN = 1;
/// <summary>
/// The PCAN filter is custom configured. Only registered
/// messages will be received
/// </summary>
public const int PCAN_FILTER_CUSTOM = 2;
/// <summary>
/// The PCAN-Channel handle is illegal, or its associated hardware is not available
/// </summary>
public const int PCAN_CHANNEL_UNAVAILABLE = 0;
/// <summary>
/// The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
/// </summary>
public const int PCAN_CHANNEL_AVAILABLE = 1;
/// <summary>
/// The PCAN-Channel handle is valid, and is already being used
/// </summary>
public const int PCAN_CHANNEL_OCCUPIED = 2;
/// <summary>
/// The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
/// </summary>
public const int PCAN_CHANNEL_PCANVIEW = (PCAN_CHANNEL_AVAILABLE | PCAN_CHANNEL_OCCUPIED);
/// <summary>
/// Logs system exceptions / errors
/// </summary>
public const int LOG_FUNCTION_DEFAULT = 0x00;
/// <summary>
/// Logs the entries to the PCAN-Basic API functions
/// </summary>
public const int LOG_FUNCTION_ENTRY = 0x01;
/// <summary>
/// Logs the parameters passed to the PCAN-Basic API functions
/// </summary>
public const int LOG_FUNCTION_PARAMETERS = 0x02;
/// <summary>
/// Logs the exits from the PCAN-Basic API functions
/// </summary>
public const int LOG_FUNCTION_LEAVE = 0x04;
/// <summary>
/// Logs the CAN messages passed to the CAN_Write function
/// </summary>
public const int LOG_FUNCTION_WRITE = 0x08;
/// <summary>
/// Logs the CAN messages received within the CAN_Read function
/// </summary>
public const int LOG_FUNCTION_READ = 0x10;
/// <summary>
/// Logs all possible information within the PCAN-Basic API functions
/// </summary>
public const int LOG_FUNCTION_ALL = 0xFFFF;
/// <summary>
/// A single file is written until it size reaches PAN_TRACE_SIZE
/// </summary>
public const int TRACE_FILE_SINGLE = 0x00;
/// <summary>
/// Traced data is distributed in several files with size PAN_TRACE_SIZE
/// </summary>
public const int TRACE_FILE_SEGMENTED = 0x01;
/// <summary>
/// Includes the date into the name of the trace file
/// </summary>
public const int TRACE_FILE_DATE = 0x02;
/// <summary>
/// Includes the start time into the name of the trace file
/// </summary>
public const int TRACE_FILE_TIME = 0x04;
/// <summary>
/// Causes the overwriting of available traces (same name)
/// </summary>
public const int TRACE_FILE_OVERWRITE = 0x80;
/// <summary>
/// Device supports flexible data-rate (CAN-FD)
/// </summary>
public const int FEATURE_FD_CAPABLE = 0x01;
/// <summary>
/// Device supports a delay between sending frames (FPGA based USB devices)
/// </summary>
public const int FEATURE_DELAY_CAPABLE = 0x02;
/// <summary>
/// Device supports I/O functionality for electronic circuits (USB-Chip devices)
/// </summary>
public const int FEATURE_IO_CAPABLE = 0x04;
/// <summary>
/// The service is not running
/// </summary>
public const int SERVICE_STATUS_STOPPED = 0x01;
/// <summary>
/// The service is running
/// </summary>
public const int SERVICE_STATUS_RUNNING = 0x04;
#endregion
#region Lookup Parameters
/// <summary>
/// Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
/// </summary>
public const string LOOKUP_DEVICE_TYPE = "devicetype";
/// <summary>
/// Lookup channel by device id
/// </summary>
public const string LOOKUP_DEVICE_ID = "deviceid";
/// <summary>
/// Lookup channel by CAN controller 0-based index
/// </summary>
public const string LOOKUP_CONTROLLER_NUMBER = "controllernumber";
/// <summary>
/// Lookup channel by IP address (LAN channels only)
/// </summary>
public const string LOOKUP_IP_ADDRESS = "ipaddress";
#endregion
#region Other Constants
/// <summary>
/// Maximum length of the name of a device: 32 characters + terminator
/// </summary>
public const int MAX_LENGTH_HARDWARE_NAME = 33;
/// <summary>
/// Maximum length of a version string: 255 characters + terminator
/// </summary>
public const int MAX_LENGTH_VERSION_STRING = 256;
#endregion
#region PCANBasic API Implementation
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
/// <param name="HwType">Non-PnP: The type of hardware and operation mode</param>
/// <param name="IOPort">Non-PnP: The I/O address for the parallel port</param>
/// <param name="Interrupt">Non-PnP: Interrupt number of the parallel por</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Initialize")]
public static extern TPCANStatus Initialize(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U2)]
TPCANBaudrate Btr0Btr1,
[MarshalAs(UnmanagedType.U1)]
TPCANType HwType,
UInt32 IOPort,
UInt16 Interrupt);
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
/// <returns>A TPCANStatus error code</returns>
public static TPCANStatus Initialize(
TPCANHandle Channel,
TPCANBaudrate Btr0Btr1)
{
return Initialize(Channel, Btr0Btr1, (TPCANType)0, 0, 0);
}
/// <summary>
/// Initializes a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="BitrateFD">The speed for the communication (FD bit rate string)</param>
/// <remarks> See PCAN_BR_* values
/// Bit rate string must follow the following construction rules:
/// * parameters and values must be separated by '='
/// * Couples of Parameter/value must be separated by ','
/// * Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
/// nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
/// * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam</remarks>
/// <example>f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1</example>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_InitializeFD")]
public static extern TPCANStatus InitializeFD(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
TPCANBitrateFD BitrateFD);
/// <summary>
/// Uninitializes one or all PCAN Channels initialized by CAN_Initialize
/// </summary>
/// <remarks>Giving the TPCANHandle value "PCAN_NONEBUS",
/// uninitialize all initialized channels</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Uninitialize")]
public static extern TPCANStatus Uninitialize(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel);
/// <summary>
/// Resets the receive and transmit queues of the PCAN Channel
/// </summary>
/// <remarks>A reset of the CAN controller is not performed</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Reset")]
public static extern TPCANStatus Reset(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel);
/// <summary>
/// Gets the current status of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetStatus")]
public static extern TPCANStatus GetStatus(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel);
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestamp structure buffer to get
/// the reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
public static extern TPCANStatus Read(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
out TPCANMsg MessageBuffer,
out TPCANTimestamp TimestampBuffer);
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
private static extern TPCANStatus Read(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
out TPCANMsg MessageBuffer,
IntPtr bufferPointer);
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
/// <returns>A TPCANStatus error code</returns>
public static TPCANStatus Read(
TPCANHandle Channel,
out TPCANMsg MessageBuffer)
{
return Read(Channel, out MessageBuffer, IntPtr.Zero);
}
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestampFD buffer to get the
/// reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_ReadFD")]
public static extern TPCANStatus ReadFD(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
out TPCANMsgFD MessageBuffer,
out TPCANTimestampFD TimestampBuffer);
[DllImport("PCANBasic.dll", EntryPoint = "CAN_ReadFD")]
private static extern TPCANStatus ReadFD(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
out TPCANMsgFD MessageBuffer,
IntPtr TimestampBuffer);
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
/// <returns>A TPCANStatus error code</returns>
public static TPCANStatus ReadFD(
TPCANHandle Channel,
out TPCANMsgFD MessageBuffer)
{
return ReadFD(Channel, out MessageBuffer, IntPtr.Zero);
}
/// <summary>
/// Transmits a CAN message
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg buffer with the message to be sent</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Write")]
public static extern TPCANStatus Write(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
ref TPCANMsg MessageBuffer);
/// <summary>
/// Transmits a CAN message over a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD buffer with the message to be sent</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_WriteFD")]
public static extern TPCANStatus WriteFD(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
ref TPCANMsgFD MessageBuffer);
/// <summary>
/// Configures the reception filter
/// </summary>
/// <remarks>The message filter will be expanded with every call to
/// this function. If it is desired to reset the filter, please use
/// the 'SetValue' function</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="FromID">The lowest CAN ID to be received</param>
/// <param name="ToID">The highest CAN ID to be received</param>
/// <param name="Mode">Message type, Standard (11-bit identifier) or
/// Extended (29-bit identifier)</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_FilterMessages")]
public static extern TPCANStatus FilterMessages(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
UInt32 FromID,
UInt32 ToID,
[MarshalAs(UnmanagedType.U1)]
TPCANMode Mode);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="StringBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
public static extern TPCANStatus GetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
StringBuilder StringBuffer,
UInt32 BufferLength);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="NumericBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
public static extern TPCANStatus GetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
out UInt32 NumericBuffer,
UInt32 BufferLength);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="NumericBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
public static extern TPCANStatus GetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
out UInt64 NumericBuffer,
UInt32 BufferLength);
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
private static extern TPCANStatus GetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
[In, Out]TPCANChannelInformation[] ChannelsBuffer,
UInt32 BufferLength);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="ChannelsBuffer">Buffer for the parameter value</param>
/// <returns>A TPCANStatus error code</returns>
public static TPCANStatus GetValue(
TPCANHandle Channel,
TPCANParameter Parameter,
TPCANChannelInformation[] ChannelsBuffer)
{
if (ChannelsBuffer == null)
return TPCANStatus.PCAN_ERROR_ILLPARAMVAL;
return GetValue(Channel, Parameter, ChannelsBuffer, (uint)(ChannelsBuffer.Length * Marshal.SizeOf(typeof(TPCANChannelInformation))));
}
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="NumericBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_SetValue")]
public static extern TPCANStatus SetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
ref UInt32 NumericBuffer,
UInt32 BufferLength);
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="NumericBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_SetValue")]
public static extern TPCANStatus SetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
ref UInt64 NumericBuffer,
UInt32 BufferLength);
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter"></param>
/// <param name="StringBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_SetValue")]
public static extern TPCANStatus SetValue(
[MarshalAs(UnmanagedType.U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType.U1)]
TPCANParameter Parameter,
[MarshalAs(UnmanagedType.LPStr,SizeParamIndex=3)]
string StringBuffer,
UInt32 BufferLength);
/// <summary>
/// Returns a descriptive text of a given TPCANStatus error
/// code, in any desired language
/// </summary>
/// <remarks>The current languages available for translation are:
/// Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
/// Italian (0x10) and French (0x0C)</remarks>
/// <param name="Error">A TPCANStatus error code</param>
/// <param name="Language">Indicates a 'Primary language ID'</param>
/// <param name="StringBuffer">Buffer for the text (must be at least 256 in length)</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetErrorText")]
public static extern TPCANStatus GetErrorText(
[MarshalAs(UnmanagedType.U4)]
TPCANStatus Error,
UInt16 Language,
StringBuilder StringBuffer);
/// <summary>
/// Finds a PCAN-Basic channel that matches with the given parameters
/// </summary>
/// <param name="Parameters">A comma separated string contained pairs of
/// parameter-name/value to be matched within a PCAN-Basic channel</param>
/// <param name="FoundChannel">Buffer for returning the PCAN-Basic channel,
/// when found</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_LookUpChannel")]
public static extern TPCANStatus LookUpChannel(
String Parameters,
out TPCANHandle FoundChannel);
#endregion
}
#endregion
}
// PCANBasic.h
//
// ~~~~~~~~~~~~
//
// PCAN-Basic API
//
// ~~~~~~~~~~~~
//
// ------------------------------------------------------------------
// Author : Keneth Wagner
// Last change: 2022-07-06
//
// Language: ANSI-C
// ------------------------------------------------------------------
//
// Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
// more Info at http://www.peak-system.com
//
#ifndef __PCANBASICH__
#define __PCANBASICH__
////////////////////////////////////////////////////////////
// Value definitions
////////////////////////////////////////////////////////////
// Currently defined and supported PCAN channels
//
#define PCAN_NONEBUS 0x00U // Undefined/default value for a PCAN bus
#define PCAN_ISABUS1 0x21U // PCAN-ISA interface, channel 1
#define PCAN_ISABUS2 0x22U // PCAN-ISA interface, channel 2
#define PCAN_ISABUS3 0x23U // PCAN-ISA interface, channel 3
#define PCAN_ISABUS4 0x24U // PCAN-ISA interface, channel 4
#define PCAN_ISABUS5 0x25U // PCAN-ISA interface, channel 5
#define PCAN_ISABUS6 0x26U // PCAN-ISA interface, channel 6
#define PCAN_ISABUS7 0x27U // PCAN-ISA interface, channel 7
#define PCAN_ISABUS8 0x28U // PCAN-ISA interface, channel 8
#define PCAN_DNGBUS1 0x31U // PCAN-Dongle/LPT interface, channel 1
#define PCAN_PCIBUS1 0x41U // PCAN-PCI interface, channel 1
#define PCAN_PCIBUS2 0x42U // PCAN-PCI interface, channel 2
#define PCAN_PCIBUS3 0x43U // PCAN-PCI interface, channel 3
#define PCAN_PCIBUS4 0x44U // PCAN-PCI interface, channel 4
#define PCAN_PCIBUS5 0x45U // PCAN-PCI interface, channel 5
#define PCAN_PCIBUS6 0x46U // PCAN-PCI interface, channel 6
#define PCAN_PCIBUS7 0x47U // PCAN-PCI interface, channel 7
#define PCAN_PCIBUS8 0x48U // PCAN-PCI interface, channel 8
#define PCAN_PCIBUS9 0x409U // PCAN-PCI interface, channel 9
#define PCAN_PCIBUS10 0x40AU // PCAN-PCI interface, channel 10
#define PCAN_PCIBUS11 0x40BU // PCAN-PCI interface, channel 11
#define PCAN_PCIBUS12 0x40CU // PCAN-PCI interface, channel 12
#define PCAN_PCIBUS13 0x40DU // PCAN-PCI interface, channel 13
#define PCAN_PCIBUS14 0x40EU // PCAN-PCI interface, channel 14
#define PCAN_PCIBUS15 0x40FU // PCAN-PCI interface, channel 15
#define PCAN_PCIBUS16 0x410U // PCAN-PCI interface, channel 16
#define PCAN_USBBUS1 0x51U // PCAN-USB interface, channel 1
#define PCAN_USBBUS2 0x52U // PCAN-USB interface, channel 2
#define PCAN_USBBUS3 0x53U // PCAN-USB interface, channel 3
#define PCAN_USBBUS4 0x54U // PCAN-USB interface, channel 4
#define PCAN_USBBUS5 0x55U // PCAN-USB interface, channel 5
#define PCAN_USBBUS6 0x56U // PCAN-USB interface, channel 6
#define PCAN_USBBUS7 0x57U // PCAN-USB interface, channel 7
#define PCAN_USBBUS8 0x58U // PCAN-USB interface, channel 8
#define PCAN_USBBUS9 0x509U // PCAN-USB interface, channel 9
#define PCAN_USBBUS10 0x50AU // PCAN-USB interface, channel 10
#define PCAN_USBBUS11 0x50BU // PCAN-USB interface, channel 11
#define PCAN_USBBUS12 0x50CU // PCAN-USB interface, channel 12
#define PCAN_USBBUS13 0x50DU // PCAN-USB interface, channel 13
#define PCAN_USBBUS14 0x50EU // PCAN-USB interface, channel 14
#define PCAN_USBBUS15 0x50FU // PCAN-USB interface, channel 15
#define PCAN_USBBUS16 0x510U // PCAN-USB interface, channel 16
#define PCAN_PCCBUS1 0x61U // PCAN-PC Card interface, channel 1
#define PCAN_PCCBUS2 0x62U // PCAN-PC Card interface, channel 2
#define PCAN_LANBUS1 0x801U // PCAN-LAN interface, channel 1
#define PCAN_LANBUS2 0x802U // PCAN-LAN interface, channel 2
#define PCAN_LANBUS3 0x803U // PCAN-LAN interface, channel 3
#define PCAN_LANBUS4 0x804U // PCAN-LAN interface, channel 4
#define PCAN_LANBUS5 0x805U // PCAN-LAN interface, channel 5
#define PCAN_LANBUS6 0x806U // PCAN-LAN interface, channel 6
#define PCAN_LANBUS7 0x807U // PCAN-LAN interface, channel 7
#define PCAN_LANBUS8 0x808U // PCAN-LAN interface, channel 8
#define PCAN_LANBUS9 0x809U // PCAN-LAN interface, channel 9
#define PCAN_LANBUS10 0x80AU // PCAN-LAN interface, channel 10
#define PCAN_LANBUS11 0x80BU // PCAN-LAN interface, channel 11
#define PCAN_LANBUS12 0x80CU // PCAN-LAN interface, channel 12
#define PCAN_LANBUS13 0x80DU // PCAN-LAN interface, channel 13
#define PCAN_LANBUS14 0x80EU // PCAN-LAN interface, channel 14
#define PCAN_LANBUS15 0x80FU // PCAN-LAN interface, channel 15
#define PCAN_LANBUS16 0x810U // PCAN-LAN interface, channel 16
// Represent the PCAN error and status codes
//
#define PCAN_ERROR_OK 0x00000U // No error
#define PCAN_ERROR_XMTFULL 0x00001U // Transmit buffer in CAN controller is full
#define PCAN_ERROR_OVERRUN 0x00002U // CAN controller was read too late
#define PCAN_ERROR_BUSLIGHT 0x00004U // Bus error: an error counter reached the 'light' limit
#define PCAN_ERROR_BUSHEAVY 0x00008U // Bus error: an error counter reached the 'heavy' limit
#define PCAN_ERROR_BUSWARNING PCAN_ERROR_BUSHEAVY // Bus error: an error counter reached the 'warning' limit
#define PCAN_ERROR_BUSPASSIVE 0x40000U // Bus error: the CAN controller is error passive
#define PCAN_ERROR_BUSOFF 0x00010U // Bus error: the CAN controller is in bus-off state
#define PCAN_ERROR_ANYBUSERR (PCAN_ERROR_BUSWARNING | PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY | PCAN_ERROR_BUSOFF | PCAN_ERROR_BUSPASSIVE) // Mask for all bus errors
#define PCAN_ERROR_QRCVEMPTY 0x00020U // Receive queue is empty
#define PCAN_ERROR_QOVERRUN 0x00040U // Receive queue was read too late
#define PCAN_ERROR_QXMTFULL 0x00080U // Transmit queue is full
#define PCAN_ERROR_REGTEST 0x00100U // Test of the CAN controller hardware registers failed (no hardware found)
#define PCAN_ERROR_NODRIVER 0x00200U // Driver not loaded
#define PCAN_ERROR_HWINUSE 0x00400U // Hardware already in use by a Net
#define PCAN_ERROR_NETINUSE 0x00800U // A Client is already connected to the Net
#define PCAN_ERROR_ILLHW 0x01400U // Hardware handle is invalid
#define PCAN_ERROR_ILLNET 0x01800U // Net handle is invalid
#define PCAN_ERROR_ILLCLIENT 0x01C00U // Client handle is invalid
#define PCAN_ERROR_ILLHANDLE (PCAN_ERROR_ILLHW | PCAN_ERROR_ILLNET | PCAN_ERROR_ILLCLIENT) // Mask for all handle errors
#define PCAN_ERROR_RESOURCE 0x02000U // Resource (FIFO, Client, timeout) cannot be created
#define PCAN_ERROR_ILLPARAMTYPE 0x04000U // Invalid parameter
#define PCAN_ERROR_ILLPARAMVAL 0x08000U // Invalid parameter value
#define PCAN_ERROR_UNKNOWN 0x10000U // Unknown error
#define PCAN_ERROR_ILLDATA 0x20000U // Invalid data, function, or action
#define PCAN_ERROR_ILLMODE 0x80000U // Driver object state is wrong for the attempted operation
#define PCAN_ERROR_CAUTION 0x2000000U // An operation was successfully carried out, however, irregularities were registered
#define PCAN_ERROR_INITIALIZE 0x4000000U // Channel is not initialized [Value was changed from 0x40000 to 0x4000000]
#define PCAN_ERROR_ILLOPERATION 0x8000000U // Invalid operation [Value was changed from 0x80000 to 0x8000000]
// PCAN devices
//
#define PCAN_NONE 0x00U // Undefined, unknown or not selected PCAN device value
#define PCAN_PEAKCAN 0x01U // PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
#define PCAN_ISA 0x02U // PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
#define PCAN_DNG 0x03U // PCAN-Dongle
#define PCAN_PCI 0x04U // PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
#define PCAN_USB 0x05U // PCAN-USB and PCAN-USB Pro
#define PCAN_PCC 0x06U // PCAN-PC Card
#define PCAN_VIRTUAL 0x07U // PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
#define PCAN_LAN 0x08U // PCAN Gateway devices
// PCAN parameters
//
#define PCAN_DEVICE_ID 0x01U // Device identifier parameter
#define PCAN_5VOLTS_POWER 0x02U // 5-Volt power parameter
#define PCAN_RECEIVE_EVENT 0x03U // PCAN receive event handler parameter
#define PCAN_MESSAGE_FILTER 0x04U // PCAN message filter parameter
#define PCAN_API_VERSION 0x05U // PCAN-Basic API version parameter
#define PCAN_CHANNEL_VERSION 0x06U // PCAN device channel version parameter
#define PCAN_BUSOFF_AUTORESET 0x07U // PCAN Reset-On-Busoff parameter
#define PCAN_LISTEN_ONLY 0x08U // PCAN Listen-Only parameter
#define PCAN_LOG_LOCATION 0x09U // Directory path for log files
#define PCAN_LOG_STATUS 0x0AU // Debug-Log activation status
#define PCAN_LOG_CONFIGURE 0x0BU // Configuration of the debugged information (LOG_FUNCTION_***)
#define PCAN_LOG_TEXT 0x0CU // Custom insertion of text into the log file
#define PCAN_CHANNEL_CONDITION 0x0DU // Availability status of a PCAN-Channel
#define PCAN_HARDWARE_NAME 0x0EU // PCAN hardware name parameter
#define PCAN_RECEIVE_STATUS 0x0FU // Message reception status of a PCAN-Channel
#define PCAN_CONTROLLER_NUMBER 0x10U // CAN-Controller number of a PCAN-Channel
#define PCAN_TRACE_LOCATION 0x11U // Directory path for PCAN trace files
#define PCAN_TRACE_STATUS 0x12U // CAN tracing activation status
#define PCAN_TRACE_SIZE 0x13U // Configuration of the maximum file size of a CAN trace
#define PCAN_TRACE_CONFIGURE 0x14U // Configuration of the trace file storing mode (TRACE_FILE_***)
#define PCAN_CHANNEL_IDENTIFYING 0x15U // Physical identification of a USB based PCAN-Channel by blinking its associated LED
#define PCAN_CHANNEL_FEATURES 0x16U // Capabilities of a PCAN device (FEATURE_***)
#define PCAN_BITRATE_ADAPTING 0x17U // Using of an existing bit rate (PCAN-View connected to a channel)
#define PCAN_BITRATE_INFO 0x18U // Configured bit rate as Btr0Btr1 value
#define PCAN_BITRATE_INFO_FD 0x19U // Configured bit rate as TPCANBitrateFD string
#define PCAN_BUSSPEED_NOMINAL 0x1AU // Configured nominal CAN Bus speed as Bits per seconds
#define PCAN_BUSSPEED_DATA 0x1BU // Configured CAN data speed as Bits per seconds
#define PCAN_IP_ADDRESS 0x1CU // Remote address of a LAN channel as string in IPv4 format
#define PCAN_LAN_SERVICE_STATUS 0x1DU // Status of the Virtual PCAN-Gateway Service
#define PCAN_ALLOW_STATUS_FRAMES 0x1EU // Status messages reception status within a PCAN-Channel
#define PCAN_ALLOW_RTR_FRAMES 0x1FU // RTR messages reception status within a PCAN-Channel
#define PCAN_ALLOW_ERROR_FRAMES 0x20U // Error messages reception status within a PCAN-Channel
#define PCAN_INTERFRAME_DELAY 0x21U // Delay, in microseconds, between sending frames
#define PCAN_ACCEPTANCE_FILTER_11BIT 0x22U // Filter over code and mask patterns for 11-Bit messages
#define PCAN_ACCEPTANCE_FILTER_29BIT 0x23U // Filter over code and mask patterns for 29-Bit messages
#define PCAN_IO_DIGITAL_CONFIGURATION 0x24U // Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
#define PCAN_IO_DIGITAL_VALUE 0x25U // Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
#define PCAN_IO_DIGITAL_SET 0x26U // Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
#define PCAN_IO_DIGITAL_CLEAR 0x27U // Clear multiple digital I/O pins to 0
#define PCAN_IO_ANALOG_VALUE 0x28U // Get value of a single analog input pin
#define PCAN_FIRMWARE_VERSION 0x29U // Get the version of the firmware used by the device associated with a PCAN-Channel
#define PCAN_ATTACHED_CHANNELS_COUNT 0x2AU // Get the amount of PCAN channels attached to a system
#define PCAN_ATTACHED_CHANNELS 0x2BU // Get information about PCAN channels attached to a system
#define PCAN_ALLOW_ECHO_FRAMES 0x2CU // Echo messages reception status within a PCAN-Channel
#define PCAN_DEVICE_PART_NUMBER 0x2DU // Get the part number associated to a device
// DEPRECATED parameters
//
#define PCAN_DEVICE_NUMBER PCAN_DEVICE_ID // Deprecated parameter. Use PCAN_DEVICE_ID instead
// PCAN parameter values
//
#define PCAN_PARAMETER_OFF 0x00U // The PCAN parameter is not set (inactive)
#define PCAN_PARAMETER_ON 0x01U // The PCAN parameter is set (active)
#define PCAN_FILTER_CLOSE 0x00U // The PCAN filter is closed. No messages will be received
#define PCAN_FILTER_OPEN 0x01U // The PCAN filter is fully opened. All messages will be received
#define PCAN_FILTER_CUSTOM 0x02U // The PCAN filter is custom configured. Only registered messages will be received
#define PCAN_CHANNEL_UNAVAILABLE 0x00U // The PCAN-Channel handle is illegal, or its associated hardware is not available
#define PCAN_CHANNEL_AVAILABLE 0x01U // The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
#define PCAN_CHANNEL_OCCUPIED 0x02U // The PCAN-Channel handle is valid, and is already being used
#define PCAN_CHANNEL_PCANVIEW (PCAN_CHANNEL_AVAILABLE | PCAN_CHANNEL_OCCUPIED) // The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
#define LOG_FUNCTION_DEFAULT 0x00U // Logs system exceptions / errors
#define LOG_FUNCTION_ENTRY 0x01U // Logs the entries to the PCAN-Basic API functions
#define LOG_FUNCTION_PARAMETERS 0x02U // Logs the parameters passed to the PCAN-Basic API functions
#define LOG_FUNCTION_LEAVE 0x04U // Logs the exits from the PCAN-Basic API functions
#define LOG_FUNCTION_WRITE 0x08U // Logs the CAN messages passed to the CAN_Write function
#define LOG_FUNCTION_READ 0x10U // Logs the CAN messages received within the CAN_Read function
#define LOG_FUNCTION_ALL 0xFFFFU // Logs all possible information within the PCAN-Basic API functions
#define TRACE_FILE_SINGLE 0x00U // A single file is written until it size reaches PAN_TRACE_SIZE
#define TRACE_FILE_SEGMENTED 0x01U // Traced data is distributed in several files with size PAN_TRACE_SIZE
#define TRACE_FILE_DATE 0x02U // Includes the date into the name of the trace file
#define TRACE_FILE_TIME 0x04U // Includes the start time into the name of the trace file
#define TRACE_FILE_OVERWRITE 0x80U // Causes the overwriting of available traces (same name)
#define FEATURE_FD_CAPABLE 0x01U // Device supports flexible data-rate (CAN-FD)
#define FEATURE_DELAY_CAPABLE 0x02U // Device supports a delay between sending frames (FPGA based USB devices)
#define FEATURE_IO_CAPABLE 0x04U // Device supports I/O functionality for electronic circuits (USB-Chip devices)
#define SERVICE_STATUS_STOPPED 0x01U // The service is not running
#define SERVICE_STATUS_RUNNING 0x04U // The service is running
// Other constants
//
#define MAX_LENGTH_HARDWARE_NAME 33 // Maximum length of the name of a device: 32 characters + terminator
#define MAX_LENGTH_VERSION_STRING 256 // Maximum length of a version string: 255 characters + terminator
// PCAN message types
//
#define PCAN_MESSAGE_STANDARD 0x00U // The PCAN message is a CAN Standard Frame (11-bit identifier)
#define PCAN_MESSAGE_RTR 0x01U // The PCAN message is a CAN Remote-Transfer-Request Frame
#define PCAN_MESSAGE_EXTENDED 0x02U // The PCAN message is a CAN Extended Frame (29-bit identifier)
#define PCAN_MESSAGE_FD 0x04U // The PCAN message represents a FD frame in terms of CiA Specs
#define PCAN_MESSAGE_BRS 0x08U // The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
#define PCAN_MESSAGE_ESI 0x10U // The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
#define PCAN_MESSAGE_ECHO 0x20U // The PCAN message represents an echo CAN Frame
#define PCAN_MESSAGE_ERRFRAME 0x40U // The PCAN message represents an error frame
#define PCAN_MESSAGE_STATUS 0x80U // The PCAN message represents a PCAN status message
// LookUp Parameters
//
#define LOOKUP_DEVICE_TYPE __T("devicetype") // Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
#define LOOKUP_DEVICE_ID __T("deviceid") // Lookup channel by device id
#define LOOKUP_CONTROLLER_NUMBER __T("controllernumber") // Lookup channel by CAN controller 0-based index
#define LOOKUP_IP_ADDRESS __T("ipaddress") // Lookup channel by IP address (LAN channels only)
// Frame Type / Initialization Mode
//
#define PCAN_MODE_STANDARD PCAN_MESSAGE_STANDARD
#define PCAN_MODE_EXTENDED PCAN_MESSAGE_EXTENDED
// Baud rate codes = BTR0/BTR1 register values for the CAN controller.
// You can define your own Baud rate with the BTROBTR1 register.
// Take a look at www.peak-system.com for our free software "BAUDTOOL"
// to calculate the BTROBTR1 register for every bit rate and sample point.
//
#define PCAN_BAUD_1M 0x0014U // 1 MBit/s
#define PCAN_BAUD_800K 0x0016U // 800 kBit/s
#define PCAN_BAUD_500K 0x001CU // 500 kBit/s
#define PCAN_BAUD_250K 0x011CU // 250 kBit/s
#define PCAN_BAUD_125K 0x031CU // 125 kBit/s
#define PCAN_BAUD_100K 0x432FU // 100 kBit/s
#define PCAN_BAUD_95K 0xC34EU // 95,238 kBit/s
#define PCAN_BAUD_83K 0x852BU // 83,333 kBit/s
#define PCAN_BAUD_50K 0x472FU // 50 kBit/s
#define PCAN_BAUD_47K 0x1414U // 47,619 kBit/s
#define PCAN_BAUD_33K 0x8B2FU // 33,333 kBit/s
#define PCAN_BAUD_20K 0x532FU // 20 kBit/s
#define PCAN_BAUD_10K 0x672FU // 10 kBit/s
#define PCAN_BAUD_5K 0x7F7FU // 5 kBit/s
// Represents the configuration for a CAN bit rate
// Note:
// * Each parameter and its value must be separated with a '='.
// * Each pair of parameter/value must be separated using ','.
//
// Example:
// f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
//
#define PCAN_BR_CLOCK __T("f_clock")
#define PCAN_BR_CLOCK_MHZ __T("f_clock_mhz")
#define PCAN_BR_NOM_BRP __T("nom_brp")
#define PCAN_BR_NOM_TSEG1 __T("nom_tseg1")
#define PCAN_BR_NOM_TSEG2 __T("nom_tseg2")
#define PCAN_BR_NOM_SJW __T("nom_sjw")
#define PCAN_BR_NOM_SAMPLE __T("nom_sam")
#define PCAN_BR_DATA_BRP __T("data_brp")
#define PCAN_BR_DATA_TSEG1 __T("data_tseg1")
#define PCAN_BR_DATA_TSEG2 __T("data_tseg2")
#define PCAN_BR_DATA_SJW __T("data_sjw")
#define PCAN_BR_DATA_SAMPLE __T("data_ssp_offset")
// Type of PCAN (Non-PnP) hardware
//
#define PCAN_TYPE_ISA 0x01U // PCAN-ISA 82C200
#define PCAN_TYPE_ISA_SJA 0x09U // PCAN-ISA SJA1000
#define PCAN_TYPE_ISA_PHYTEC 0x04U // PHYTEC ISA
#define PCAN_TYPE_DNG 0x02U // PCAN-Dongle 82C200
#define PCAN_TYPE_DNG_EPP 0x03U // PCAN-Dongle EPP 82C200
#define PCAN_TYPE_DNG_SJA 0x05U // PCAN-Dongle SJA1000
#define PCAN_TYPE_DNG_SJA_EPP 0x06U // PCAN-Dongle EPP SJA1000
////////////////////////////////////////////////////////////
// Type definitions
////////////////////////////////////////////////////////////
#define TPCANHandle WORD // Represents a PCAN hardware channel handle
#define TPCANStatus DWORD // Represents a PCAN status/error code
#define TPCANParameter BYTE // Represents a PCAN parameter to be read or set
#define TPCANDevice BYTE // Represents a PCAN device
#define TPCANMessageType BYTE // Represents the type of a PCAN message
#define TPCANType BYTE // Represents the type of PCAN hardware to be initialized
#define TPCANMode BYTE // Represents a PCAN filter mode
#define TPCANBaudrate WORD // Represents a PCAN Baud rate register value
#define TPCANBitrateFD LPSTR // Represents a PCAN-FD bit rate string
#define TPCANTimestampFD UINT64 // Represents a timestamp of a received PCAN FD message
////////////////////////////////////////////////////////////
// Structure definitions
////////////////////////////////////////////////////////////
#include <windows.h>
#include <windef.h>
// Represents a PCAN message
//
typedef struct tagTPCANMsg
{
DWORD ID; // 11/29-bit message identifier
TPCANMessageType MSGTYPE; // Type of the message
BYTE LEN; // Data Length Code of the message (0..8)
BYTE DATA[8]; // Data of the message (DATA[0]..DATA[7])
} TPCANMsg;
// Represents a timestamp of a received PCAN message
// Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
//
typedef struct tagTPCANTimestamp
{
DWORD millis; // Base-value: milliseconds: 0.. 2^32-1
WORD millis_overflow; // Roll-arounds of millis
WORD micros; // Microseconds: 0..999
} TPCANTimestamp;
// Represents a PCAN message from a FD capable hardware
//
typedef struct tagTPCANMsgFD
{
DWORD ID; // 11/29-bit message identifier
TPCANMessageType MSGTYPE; // Type of the message
BYTE DLC; // Data Length Code of the message (0..15)
BYTE DATA[64]; // Data of the message (DATA[0]..DATA[63])
} TPCANMsgFD;
// Describes an available PCAN channel
//
typedef struct tagTPCANChannelInformation
{
TPCANHandle channel_handle; // PCAN channel handle
TPCANDevice device_type; // Kind of PCAN device
BYTE controller_number; // CAN-Controller number
DWORD device_features; // Device capabilities flag (see FEATURE_*)
char device_name[MAX_LENGTH_HARDWARE_NAME]; // Device name
DWORD device_id; // Device number
DWORD channel_condition; // Availability status of a PCAN-Channel
}TPCANChannelInformation;
#ifdef __cplusplus
extern "C" {
#define _DEF_ARG =0
#else
#define _DEF_ARG
#endif
////////////////////////////////////////////////////////////
// PCAN-Basic API function declarations
////////////////////////////////////////////////////////////
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <param name="Btr0Btr1">"The speed for the communication (BTR0BTR1 code)"</param>
/// <param name="HwType">"Non-PnP: The type of hardware and operation mode"</param>
/// <param name="IOPort">"Non-PnP: The I/O address for the parallel port"</param>
/// <param name="Interrupt">"Non-PnP: Interrupt number of the parallel port"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_Initialize(
TPCANHandle Channel,
TPCANBaudrate Btr0Btr1,
TPCANType HwType _DEF_ARG,
DWORD IOPort _DEF_ARG,
WORD Interrupt _DEF_ARG);
/// <summary>
/// Initializes a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">"The handle of a FD capable PCAN Channel"</param>
/// <param name="BitrateFD">"The speed for the communication (FD bit rate string)"</param>
/// <remarks>See PCAN_BR_* values
/// * Parameter and values must be separated by '='
/// * Couples of Parameter/value must be separated by ','
/// * Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
/// nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
/// * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam
///</remarks>
/// <example>f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1</example>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_InitializeFD(
TPCANHandle Channel,
TPCANBitrateFD BitrateFD);
/// <summary>
/// Uninitializes one or all PCAN Channels initialized by CAN_Initialize
/// </summary>
/// <remarks>Giving the TPCANHandle value "PCAN_NONEBUS",
/// uninitialize all initialized channels</remarks>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_Uninitialize(
TPCANHandle Channel);
/// <summary>
/// Resets the receive and transmit queues of the PCAN Channel
/// </summary>
/// <remarks>
/// A reset of the CAN controller is not performed.
/// </remarks>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_Reset(
TPCANHandle Channel);
/// <summary>
/// Gets the current status of a PCAN Channel
/// </summary>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_GetStatus(
TPCANHandle Channel);
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <param name="MessageBuffer">"A TPCANMsg structure buffer to store the CAN message"</param>
/// <param name="TimestampBuffer">"A TPCANTimestamp structure buffer to get
/// the reception time of the message. If this value is not desired, this parameter
/// should be passed as NULL"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_Read(
TPCANHandle Channel,
TPCANMsg* MessageBuffer,
TPCANTimestamp* TimestampBuffer);
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">"The handle of a FD capable PCAN Channel"</param>
/// <param name="MessageBuffer">"A TPCANMsgFD structure buffer to store the CAN message"</param>
/// <param name="TimestampBuffer">"A TPCANTimestampFD buffer to get
/// the reception time of the message. If this value is not desired, this parameter
/// should be passed as NULL"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_ReadFD(
TPCANHandle Channel,
TPCANMsgFD* MessageBuffer,
TPCANTimestampFD *TimestampBuffer);
/// <summary>
/// Transmits a CAN message
/// </summary>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <param name="MessageBuffer">"A TPCANMsg buffer with the message to be sent"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_Write(
TPCANHandle Channel,
TPCANMsg* MessageBuffer);
/// <summary>
/// Transmits a CAN message over a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">"The handle of a FD capable PCAN Channel"</param>
/// <param name="MessageBuffer">"A TPCANMsgFD buffer with the message to be sent"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_WriteFD(
TPCANHandle Channel,
TPCANMsgFD* MessageBuffer);
/// <summary>
/// Configures the reception filter.
/// </summary>
/// <remarks>The message filter will be expanded with every call to
/// this function. If it is desired to reset the filter, please use
/// the CAN_SetValue function</remarks>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <param name="FromID">"The lowest CAN ID to be received"</param>
/// <param name="ToID">"The highest CAN ID to be received"</param>
/// <param name="Mode">"Message type, Standard (11-bit identifier) or
/// Extended (29-bit identifier)"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_FilterMessages(
TPCANHandle Channel,
DWORD FromID,
DWORD ToID,
TPCANMode Mode);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <param name="Parameter">"The TPCANParameter parameter to get"</param>
/// <param name="Buffer">"Buffer for the parameter value"</param>
/// <param name="BufferLength">"Size in bytes of the buffer"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_GetValue(
TPCANHandle Channel,
TPCANParameter Parameter,
void* Buffer,
DWORD BufferLength);
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">"The handle of a PCAN Channel"</param>
/// <param name="Parameter">"The TPCANParameter parameter to set"</param>
/// <param name="Buffer">"Buffer with the value to be set"</param>
/// <param name="BufferLength">"Size in bytes of the buffer"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_SetValue(
TPCANHandle Channel,
TPCANParameter Parameter,
void* Buffer,
DWORD BufferLength);
/// <summary>
/// Returns a descriptive text of a given TPCANStatus error
/// code, in any desired language
/// </summary>
/// <remarks>The current languages available for translation are:
/// Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
/// Italian (0x10) and French (0x0C)</remarks>
/// <param name="Error">"A TPCANStatus error code"</param>
/// <param name="Language">"Indicates a 'Primary language ID'"</param>
/// <param name="Buffer">"Buffer for a null terminated char array"</param>
/// <returns>"A TPCANStatus error code"</returns>
TPCANStatus __stdcall CAN_GetErrorText(
TPCANStatus Error,
WORD Language,
LPSTR Buffer);
/// <summary>
/// Finds a PCAN-Basic channel that matches with the given parameters
/// </summary>
/// <param name="Parameters">A comma separated string contained pairs of
/// parameter-name/value to be matched within a PCAN-Basic channel</param>
/// <param name="FoundChannel">Buffer for returning the PCAN-Basic channel,
/// when found</param>
/// <returns>A TPCANStatus error code</returns>
TPCANStatus __stdcall CAN_LookUpChannel(
LPSTR Parameters,
TPCANHandle* FoundChannel);
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
// PCANBasic.pas
//
// ~~~~~~~~~~~~
//
// PCAN-Basic API
//
// ~~~~~~~~~~~~
//
// ------------------------------------------------------------------
// Author : Keneth Wagner
// Last change: 2022-07-06
//
// Language: Object Pascal
// ------------------------------------------------------------------
//
// Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
// more Info at http://www.peak-system.com
//
unit PCANBasic;
interface
Const
// Other constants
//
MAX_LENGTH_HARDWARE_NAME = 33; // Maximum length of the name of a device: 32 characters + terminator
MAX_LENGTH_VERSION_STRING = 256; // Maximum length of a version string: 255 characters + terminator
type
TPCANHandle = Word;
PTPCANHandle = ^Word;
TPCANBitrateFD = PAnsiChar;
TPCANTimestampFD = UInt64;
PUInt64 = ^UInt64;
{$Z4}
/// <summary>
/// Represents a PCAN status/error code
/// </summary>
TPCANStatus = (
/// <summary>
/// No error
/// </summary>
PCAN_ERROR_OK = $00000,
/// <summary>
/// Transmit buffer in CAN controller is full
/// </summary>
PCAN_ERROR_XMTFULL = $00001,
/// <summary>
/// CAN controller was read too late
/// </summary>
PCAN_ERROR_OVERRUN = $00002,
/// <summary>
/// Bus error: an error counter reached the 'light' limit
/// </summary>
PCAN_ERROR_BUSLIGHT = $00004,
/// <summary>
/// Bus error: an error counter reached the 'heavy' limit
/// </summary>
PCAN_ERROR_BUSHEAVY = $00008,
/// <summary>
/// Bus error: an error counter reached the 'warning' limit
/// </summary>
PCAN_ERROR_BUSWARNING = LongWord(PCAN_ERROR_BUSHEAVY),
/// <summary>
/// Bus error: the CAN controller is error passive
/// </summary>
PCAN_ERROR_BUSPASSIVE = $40000,
/// <summary>
/// Bus error: the CAN controller is in bus-off state
/// </summary>
PCAN_ERROR_BUSOFF = $00010,
/// <summary>
/// Mask for all bus errors
/// </summary>
PCAN_ERROR_ANYBUSERR = LongWord(PCAN_ERROR_BUSWARNING) Or LongWord(PCAN_ERROR_BUSLIGHT) Or LongWord(PCAN_ERROR_BUSHEAVY) Or LongWord(PCAN_ERROR_BUSOFF) Or LongWord(PCAN_ERROR_BUSPASSIVE),
/// <summary>
/// Receive queue is empty
/// </summary>
PCAN_ERROR_QRCVEMPTY = $00020,
/// <summary>
/// Receive queue was read too late
/// </summary>
PCAN_ERROR_QOVERRUN = $00040,
/// <summary>
/// Transmit queue is full
/// </summary>
PCAN_ERROR_QXMTFULL = $00080,
/// <summary>
/// Test of the CAN controller hardware registers failed (no hardware found)
/// </summary>
PCAN_ERROR_REGTEST = $00100,
/// <summary>
/// Driver not loaded
/// </summary>
PCAN_ERROR_NODRIVER = $00200,
/// <summary>
/// Hardware already in use by a Net
/// </summary>
PCAN_ERROR_HWINUSE = $00400,
/// <summary>
/// A Client is already connected to the Net
/// </summary>
PCAN_ERROR_NETINUSE = $00800,
/// <summary>
/// Hardware handle is invalid
/// </summary>
PCAN_ERROR_ILLHW = $01400,
/// <summary>
/// Net handle is invalid
/// </summary>
PCAN_ERROR_ILLNET = $01800,
/// <summary>
/// Client handle is invalid
/// </summary>
PCAN_ERROR_ILLCLIENT = $01C00,
/// <summary>
/// Mask for all handle errors
/// </summary>
PCAN_ERROR_ILLHANDLE = LongWord(PCAN_ERROR_ILLHW) Or LongWord(PCAN_ERROR_ILLNET) Or LongWord(PCAN_ERROR_ILLCLIENT),
/// <summary>
/// Resource (FIFO, Client, timeout) cannot be created
/// </summary>
PCAN_ERROR_RESOURCE = $02000,
/// <summary>
/// Invalid parameter
/// </summary>
PCAN_ERROR_ILLPARAMTYPE = $04000,
/// <summary>
/// Invalid parameter value
/// </summary>
PCAN_ERROR_ILLPARAMVAL = $08000,
/// <summary>
/// Unknown error
/// </summary>
PCAN_ERROR_UNKNOWN = $10000,
/// <summary>
/// Invalid data, function, or action
/// </summary>
PCAN_ERROR_ILLDATA = $20000,
/// <summary>
/// Driver object state is wrong for the attempted operation
/// </summary>
PCAN_ERROR_ILLMODE = $80000,
/// <summary>
/// An operation was successfully carried out, however, irregularities were registered
/// </summary>
PCAN_ERROR_CAUTION = $2000000,
/// <summary>
/// Channel is not initialized
/// <remarks>Value was changed from 0x40000 to 0x4000000</remarks>
/// </summary>
PCAN_ERROR_INITIALIZE = $4000000,
/// <summary>
/// Invalid operation
/// <remarks>Value was changed from 0x80000 to 0x8000000</remarks>
/// </summary>
PCAN_ERROR_ILLOPERATION = $8000000
);
{$Z1}
/// <summary>
/// Represents a PCAN device
/// </summary>
TPCANDevice = (
/// <summary>
/// Undefined, unknown or not selected PCAN device value
/// </summary>
PCAN_NONE = 0,
/// <summary>
/// PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
/// </summary>
PCAN_PEAKCAN = 1,
/// <summary>
/// PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
/// </summary>
PCAN_ISA = 2,
/// <summary>
/// PCAN-Dongle
/// </summary>
PCAN_DNG = 3,
/// <summary>
/// PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
/// </summary>
PCAN_PCI = 4,
/// <summary>
/// PCAN-USB and PCAN-USB Pro
/// </summary>
PCAN_USB = 5,
/// <summary>
/// PCAN-PC Card
/// </summary>
PCAN_PCC = 6,
/// <summary>
/// PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
/// </summary>
PCAN_VIRTUAL = 7,
/// <summary>
/// PCAN Gateway devices
/// </summary>
PCAN_LAN = 8
);
/// <summary>
/// Represents a PCAN parameter to be read or set
/// </summary>
TPCANParameter = (
/// <summary>
/// Device identifier parameter
/// </summary>
PCAN_DEVICE_ID = 1,
/// <summary>
/// DEPRECATED. Use PCAN_DEVICE_ID instead
/// </summary>
PCAN_DEVICE_NUMBER = PCAN_DEVICE_ID,
/// <summary>
/// 5-Volt power parameter
/// </summary>
PCAN_5VOLTS_POWER = 2,
/// <summary>
/// PCAN receive event handler parameter
/// </summary>
PCAN_RECEIVE_EVENT = 3,
/// <summary>
/// PCAN message filter parameter
/// </summary>
PCAN_MESSAGE_FILTER = 4,
/// <summary>
/// PCAN-Basic API version parameter
/// </summary>
PCAN_API_VERSION = 5,
/// <summary>
/// PCAN device channel version parameter
/// </summary>
PCAN_CHANNEL_VERSION = 6,
/// <summary>
/// PCAN Reset-On-Busoff parameter
/// </summary>
PCAN_BUSOFF_AUTORESET = 7,
/// <summary>
/// PCAN Listen-Only parameter
/// </summary>
PCAN_LISTEN_ONLY = 8,
/// <summary>
/// Directory path for log files
/// </summary>
PCAN_LOG_LOCATION = 9,
/// <summary>
/// Debug-Log activation status
/// </summary>
PCAN_LOG_STATUS = 10,
/// <summary>
/// Configuration of the debugged information (LOG_FUNCTION_***)
/// </summary>
PCAN_LOG_CONFIGURE = 11,
/// <summary>
/// Custom insertion of text into the log file
/// </summary>
PCAN_LOG_TEXT = 12,
/// <summary>
/// Availability status of a PCAN-Channel
/// </summary>
PCAN_CHANNEL_CONDITION = 13,
/// <summary>
/// PCAN hardware name parameter
/// </summary>
PCAN_HARDWARE_NAME = 14,
/// <summary>
/// Message reception status of a PCAN-Channel
/// </summary>
PCAN_RECEIVE_STATUS = 15,
/// <summary>
/// CAN-Controller number of a PCAN-Channel
/// </summary>
PCAN_CONTROLLER_NUMBER = 16,
/// <summary>
/// Directory path for PCAN trace files
/// </summary>
PCAN_TRACE_LOCATION = 17,
/// <summary>
/// CAN tracing activation status
/// </summary>
PCAN_TRACE_STATUS = 18,
/// <summary>
/// Configuration of the maximum file size of a CAN trace
/// </summary>
PCAN_TRACE_SIZE = 19,
/// <summary>
/// Configuration of the trace file storing mode (TRACE_FILE_***)
/// </summary>
PCAN_TRACE_CONFIGURE = 20,
/// <summary>
/// Physical identification of a USB based PCAN-Channel by blinking its associated LED
/// </summary>
PCAN_CHANNEL_IDENTIFYING = 21,
/// <summary>
/// Capabilities of a PCAN device (FEATURE_***)
/// </summary>
PCAN_CHANNEL_FEATURES = 22,
/// <summary>
/// Using of an existing bit rate (PCAN-View connected to a channel)
/// </summary>
PCAN_BITRATE_ADAPTING = 23,
/// <summary>
/// Configured bit rate as Btr0Btr1 value
/// </summary>
PCAN_BITRATE_INFO = 24,
/// <summary>
/// Configured bit rate as TPCANBitrateFD string
/// </summary>
PCAN_BITRATE_INFO_FD = 25,
/// <summary>
/// Configured nominal CAN Bus speed as Bits per seconds
/// </summary>
PCAN_BUSSPEED_NOMINAL = 26,
/// <summary>
/// Configured CAN data speed as Bits per seconds
/// </summary>
PCAN_BUSSPEED_DATA = 27,
/// <summary>
/// Remote address of a LAN channel as string in IPv4 format
/// </summary>
PCAN_IP_ADDRESS = 28,
/// <summary>
/// Status of the Virtual PCAN-Gateway Service
/// </summary>
PCAN_LAN_SERVICE_STATUS = 29,
/// <summary>
/// Status messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_STATUS_FRAMES = 30,
/// <summary>
/// RTR messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_RTR_FRAMES = 31,
/// <summary>
/// Error messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_ERROR_FRAMES = 32,
/// <summary>
/// Delay, in microseconds, between sending frames
/// </summary>
PCAN_INTERFRAME_DELAY = 33,
/// <summary>
/// Filter over code and mask patterns for 11-Bit messages
/// </summary>
PCAN_ACCEPTANCE_FILTER_11BIT = 34,
/// <summary>
/// Filter over code and mask patterns for 29-Bit messages
/// </summary>
PCAN_ACCEPTANCE_FILTER_29BIT = 35,
/// <summary>
/// Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
/// </summary>
PCAN_IO_DIGITAL_CONFIGURATION = 36,
/// <summary>
/// Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
/// </summary>
PCAN_IO_DIGITAL_VALUE = 37,
/// <summary>
/// Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
/// </summary>
PCAN_IO_DIGITAL_SET = 38,
/// <summary>
/// Clear multiple digital I/O pins to 0
/// </summary>
PCAN_IO_DIGITAL_CLEAR = 39,
/// <summary>
/// Get value of a single analog input pin
/// </summary>
PCAN_IO_ANALOG_VALUE = 40,
/// <summary>
/// Get the version of the firmware used by the device associated with a PCAN-Channel
/// </summary>
PCAN_FIRMWARE_VERSION = 41,
/// <summary>
/// Get the amount of PCAN channels attached to a system
/// </summary>
PCAN_ATTACHED_CHANNELS_COUNT = 42,
/// <summary>
/// Get information about PCAN channels attached to a system
/// </summary>
PCAN_ATTACHED_CHANNELS = 43,
/// <summary>
/// Echo messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_ECHO_FRAMES = 44,
/// <summary>
/// Get the part number associated to a device
/// </summary>
PCAN_DEVICE_PART_NUMBER = 45
);
/// <summary>
/// Represents the type of a PCAN message
/// </summary>
TPCANMessageType = (
/// <summary>
/// The PCAN message is a CAN Standard Frame (11-bit identifier)
/// </summary>
PCAN_MESSAGE_STANDARD = $00,
/// <summary>
/// The PCAN message is a CAN Remote-Transfer-Request Frame
/// </summary>
PCAN_MESSAGE_RTR = $01,
/// <summary>
/// The PCAN message is a CAN Extended Frame (29-bit identifier)
/// </summary>
PCAN_MESSAGE_EXTENDED = $02,
/// <summary>
/// The PCAN message represents a FD frame in terms of CiA Specs
/// </summary>
PCAN_MESSAGE_FD = $04,
/// <summary>
/// The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
/// </summary>
PCAN_MESSAGE_BRS = $08,
/// <summary>
/// The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
/// </summary>
PCAN_MESSAGE_ESI = $10,
/// <summary>
/// The PCAN message represents an echo CAN Frame
/// </summary>
PCAN_MESSAGE_ECHO = $20,
/// <summary>
/// The PCAN message represents an error frame
/// </summary>
PCAN_MESSAGE_ERRFRAME = $40,
/// <summary>
/// The PCAN message represents a PCAN status message
/// </summary>
PCAN_MESSAGE_STATUS = $80
);
/// <summary>
/// Represents a PCAN filter mode
/// </summary>
TPCANMode = (
/// <summary>
/// Mode is Standard (11-bit identifier)
/// </summary>
PCAN_MODE_STANDARD = Byte(PCAN_MESSAGE_STANDARD),
/// <summary>
/// Mode is Extended (29-bit identifier)
/// </summary>
PCAN_MODE_EXTENDED = Byte(PCAN_MESSAGE_EXTENDED)
);
{$Z2}
/// <summary>
/// Represents a PCAN Baud rate register value
/// </summary>
TPCANBaudrate = (
/// <summary>
/// 1 MBit/s
/// </summary>
PCAN_BAUD_1M = $0014,
/// <summary>
/// 800 kBit/s
/// </summary>
PCAN_BAUD_800K = $0016,
/// <summary>
/// 500 kBit/s
/// </summary>
PCAN_BAUD_500K = $001C,
/// <summary>
/// 250 kBit/s
/// </summary>
PCAN_BAUD_250K = $011C,
/// <summary>
/// 125 kBit/s
/// </summary>
PCAN_BAUD_125K = $031C,
/// <summary>
/// 100 kBit/s
/// </summary>
PCAN_BAUD_100K = $432F,
/// <summary>
/// 95,238 kBit/s
/// </summary>
PCAN_BAUD_95K = $C34E,
/// <summary>
/// 83,333 kBit/s
/// </summary>
PCAN_BAUD_83K = $852B,
/// <summary>
/// 50 kBit/s
/// </summary>
PCAN_BAUD_50K = $472F,
/// <summary>
/// 47,619 kBit/s
/// </summary>
PCAN_BAUD_47K = $1414,
/// <summary>
/// 33,333 kBit/s
/// </summary>
PCAN_BAUD_33K = $8B2F,
/// <summary>
/// 20 kBit/s
/// </summary>
PCAN_BAUD_20K = $532F,
/// <summary>
/// 10 kBit/s
/// </summary>
PCAN_BAUD_10K = $672F,
/// <summary>
/// 5 kBit/s
/// </summary>
PCAN_BAUD_5K = $7F7F
);
{$Z1}
/// <summary>
/// Represents the type of PCAN (Non-PnP) hardware to be initialized
/// </summary>
TPCANType = (
/// <summary>
/// PCAN-ISA 82C200
/// </summary>
PCAN_TYPE_ISA = $01,
/// <summary>
/// PCAN-ISA SJA1000
/// </summary>
PCAN_TYPE_ISA_SJA = $09,
/// <summary>
/// PHYTEC ISA
/// </summary>
PCAN_TYPE_ISA_PHYTEC = $04,
/// <summary>
/// PCAN-Dongle 82C200
/// </summary>
PCAN_TYPE_DNG = $02,
/// <summary>
/// PCAN-Dongle EPP 82C200
/// </summary>
PCAN_TYPE_DNG_EPP = $03,
/// <summary>
/// PCAN-Dongle SJA1000
/// </summary>
PCAN_TYPE_DNG_SJA = $05,
/// <summary>
/// PCAN-Dongle EPP SJA1000
/// </summary>
PCAN_TYPE_DNG_SJA_EPP = $06
);
/// <summary>
/// Represents a PCAN message
/// </summary>
TPCANMsg = record
/// <summary>
/// 11/29-bit message identifier
/// </summary>
ID: Longword;
/// <summary>
/// Type of the message
/// </summary>
MSGTYPE: TPCANMessageType;
/// <summary>
/// Data Length Code of the message (0..8)
/// </summary>
LEN: Byte;
/// <summary>
/// Data of the message (DATA[0]..DATA[7])
/// </summary>
DATA: array[0..7] of Byte;
end;
PTPCANMsg = ^TPCANMsg;
/// <summary>
/// Represents a timestamp of a received PCAN message.
/// Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
/// </summary>
TPCANTimestamp = record
/// <summary>
/// Base-value: milliseconds: 0.. 2^32-1
/// </summary>
millis: Longword;
/// <summary>
/// Roll-arounds of millis
/// </summary>
millis_overflow: Word;
/// <summary>
/// Microseconds: 0..999
/// </summary>
micros: Word;
end;
PTPCANTimestamp = ^TPCANTimestamp;
/// <summary>
/// Represents a PCAN message from a FD capable hardware
/// </summary>
TPCANMsgFD = record
/// <summary>
/// 11/29-bit message identifier
/// </summary>
ID: Longword;
/// <summary>
/// Type of the message
/// </summary>
MSGTYPE: TPCANMessageType;
/// <summary>
/// Data Length Code of the message (0..15)
/// </summary>
DLC: Byte;
/// <summary>
/// Data of the message (DATA[0]..DATA[63])
/// </summary>
DATA: array[0..63] of Byte;
end;
PTPCANMsgFD = ^TPCANMsgFD;
/// <summary>
/// Describes an available PCAN channel
/// </summary>
TPCANChannelInformation = record
/// <summary>
/// PCAN channel handle
/// </summary>
channel_handle: TPCANHandle;
/// <summary>
/// Kind of PCAN device
/// </summary>
device_type: TPCANDevice;
/// <summary>
/// CAN-Controller number
/// </summary>
controller_number: Byte;
/// <summary>
/// Device capabilities flag (see FEATURE_*)
/// </summary>
device_features: Longword;
/// <summary>
/// Device name
/// </summary>
device_name: array [0..MAX_LENGTH_HARDWARE_NAME-1] of AnsiChar;
/// <summary>
/// Device number
/// </summary>
device_id: Longword;
/// <summary>
/// Availability status of a PCAN-Channel
/// </summary>
channel_condition: Longword;
end;
PTPCANChannelInformation = ^TPCANChannelInformation;
/// <summary>
/// PCAN-Basic API class implementation
/// </summary>
TPCANBasic = class
public
class var
/// <summary>
/// Undefined/default value for a PCAN bus
/// </summary>
const PCAN_NONEBUS: TPCANHandle = $00;
/// <summary>
/// PCAN-ISA interface, channel 1
/// </summary>
const PCAN_ISABUS1: TPCANHandle = $21;
/// <summary>
/// PCAN-ISA interface, channel 2
/// </summary>
const PCAN_ISABUS2: TPCANHandle = $22;
/// <summary>
/// PCAN-ISA interface, channel 3
/// </summary>
const PCAN_ISABUS3: TPCANHandle = $23;
/// <summary>
/// PCAN-ISA interface, channel 4
/// </summary>
const PCAN_ISABUS4: TPCANHandle = $24;
/// <summary>
/// PCAN-ISA interface, channel 5
/// </summary>
const PCAN_ISABUS5: TPCANHandle = $25;
/// <summary>
/// PCAN-ISA interface, channel 6
/// </summary>
const PCAN_ISABUS6: TPCANHandle = $26;
/// <summary>
/// PCAN-ISA interface, channel 7
/// </summary>
const PCAN_ISABUS7: TPCANHandle = $27;
/// <summary>
/// PCAN-ISA interface, channel 8
/// </summary>
const PCAN_ISABUS8: TPCANHandle = $28;
/// <summary>
/// PPCAN-Dongle/LPT interface, channel 1
/// </summary>
const PCAN_DNGBUS1: TPCANHandle = $31;
/// <summary>
/// PCAN-PCI interface, channel 1
/// </summary>
const PCAN_PCIBUS1: TPCANHandle = $41;
/// <summary>
/// PCAN-PCI interface, channel 2
/// </summary>
const PCAN_PCIBUS2: TPCANHandle = $42;
/// <summary>
/// PCAN-PCI interface, channel 3
/// </summary>
const PCAN_PCIBUS3: TPCANHandle = $43;
/// <summary>
/// PCAN-PCI interface, channel 4
/// </summary>
const PCAN_PCIBUS4: TPCANHandle = $44;
/// <summary>
/// PCAN-PCI interface, channel 5
/// </summary>
const PCAN_PCIBUS5: TPCANHandle = $45;
/// <summary>
/// PCAN-PCI interface, channel 6
/// </summary>
const PCAN_PCIBUS6: TPCANHandle = $46;
/// <summary>
/// PCAN-PCI interface, channel 7
/// </summary>
const PCAN_PCIBUS7: TPCANHandle = $47;
/// <summary>
/// PCAN-PCI interface, channel 8
/// </summary>
const PCAN_PCIBUS8: TPCANHandle = $48;
/// <summary>
/// PCAN-PCI interface, channel 9
/// </summary>
const PCAN_PCIBUS9: TPCANHandle = $409;
/// <summary>
/// PCAN-PCI interface, channel 10
/// </summary>
const PCAN_PCIBUS10: TPCANHandle = $40A;
/// <summary>
/// PCAN-PCI interface, channel 11
/// </summary>
const PCAN_PCIBUS11: TPCANHandle = $40B;
/// <summary>
/// PCAN-PCI interface, channel 12
/// </summary>
const PCAN_PCIBUS12: TPCANHandle = $40C;
/// <summary>
/// PCAN-PCI interface, channel 13
/// </summary>
const PCAN_PCIBUS13: TPCANHandle = $40D;
/// <summary>
/// PCAN-PCI interface, channel 14
/// </summary>
const PCAN_PCIBUS14: TPCANHandle = $40E;
/// <summary>
/// PCAN-PCI interface, channel 15
/// </summary>
const PCAN_PCIBUS15: TPCANHandle = $40F;
/// <summary>
/// PCAN-PCI interface, channel 16
/// </summary>
const PCAN_PCIBUS16: TPCANHandle = $410;
/// <summary>
/// PCAN-USB interface, channel 1
/// </summary>
const PCAN_USBBUS1: TPCANHandle = $51;
/// <summary>
/// PCAN-USB interface, channel 2
/// </summary>
const PCAN_USBBUS2: TPCANHandle = $52;
/// <summary>
/// PCAN-USB interface, channel 3
/// </summary>
const PCAN_USBBUS3: TPCANHandle = $53;
/// <summary>
/// PCAN-USB interface, channel 4
/// </summary>
const PCAN_USBBUS4: TPCANHandle = $54;
/// <summary>
/// PCAN-USB interface, channel 5
/// </summary>
const PCAN_USBBUS5: TPCANHandle = $55;
/// <summary>
/// PCAN-USB interface, channel 6
/// </summary>
const PCAN_USBBUS6: TPCANHandle = $56;
/// <summary>
/// PCAN-USB interface, channel 7
/// </summary>
const PCAN_USBBUS7: TPCANHandle = $57;
/// <summary>
/// PCAN-USB interface, channel 8
/// </summary>
const PCAN_USBBUS8: TPCANHandle = $58;
/// <summary>
/// PCAN-USB interface, channel 9
/// </summary>
const PCAN_USBBUS9: TPCANHandle = $509;
/// <summary>
/// PCAN-USB interface, channel 10
/// </summary>
const PCAN_USBBUS10: TPCANHandle = $50A;
/// <summary>
/// PCAN-USB interface, channel 11
/// </summary>
const PCAN_USBBUS11: TPCANHandle = $50B;
/// <summary>
/// PCAN-USB interface, channel 12
/// </summary>
const PCAN_USBBUS12: TPCANHandle = $50C;
/// <summary>
/// PCAN-USB interface, channel 13
/// </summary>
const PCAN_USBBUS13: TPCANHandle = $50D;
/// <summary>
/// PCAN-USB interface, channel 14
/// </summary>
const PCAN_USBBUS14: TPCANHandle = $50E;
/// <summary>
/// PCAN-USB interface, channel 15
/// </summary>
const PCAN_USBBUS15: TPCANHandle = $50F;
/// <summary>
/// PCAN-USB interface, channel 16
/// </summary>
const PCAN_USBBUS16: TPCANHandle = $510;
/// <summary>
/// PCAN-PC Card interface, channel 1
/// </summary>
const PCAN_PCCBUS1: TPCANHandle = $61;
/// <summary>
/// PCAN-PC Card interface, channel 2
/// </summary>
const PCAN_PCCBUS2: TPCANHandle = $62;
/// <summary>
/// PCAN-LAN interface, channel 1
/// </summary>
const PCAN_LANBUS1: TPCANHandle = $801;
/// <summary>
/// PCAN-LAN interface, channel 2
/// </summary>
const PCAN_LANBUS2: TPCANHandle = $802;
/// <summary>
/// PCAN-LAN interface, channel 3
/// </summary>
const PCAN_LANBUS3: TPCANHandle = $803;
/// <summary>
/// PCAN-LAN interface, channel 4
/// </summary>
const PCAN_LANBUS4: TPCANHandle = $804;
/// <summary>
/// PCAN-LAN interface, channel 5
/// </summary>
const PCAN_LANBUS5: TPCANHandle = $805;
/// <summary>
/// PCAN-LAN interface, channel 6
/// </summary>
const PCAN_LANBUS6: TPCANHandle = $806;
/// <summary>
/// PCAN-LAN interface, channel 7
/// </summary>
const PCAN_LANBUS7: TPCANHandle = $807;
/// <summary>
/// PCAN-LAN interface, channel 8
/// </summary>
const PCAN_LANBUS8: TPCANHandle = $808;
/// <summary>
/// PCAN-LAN interface, channel 9
/// </summary>
const PCAN_LANBUS9: TPCANHandle = $809;
/// <summary>
/// PCAN-LAN interface, channel 10
/// </summary>
const PCAN_LANBUS10: TPCANHandle = $80A;
/// <summary>
/// PCAN-LAN interface, channel 11
/// </summary>
const PCAN_LANBUS11: TPCANHandle = $80B;
/// <summary>
/// PCAN-LAN interface, channel 12
/// </summary>
const PCAN_LANBUS12: TPCANHandle = $80C;
/// <summary>
/// PCAN-LAN interface, channel 13
/// </summary>
const PCAN_LANBUS13: TPCANHandle = $80D;
/// <summary>
/// PCAN-LAN interface, channel 14
/// </summary>
const PCAN_LANBUS14: TPCANHandle = $80E;
/// <summary>
/// PCAN-LAN interface, channel 15
/// </summary>
const PCAN_LANBUS15: TPCANHandle = $80F;
/// <summary>
/// PCAN-LAN interface, channel 16
/// </summary>
const PCAN_LANBUS16: TPCANHandle = $810;
/// <summary>
/// Clock frequency in Herz (80000000, 60000000, 40000000, 30000000, 24000000, 20000000)
/// </summary>
const PCAN_BR_CLOCK: String = 'f_clock';
/// <summary>
/// Clock frequency in Megaherz (80, 60, 40, 30, 24, 20)
/// </summary>
const PCAN_BR_CLOCK_MHZ: String = 'f_clock_mhz';
/// <summary>
/// Clock prescaler for nominal time quantum
/// </summary>
const PCAN_BR_NOM_BRP: String = 'nom_brp';
/// <summary>
/// TSEG1 segment for nominal bit rate in time quanta
/// </summary>
const PCAN_BR_NOM_TSEG1: String = 'nom_tseg1';
/// <summary>
/// TSEG2 segment for nominal bit rate in time quanta
/// </summary>
const PCAN_BR_NOM_TSEG2: String = 'nom_tseg2';
/// <summary>
/// Synchronization Jump Width for nominal bit rate in time quanta
/// </summary>
const PCAN_BR_NOM_SJW: String = 'nom_sjw';
/// <summary>
/// Sample point for nominal bit rate
/// </summary>
const PCAN_BR_NOM_SAMPLE: String = 'nom_sam';
/// <summary>
/// Clock prescaler for highspeed data time quantum
/// </summary>
const PCAN_BR_DATA_BRP: String = 'data_brp';
/// <summary>
/// TSEG1 segment for fast data bit rate in time quanta
/// </summary>
const PCAN_BR_DATA_TSEG1: String = 'data_tseg1';
/// <summary>
/// TSEG2 segment for fast data bit rate in time quanta
/// </summary>
const PCAN_BR_DATA_TSEG2: String = 'data_tseg2';
/// <summary>
/// Synchronization Jump Width for highspeed data bit rate in time quanta
/// </summary>
const PCAN_BR_DATA_SJW: String = 'data_sjw';
/// <summary>
/// Secondary sample point delay for highspeed data bit rate in cyles
/// </summary>
const PCAN_BR_DATA_SAMPLE: String = 'data_ssp_offset';
/// <summary>
/// The PCAN parameter is not set (inactive)
/// </summary>
const PCAN_PARAMETER_OFF: Integer = 0;
/// <summary>
/// The PCAN parameter is set (active)
/// </summary>
const PCAN_PARAMETER_ON: Integer = 1;
/// <summary>
/// The PCAN filter is closed. No messages will be received
/// </summary>
const PCAN_FILTER_CLOSE: Integer = 0;
/// <summary>
/// The PCAN filter is fully opened. All messages will be received
/// </summary>
const PCAN_FILTER_OPEN: Integer = 1;
/// <summary>
/// The PCAN filter is custom configured. Only registered
/// messages will be received
/// </summary>
const PCAN_FILTER_CUSTOM: Integer = 2;
/// <summary>
/// The PCAN-Channel handle is illegal, or its associated hardware is not available
/// </summary>
const PCAN_CHANNEL_UNAVAILABLE: Integer = 0;
/// <summary>
/// The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
/// </summary>
const PCAN_CHANNEL_AVAILABLE: Integer = 1;
/// <summary>
/// The PCAN-Channel handle is valid, and is already being used
/// </summary>
const PCAN_CHANNEL_OCCUPIED: Integer = 2;
/// <summary>
/// The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
/// </summary>
const PCAN_CHANNEL_PCANVIEW: Integer = 3;
/// <summary>
/// Logs system exceptions / errors
/// </summary>
const LOG_FUNCTION_DEFAULT: Integer = $00;
/// <summary>
/// Logs the entries to the PCAN-Basic API functions
/// </summary>
const LOG_FUNCTION_ENTRY: Integer = $01;
/// <summary>
/// Logs the parameters passed to the PCAN-Basic API functions
/// </summary>
const LOG_FUNCTION_PARAMETERS: Integer = $02;
/// <summary>
/// Logs the exits from the PCAN-Basic API functions
/// </summary>
const LOG_FUNCTION_LEAVE: Integer = $04;
/// <summary>
/// Logs the CAN messages passed to the CAN_Write function
/// </summary>
const LOG_FUNCTION_WRITE: Integer = $08;
/// <summary>
/// Logs the CAN messages received within the CAN_Read function
/// </summary>
const LOG_FUNCTION_READ: Integer = $10;
/// <summary>
/// Logs all possible information within the PCAN-Basic API functions
/// </summary>
const LOG_FUNCTION_ALL: Integer = $FFFF;
/// <summary>
/// A single file is written until it size reaches PAN_TRACE_SIZE
/// </summary>
const TRACE_FILE_SINGLE: Integer = $00;
/// <summary>
/// Traced data is distributed in several files with size PAN_TRACE_SIZE
/// </summary>
const TRACE_FILE_SEGMENTED: Integer = $01;
/// <summary>
/// Includes the date into the name of the trace file
/// </summary>
const TRACE_FILE_DATE: Integer = $02;
/// <summary>
/// Includes the start time into the name of the trace file
/// </summary>
const TRACE_FILE_TIME: Integer = $04;
/// <summary>
/// Causes the overwriting of available traces (same name)
/// </summary>
const TRACE_FILE_OVERWRITE: Integer = $80;
/// <summary>
/// Device supports flexible data-rate (CAN-FD)
/// </summary>
const FEATURE_FD_CAPABLE: Integer = $01;
/// <summary>
/// Device supports a delay between sending frames (FPGA based USB devices)
/// </summary>
const FEATURE_DELAY_CAPABLE: Integer = $2;
/// <summary>
/// Device supports I/O functionality for electronic circuits (USB-Chip devices)
/// </summary>
const FEATURE_IO_CAPABLE: Integer = $4;
/// <summary>
/// The service is not running
/// </summary>
const SERVICE_STATUS_STOPPED: Integer = $01;
/// <summary>
/// The service is running
/// </summary>
const SERVICE_STATUS_RUNNING: Integer = $04;
/// <summary>
/// Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
/// </summary>
const LOOKUP_DEVICE_TYPE: String = 'devicetype';
/// <summary>
/// Lookup channel by device id
/// </summary>
const LOOKUP_DEVICE_ID: String = 'deviceid';
/// <summary>
/// Lookup channel by CAN controller 0-based index
/// </summary>
const LOOKUP_CONTROLLER_NUMBER: String = 'controllernumber';
/// <summary>
/// Lookup channel by IP address (LAN channels only)
/// </summary>
const LOOKUP_IP_ADDRESS: String = 'ipaddress';
/// <summary>
/// Maximum length of the name of a device: 32 characters + terminator
/// </summary>
const MAX_LENGTH_HARDWARE_NAME: Integer = 33;
/// <summary>
/// Maximum length of a version string: 255 characters + terminator
/// </summary>
const MAX_LENGTH_VERSION_STRING: Integer = 256;
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
/// <param name="HwType">Non-PnP: The type of hardware and operation mode</param>
/// <param name="IOPort">Non-PnP: The I/O address for the parallel port</param>
/// <param name="Interrupt">Non-PnP: Interrupt number of the parallel port</param>
/// <returns>A TPCANStatus error code</returns>
class function Initialize(
Channel: TPCANHandle;
Btr0Btr1: TPCANBaudrate;
HwType: TPCANType;
IOPort: LongWord;
Interrupt: Word
): TPCANStatus; overload;
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
/// <returns>A TPCANStatus error code</returns>
class function Initialize(
Channel: TPCANHandle;
Btr0Btr1: TPCANBaudrate
): TPCANStatus; overload;
/// <summary>
/// Initializes a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="BitrateFD">The speed for the communication (FD bit rate string)</param>
/// <remarks> See PCAN_BR_* values
/// Bit rate string must follow the following construction rules:
/// * parameter and values must be separated by '='
/// * Couples of Parameter/value must be separated by ','
/// * Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
/// nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
/// * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam</remarks>
/// <example>f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1</example>
/// <returns>A TPCANStatus error code</returns>
class function InitializeFD(
Channel: TPCANHandle;
BitrateFD: TPCANBitrateFD
): TPCANStatus;
/// <summary>
/// Uninitializes one or all PCAN Channels initialized by CAN_Initialize
/// </summary>
/// <remarks>Giving the TPCANHandle value "PCAN_NONEBUS",
/// uninitialize all initialized channels</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
class function Uninitialize(
Channel: TPCANHandle
): TPCANStatus;
/// <summary>
/// Resets the receive and transmit queues of the PCAN Channel
/// </summary>
/// <remarks>A reset of the CAN controller is not performed</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
class function Reset(
Channel: TPCANHandle
): TPCANStatus;
/// <summary>
/// Gets the current status of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
class function GetStatus(
Channel: TPCANHandle
): TPCANStatus;
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestamp structure buffer to get
/// the reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
class function Read(
Channel: TPCANHandle;
var MessageBuffer: TPCANMsg;
var TimestampBuffer: TPCANTimestamp
):TPCANStatus; overload;
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
/// <returns>A TPCANStatus error code</returns>
class function Read(
Channel: TPCANHandle;
var MessageBuffer: TPCANMsg
): TPCANStatus; overload;
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestampFD buffer to get the
/// reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
class function ReadFD(
Channel: TPCANHandle;
var MessageBuffer: TPCANMsgFD;
var TimestampBuffer: TPCANTimestampFD
):TPCANStatus; overload;
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
/// <returns>A TPCANStatus error code</returns>
class function ReadFD(
Channel: TPCANHandle;
var MessageBuffer: TPCANMsgFD
):TPCANStatus; overload;
/// <summary>
/// Transmits a CAN message
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg buffer with the message to be sent</param>
/// <returns>A TPCANStatus error code</returns>
class function Write(
Channel: TPCANHandle;
var MessageBuffer: TPCANMsg
): TPCANStatus;
/// <summary>
/// Transmits a CAN message over a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD buffer with the message to be sent</param>
/// <returns>A TPCANStatus error code</returns>
class function WriteFD(
Channel: TPCANHandle;
var MessageBuffer: TPCANMsgFD
): TPCANStatus;
/// <summary>
/// Configures the reception filter
/// </summary>
/// <remarks>The message filter will be expanded with every call to
/// this function. If it is desired to reset the filter, please use
/// the 'SetValue' function</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="FromID">The lowest CAN ID to be received</param>
/// <param name="ToID">The highest CAN ID to be received</param>
/// <param name="Mode">Message type, Standard (11-bit identifier) or
/// Extended (29-bit identifier)</param>
/// <returns>A TPCANStatus error code</returns>
class function FilterMessages(
Channel: TPCANHandle;
FromID: LongWord;
ToID: LongWord;
Mode: TPCANMode
): TPCANStatus;
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="NumericBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
class function GetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
NumericBuffer: PLongWord;
BufferLength: LongWord
): TPCANStatus; overload;
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="NumericBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
class function GetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
NumericBuffer: PUInt64;
BufferLength: LongWord
): TPCANStatus; overload;
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="StringBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
class function GetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
StringBuffer: PAnsiChar;
BufferLength: LongWord
): TPCANStatus; overload;
class function GetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
ChannelsBuffer: PTPCANChannelInformation;
BufferLength: LongWord
): TPCANStatus; overload;
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="NumericBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
class function SetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
NumericBuffer: PLongWord;
BufferLength: LongWord
): TPCANStatus; overload;
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="NumericBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
class function SetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
NumericBuffer: PUInt64;
BufferLength: LongWord
): TPCANStatus; overload;
/// <summary>
/// Configures or sets a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="StringBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
class function SetValue(
Channel: TPCANHandle;
Parameter: TPCANParameter;
StringBuffer: PAnsiChar;
BufferLength: LongWord
): TPCANStatus; overload;
/// <summary>
/// Returns a descriptive text of a given TPCANStatus error
/// code, in any desired language
/// </summary>
/// <remarks>The current languages available for translation are:
/// Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
/// Italian (0x10) and French (0x0C)</remarks>
/// <param name="Error">A TPCANStatus error code</param>
/// <param name="Language">Indicates a 'Primary language ID'</param>
/// <param name="StringBuffer">Buffer for the text (must be at least 256 in length)</param>
/// <returns>A TPCANStatus error code</returns>
class function GetErrorText(
Error: TPCANStatus;
Language: Word;
StringBuffer: PAnsiChar
): TPCANStatus;
/// <summary>
/// Finds a PCAN-Basic channel that matches with the given parameters
/// </summary>
/// <param name="Parameters">A comma separated string contained pairs of
/// parameter-name/value to be matched within a PCAN-Basic channel</param>
/// <param name="FoundChannel">Buffer for returning the PCAN-basic channel,
/// when found</param>
/// <returns>A TPCANStatus error code</returns>
class function LookUpChannel(
Parameters: PAnsiChar;
FoundChannel: PTPCANHandle
): TPCANStatus;
end;
implementation
uses SysUtils;
const DLL_Name = 'PCANBASIC.DLL';
function CAN_Initialize(Channel: TPCANHandle; Btr0Btr1: TPCANBaudrate; HwType: TPCANType; IOPort: LongWord; Interrupt: Word): TPCANStatus; stdcall;
external DLL_Name;
function CAN_InitializeFD(Channel: TPCANHandle; BitrateFD: TPCANBitrateFD): TPCANStatus; stdcall;
external DLL_Name;
function CAN_Uninitialize(Channel: TPCANHandle): TPCANStatus; stdcall;
external DLL_Name;
function CAN_Reset(Channel: TPCANHandle): TPCANStatus; stdcall;
external DLL_Name;
function CAN_GetStatus(Channel: TPCANHandle): TPCANStatus; stdcall;
external DLL_Name;
function CAN_Read(Channel: TPCANHandle; var MessageBuffer: TPCANMsg; TimestampBuffer: PTPCANTimestamp):TPCANStatus; overload; stdcall;
external DLL_Name;
function CAN_ReadFD(Channel: TPCANHandle; var MessageBuffer: TPCANMsgFD; TimestampBuffer: PUInt64):TPCANStatus; overload; stdcall;
external DLL_Name;
function CAN_Write(Channel: TPCANHandle; var MessageBuffer: TPCANMsg): TPCANStatus; stdcall;
external DLL_Name;
function CAN_WriteFD(Channel: TPCANHandle; var MessageBuffer: TPCANMsgFD): TPCANStatus; stdcall;
external DLL_Name;
function CAN_FilterMessages(Channel: TPCANHandle; FromID: LongWord; ToID: LongWord; Mode: TPCANMode): TPCANStatus; stdcall;
external DLL_Name;
function CAN_GetValue(Channel: TPCANHandle; Parameter: TPCANParameter; Buffer: Pointer; BufferLength: LongWord): TPCANStatus; stdcall;
external DLL_Name;
function CAN_SetValue(Channel: TPCANHandle; Parameter: TPCANParameter; Buffer: Pointer; BufferLength: LongWord): TPCANStatus; stdcall;
external DLL_Name;
function CAN_GetErrorText(Error: TPCANStatus; Language: Word; StringBuffer: PAnsiChar): TPCANStatus; stdcall;
external DLL_Name;
function CAN_LookUpChannel(Parameters: PAnsiChar; FoundChannel: PTPCANHandle): TPCANStatus; stdcall;
external DLL_Name;
class function TPCANBasic.Initialize(Channel: TPCANHandle; Btr0Btr1: TPCANBaudrate; HwType: TPCANType; IOPort: LongWord; Interrupt: Word): TPCANStatus;
begin
Result:= CAN_Initialize(Channel,Btr0Btr1,HwType,IOPort,Interrupt);
end;
class function TPCANBasic.Initialize(Channel: TPCANHandle; Btr0Btr1: TPCANBaudrate): TPCANStatus;
begin
Result:= CAN_Initialize(Channel,Btr0Btr1,PCAN_TYPE_ISA, 0,0);
end;
class function TPCANBasic.InitializeFD(Channel: TPCANHandle; BitrateFD: TPCANBitrateFD): TPCANStatus;
begin
Result:= CAN_InitializeFD(Channel,BitrateFD);
end;
class function TPCANBasic.Uninitialize(Channel: TPCANHandle): TPCANStatus;
begin
Result:= CAN_Uninitialize(Channel);
end;
class function TPCANBasic.Reset(Channel: TPCANHandle): TPCANStatus;
begin
Result:= CAN_Reset(Channel);
end;
class function TPCANBasic.GetStatus(Channel: TPCANHandle): TPCANStatus;
begin
Result:= CAN_GetStatus(Channel);
end;
class function TPCANBasic.Read(Channel: TPCANHandle; var MessageBuffer: TPCANMsg; var TimestampBuffer: TPCANTimestamp):TPCANStatus;
begin
Result:= CAN_Read(Channel, MessageBuffer, @TimestampBuffer);
end;
class function TPCANBasic.Read(Channel: TPCANHandle; var MessageBuffer: TPCANMsg):TPCANStatus;
begin
Result:= CAN_Read(Channel, MessageBuffer, nil);
end;
class function TPCANBasic.ReadFD(Channel: TPCANHandle; var MessageBuffer: TPCANMsgFD; var TimestampBuffer: TPCANTimestampFD):TPCANStatus;
begin
Result:= CAN_ReadFD(Channel, MessageBuffer, @TimestampBuffer);
end;
class function TPCANBasic.ReadFD(Channel: TPCANHandle; var MessageBuffer: TPCANMsgFD):TPCANStatus;
begin
Result:= CAN_ReadFD(Channel, MessageBuffer, nil);
end;
class function TPCANBasic.Write(Channel: TPCANHandle; var MessageBuffer: TPCANMsg): TPCANStatus;
begin
Result:= CAN_Write(Channel, MessageBuffer);
end;
class function TPCANBasic.WriteFD(Channel: TPCANHandle; var MessageBuffer: TPCANMsgFD): TPCANStatus;
begin
Result:= CAN_WriteFD(Channel, MessageBuffer);
end;
class function TPCANBasic.FilterMessages(Channel: TPCANHandle; FromID: LongWord; ToID: LongWord; Mode: TPCANMode): TPCANStatus;
begin
Result:= CAN_FilterMessages(Channel, FromID,ToID,Mode);
end;
class function TPCANBasic.GetValue(Channel: TPCANHandle; Parameter: TPCANParameter; NumericBuffer: PLongWord; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_GetValue(Channel, Parameter, NumericBuffer, BufferLength);
end;
class function TPCANBasic.GetValue(Channel: TPCANHandle; Parameter: TPCANParameter; NumericBuffer: PUInt64; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_GetValue(Channel, Parameter, NumericBuffer, BufferLength);
end;
class function TPCANBasic.GetValue(Channel: TPCANHandle; Parameter: TPCANParameter; StringBuffer: PAnsiChar; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_GetValue(Channel, Parameter, StringBuffer, BufferLength);
end;
class function TPCANBasic.GetValue(Channel: TPCANHandle; Parameter: TPCANParameter; ChannelsBuffer: PTPCANChannelInformation; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_GetValue(Channel, Parameter, ChannelsBuffer, BufferLength);
end;
class function TPCANBasic.SetValue(Channel: TPCANHandle; Parameter: TPCANParameter; NumericBuffer: PLongWord; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_SetValue(Channel, Parameter, NumericBuffer, BufferLength);
end;
class function TPCANBasic.SetValue(Channel: TPCANHandle; Parameter: TPCANParameter; NumericBuffer: PUInt64; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_SetValue(Channel, Parameter, NumericBuffer, BufferLength);
end;
class function TPCANBasic.SetValue(Channel: TPCANHandle; Parameter: TPCANParameter; StringBuffer: PAnsiChar; BufferLength: LongWord): TPCANStatus;
begin
Result:= CAN_SetValue(Channel, Parameter, StringBuffer, BufferLength);
end;
class function TPCANBasic.GetErrorText(Error: TPCANStatus; Language: Word; StringBuffer: PAnsiChar): TPCANStatus;
begin
Result:= CAN_GetErrorText(Error, Language, StringBuffer);
end;
class function TPCANBasic.LookUpChannel(Parameters: PAnsiChar; FoundChannel: PTPCANHandle): TPCANStatus;
begin
Result:= CAN_LookUpChannel(Parameters, FoundChannel);
end;
end.
\ No newline at end of file
# PCANBasic.py
#
# ~~~~~~~~~~~~
#
# PCAN-Basic API
#
# ~~~~~~~~~~~~
#
# ------------------------------------------------------------------
# Author : Keneth Wagner
# Last change: 2022-07-06
#
# Language: Python 2.7, 3.8
# ------------------------------------------------------------------
#
# Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
# more Info at http://www.peak-system.com
#
# Module Imports
#
from ctypes import *
from string import *
import platform
#///////////////////////////////////////////////////////////
# Type definitions
#///////////////////////////////////////////////////////////
TPCANHandle = c_ushort # Represents a PCAN hardware channel handle
TPCANStatus = int # Represents a PCAN status/error code
TPCANParameter = c_ubyte # Represents a PCAN parameter to be read or set
TPCANDevice = c_ubyte # Represents a PCAN device
TPCANMessageType = c_ubyte # Represents the type of a PCAN message
TPCANType = c_ubyte # Represents the type of PCAN hardware to be initialized
TPCANMode = c_ubyte # Represents a PCAN filter mode
TPCANBaudrate = c_ushort # Represents a PCAN Baud rate register value
TPCANBitrateFD = c_char_p # Represents a PCAN-FD bit rate string
TPCANTimestampFD = c_ulonglong # Represents a timestamp of a received PCAN FD message
#///////////////////////////////////////////////////////////
# Value definitions
#///////////////////////////////////////////////////////////
# Currently defined and supported PCAN channels
#
PCAN_NONEBUS = TPCANHandle(0x00) # Undefined/default value for a PCAN bus
PCAN_ISABUS1 = TPCANHandle(0x21) # PCAN-ISA interface, channel 1
PCAN_ISABUS2 = TPCANHandle(0x22) # PCAN-ISA interface, channel 2
PCAN_ISABUS3 = TPCANHandle(0x23) # PCAN-ISA interface, channel 3
PCAN_ISABUS4 = TPCANHandle(0x24) # PCAN-ISA interface, channel 4
PCAN_ISABUS5 = TPCANHandle(0x25) # PCAN-ISA interface, channel 5
PCAN_ISABUS6 = TPCANHandle(0x26) # PCAN-ISA interface, channel 6
PCAN_ISABUS7 = TPCANHandle(0x27) # PCAN-ISA interface, channel 7
PCAN_ISABUS8 = TPCANHandle(0x28) # PCAN-ISA interface, channel 8
PCAN_DNGBUS1 = TPCANHandle(0x31) # PCAN-Dongle/LPT interface, channel 1
PCAN_PCIBUS1 = TPCANHandle(0x41) # PCAN-PCI interface, channel 1
PCAN_PCIBUS2 = TPCANHandle(0x42) # PCAN-PCI interface, channel 2
PCAN_PCIBUS3 = TPCANHandle(0x43) # PCAN-PCI interface, channel 3
PCAN_PCIBUS4 = TPCANHandle(0x44) # PCAN-PCI interface, channel 4
PCAN_PCIBUS5 = TPCANHandle(0x45) # PCAN-PCI interface, channel 5
PCAN_PCIBUS6 = TPCANHandle(0x46) # PCAN-PCI interface, channel 6
PCAN_PCIBUS7 = TPCANHandle(0x47) # PCAN-PCI interface, channel 7
PCAN_PCIBUS8 = TPCANHandle(0x48) # PCAN-PCI interface, channel 8
PCAN_PCIBUS9 = TPCANHandle(0x409) # PCAN-PCI interface, channel 9
PCAN_PCIBUS10 = TPCANHandle(0x40A) # PCAN-PCI interface, channel 10
PCAN_PCIBUS11 = TPCANHandle(0x40B) # PCAN-PCI interface, channel 11
PCAN_PCIBUS12 = TPCANHandle(0x40C) # PCAN-PCI interface, channel 12
PCAN_PCIBUS13 = TPCANHandle(0x40D) # PCAN-PCI interface, channel 13
PCAN_PCIBUS14 = TPCANHandle(0x40E) # PCAN-PCI interface, channel 14
PCAN_PCIBUS15 = TPCANHandle(0x40F) # PCAN-PCI interface, channel 15
PCAN_PCIBUS16 = TPCANHandle(0x410) # PCAN-PCI interface, channel 16
PCAN_USBBUS1 = TPCANHandle(0x51) # PCAN-USB interface, channel 1
PCAN_USBBUS2 = TPCANHandle(0x52) # PCAN-USB interface, channel 2
PCAN_USBBUS3 = TPCANHandle(0x53) # PCAN-USB interface, channel 3
PCAN_USBBUS4 = TPCANHandle(0x54) # PCAN-USB interface, channel 4
PCAN_USBBUS5 = TPCANHandle(0x55) # PCAN-USB interface, channel 5
PCAN_USBBUS6 = TPCANHandle(0x56) # PCAN-USB interface, channel 6
PCAN_USBBUS7 = TPCANHandle(0x57) # PCAN-USB interface, channel 7
PCAN_USBBUS8 = TPCANHandle(0x58) # PCAN-USB interface, channel 8
PCAN_USBBUS9 = TPCANHandle(0x509) # PCAN-USB interface, channel 9
PCAN_USBBUS10 = TPCANHandle(0x50A) # PCAN-USB interface, channel 10
PCAN_USBBUS11 = TPCANHandle(0x50B) # PCAN-USB interface, channel 11
PCAN_USBBUS12 = TPCANHandle(0x50C) # PCAN-USB interface, channel 12
PCAN_USBBUS13 = TPCANHandle(0x50D) # PCAN-USB interface, channel 13
PCAN_USBBUS14 = TPCANHandle(0x50E) # PCAN-USB interface, channel 14
PCAN_USBBUS15 = TPCANHandle(0x50F) # PCAN-USB interface, channel 15
PCAN_USBBUS16 = TPCANHandle(0x510) # PCAN-USB interface, channel 16
PCAN_PCCBUS1 = TPCANHandle(0x61) # PCAN-PC Card interface, channel 1
PCAN_PCCBUS2 = TPCANHandle(0x62) # PCAN-PC Card interface, channel 2
PCAN_LANBUS1 = TPCANHandle(0x801) # PCAN-LAN interface, channel 1
PCAN_LANBUS2 = TPCANHandle(0x802) # PCAN-LAN interface, channel 2
PCAN_LANBUS3 = TPCANHandle(0x803) # PCAN-LAN interface, channel 3
PCAN_LANBUS4 = TPCANHandle(0x804) # PCAN-LAN interface, channel 4
PCAN_LANBUS5 = TPCANHandle(0x805) # PCAN-LAN interface, channel 5
PCAN_LANBUS6 = TPCANHandle(0x806) # PCAN-LAN interface, channel 6
PCAN_LANBUS7 = TPCANHandle(0x807) # PCAN-LAN interface, channel 7
PCAN_LANBUS8 = TPCANHandle(0x808) # PCAN-LAN interface, channel 8
PCAN_LANBUS9 = TPCANHandle(0x809) # PCAN-LAN interface, channel 9
PCAN_LANBUS10 = TPCANHandle(0x80A) # PCAN-LAN interface, channel 10
PCAN_LANBUS11 = TPCANHandle(0x80B) # PCAN-LAN interface, channel 11
PCAN_LANBUS12 = TPCANHandle(0x80C) # PCAN-LAN interface, channel 12
PCAN_LANBUS13 = TPCANHandle(0x80D) # PCAN-LAN interface, channel 13
PCAN_LANBUS14 = TPCANHandle(0x80E) # PCAN-LAN interface, channel 14
PCAN_LANBUS15 = TPCANHandle(0x80F) # PCAN-LAN interface, channel 15
PCAN_LANBUS16 = TPCANHandle(0x810) # PCAN-LAN interface, channel 16
# Represent the PCAN error and status codes
#
PCAN_ERROR_OK = TPCANStatus(0x00000) # No error
PCAN_ERROR_XMTFULL = TPCANStatus(0x00001) # Transmit buffer in CAN controller is full
PCAN_ERROR_OVERRUN = TPCANStatus(0x00002) # CAN controller was read too late
PCAN_ERROR_BUSLIGHT = TPCANStatus(0x00004) # Bus error: an error counter reached the 'light' limit
PCAN_ERROR_BUSHEAVY = TPCANStatus(0x00008) # Bus error: an error counter reached the 'heavy' limit
PCAN_ERROR_BUSWARNING = TPCANStatus(PCAN_ERROR_BUSHEAVY) # Bus error: an error counter reached the 'warning' limit
PCAN_ERROR_BUSPASSIVE = TPCANStatus(0x40000) # Bus error: the CAN controller is error passive
PCAN_ERROR_BUSOFF = TPCANStatus(0x00010) # Bus error: the CAN controller is in bus-off state
PCAN_ERROR_ANYBUSERR = TPCANStatus(PCAN_ERROR_BUSWARNING | PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY | PCAN_ERROR_BUSOFF | PCAN_ERROR_BUSPASSIVE) # Mask for all bus errors
PCAN_ERROR_QRCVEMPTY = TPCANStatus(0x00020) # Receive queue is empty
PCAN_ERROR_QOVERRUN = TPCANStatus(0x00040) # Receive queue was read too late
PCAN_ERROR_QXMTFULL = TPCANStatus(0x00080) # Transmit queue is full
PCAN_ERROR_REGTEST = TPCANStatus(0x00100) # Test of the CAN controller hardware registers failed (no hardware found)
PCAN_ERROR_NODRIVER = TPCANStatus(0x00200) # Driver not loaded
PCAN_ERROR_HWINUSE = TPCANStatus(0x00400) # Hardware already in use by a Net
PCAN_ERROR_NETINUSE = TPCANStatus(0x00800) # A Client is already connected to the Net
PCAN_ERROR_ILLHW = TPCANStatus(0x01400) # Hardware handle is invalid
PCAN_ERROR_ILLNET = TPCANStatus(0x01800) # Net handle is invalid
PCAN_ERROR_ILLCLIENT = TPCANStatus(0x01C00) # Client handle is invalid
PCAN_ERROR_ILLHANDLE = TPCANStatus(PCAN_ERROR_ILLHW | PCAN_ERROR_ILLNET | PCAN_ERROR_ILLCLIENT) # Mask for all handle errors
PCAN_ERROR_RESOURCE = TPCANStatus(0x02000) # Resource (FIFO, Client, timeout) cannot be created
PCAN_ERROR_ILLPARAMTYPE = TPCANStatus(0x04000) # Invalid parameter
PCAN_ERROR_ILLPARAMVAL = TPCANStatus(0x08000) # Invalid parameter value
PCAN_ERROR_UNKNOWN = TPCANStatus(0x10000) # Unknown error
PCAN_ERROR_ILLDATA = TPCANStatus(0x20000) # Invalid data, function, or action
PCAN_ERROR_ILLMODE = TPCANStatus(0x80000) # Driver object state is wrong for the attempted operation
PCAN_ERROR_CAUTION = TPCANStatus(0x2000000)# An operation was successfully carried out, however, irregularities were registered
PCAN_ERROR_INITIALIZE = TPCANStatus(0x4000000)# Channel is not initialized [Value was changed from 0x40000 to 0x4000000]
PCAN_ERROR_ILLOPERATION = TPCANStatus(0x8000000)# Invalid operation [Value was changed from 0x80000 to 0x8000000]
# PCAN devices
#
PCAN_NONE = TPCANDevice(0x00) # Undefined, unknown or not selected PCAN device value
PCAN_PEAKCAN = TPCANDevice(0x01) # PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
PCAN_ISA = TPCANDevice(0x02) # PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
PCAN_DNG = TPCANDevice(0x03) # PCAN-Dongle
PCAN_PCI = TPCANDevice(0x04) # PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
PCAN_USB = TPCANDevice(0x05) # PCAN-USB and PCAN-USB Pro
PCAN_PCC = TPCANDevice(0x06) # PCAN-PC Card
PCAN_VIRTUAL = TPCANDevice(0x07) # PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
PCAN_LAN = TPCANDevice(0x08) # PCAN Gateway devices
# PCAN parameters
#
PCAN_DEVICE_ID = TPCANParameter(0x01) # Device identifier parameter
PCAN_5VOLTS_POWER = TPCANParameter(0x02) # 5-Volt power parameter
PCAN_RECEIVE_EVENT = TPCANParameter(0x03) # PCAN receive event handler parameter
PCAN_MESSAGE_FILTER = TPCANParameter(0x04) # PCAN message filter parameter
PCAN_API_VERSION = TPCANParameter(0x05) # PCAN-Basic API version parameter
PCAN_CHANNEL_VERSION = TPCANParameter(0x06) # PCAN device channel version parameter
PCAN_BUSOFF_AUTORESET = TPCANParameter(0x07) # PCAN Reset-On-Busoff parameter
PCAN_LISTEN_ONLY = TPCANParameter(0x08) # PCAN Listen-Only parameter
PCAN_LOG_LOCATION = TPCANParameter(0x09) # Directory path for log files
PCAN_LOG_STATUS = TPCANParameter(0x0A) # Debug-Log activation status
PCAN_LOG_CONFIGURE = TPCANParameter(0x0B) # Configuration of the debugged information (LOG_FUNCTION_***)
PCAN_LOG_TEXT = TPCANParameter(0x0C) # Custom insertion of text into the log file
PCAN_CHANNEL_CONDITION = TPCANParameter(0x0D) # Availability status of a PCAN-Channel
PCAN_HARDWARE_NAME = TPCANParameter(0x0E) # PCAN hardware name parameter
PCAN_RECEIVE_STATUS = TPCANParameter(0x0F) # Message reception status of a PCAN-Channel
PCAN_CONTROLLER_NUMBER = TPCANParameter(0x10) # CAN-Controller number of a PCAN-Channel
PCAN_TRACE_LOCATION = TPCANParameter(0x11) # Directory path for PCAN trace files
PCAN_TRACE_STATUS = TPCANParameter(0x12) # CAN tracing activation status
PCAN_TRACE_SIZE = TPCANParameter(0x13) # Configuration of the maximum file size of a CAN trace
PCAN_TRACE_CONFIGURE = TPCANParameter(0x14) # Configuration of the trace file storing mode (TRACE_FILE_***)
PCAN_CHANNEL_IDENTIFYING = TPCANParameter(0x15) # Physical identification of a USB based PCAN-Channel by blinking its associated LED
PCAN_CHANNEL_FEATURES = TPCANParameter(0x16) # Capabilities of a PCAN device (FEATURE_***)
PCAN_BITRATE_ADAPTING = TPCANParameter(0x17) # Using of an existing bit rate (PCAN-View connected to a channel)
PCAN_BITRATE_INFO = TPCANParameter(0x18) # Configured bit rate as Btr0Btr1 value
PCAN_BITRATE_INFO_FD = TPCANParameter(0x19) # Configured bit rate as TPCANBitrateFD string
PCAN_BUSSPEED_NOMINAL = TPCANParameter(0x1A) # Configured nominal CAN Bus speed as Bits per seconds
PCAN_BUSSPEED_DATA = TPCANParameter(0x1B) # Configured CAN data speed as Bits per seconds
PCAN_IP_ADDRESS = TPCANParameter(0x1C) # Remote address of a LAN channel as string in IPv4 format
PCAN_LAN_SERVICE_STATUS = TPCANParameter(0x1D) # Status of the Virtual PCAN-Gateway Service
PCAN_ALLOW_STATUS_FRAMES = TPCANParameter(0x1E) # Status messages reception status within a PCAN-Channel
PCAN_ALLOW_RTR_FRAMES = TPCANParameter(0x1F) # RTR messages reception status within a PCAN-Channel
PCAN_ALLOW_ERROR_FRAMES = TPCANParameter(0x20) # Error messages reception status within a PCAN-Channel
PCAN_INTERFRAME_DELAY = TPCANParameter(0x21) # Delay, in microseconds, between sending frames
PCAN_ACCEPTANCE_FILTER_11BIT = TPCANParameter(0x22) # Filter over code and mask patterns for 11-Bit messages
PCAN_ACCEPTANCE_FILTER_29BIT = TPCANParameter(0x23) # Filter over code and mask patterns for 29-Bit messages
PCAN_IO_DIGITAL_CONFIGURATION = TPCANParameter(0x24) # Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
PCAN_IO_DIGITAL_VALUE = TPCANParameter(0x25) # Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
PCAN_IO_DIGITAL_SET = TPCANParameter(0x26) # Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
PCAN_IO_DIGITAL_CLEAR = TPCANParameter(0x27) # Clear multiple digital I/O pins to 0
PCAN_IO_ANALOG_VALUE = TPCANParameter(0x28) # Get value of a single analog input pin
PCAN_FIRMWARE_VERSION = TPCANParameter(0x29) # Get the version of the firmware used by the device associated with a PCAN-Channel
PCAN_ATTACHED_CHANNELS_COUNT = TPCANParameter(0x2A) # Get the amount of PCAN channels attached to a system
PCAN_ATTACHED_CHANNELS = TPCANParameter(0x2B) # Get information about PCAN channels attached to a system
PCAN_ALLOW_ECHO_FRAMES = TPCANParameter(0x2C) # Echo messages reception status within a PCAN-Channel
PCAN_DEVICE_PART_NUMBER = TPCANParameter(0x2D) # Get the part number associated to a device
# DEPRECATED parameters
#
PCAN_DEVICE_NUMBER = PCAN_DEVICE_ID # DEPRECATED. Use PCAN_DEVICE_ID instead
# PCAN parameter values
#
PCAN_PARAMETER_OFF = int(0x00) # The PCAN parameter is not set (inactive)
PCAN_PARAMETER_ON = int(0x01) # The PCAN parameter is set (active)
PCAN_FILTER_CLOSE = int(0x00) # The PCAN filter is closed. No messages will be received
PCAN_FILTER_OPEN = int(0x01) # The PCAN filter is fully opened. All messages will be received
PCAN_FILTER_CUSTOM = int(0x02) # The PCAN filter is custom configured. Only registered messages will be received
PCAN_CHANNEL_UNAVAILABLE = int(0x00) # The PCAN-Channel handle is illegal, or its associated hardware is not available
PCAN_CHANNEL_AVAILABLE = int(0x01) # The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
PCAN_CHANNEL_OCCUPIED = int(0x02) # The PCAN-Channel handle is valid, and is already being used
PCAN_CHANNEL_PCANVIEW = PCAN_CHANNEL_AVAILABLE | PCAN_CHANNEL_OCCUPIED # The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
LOG_FUNCTION_DEFAULT = int(0x00) # Logs system exceptions / errors
LOG_FUNCTION_ENTRY = int(0x01) # Logs the entries to the PCAN-Basic API functions
LOG_FUNCTION_PARAMETERS = int(0x02) # Logs the parameters passed to the PCAN-Basic API functions
LOG_FUNCTION_LEAVE = int(0x04) # Logs the exits from the PCAN-Basic API functions
LOG_FUNCTION_WRITE = int(0x08) # Logs the CAN messages passed to the CAN_Write function
LOG_FUNCTION_READ = int(0x10) # Logs the CAN messages received within the CAN_Read function
LOG_FUNCTION_ALL = int(0xFFFF) # Logs all possible information within the PCAN-Basic API functions
TRACE_FILE_SINGLE = int(0x00) # A single file is written until it size reaches PAN_TRACE_SIZE
TRACE_FILE_SEGMENTED = int(0x01) # Traced data is distributed in several files with size PAN_TRACE_SIZE
TRACE_FILE_DATE = int(0x02) # Includes the date into the name of the trace file
TRACE_FILE_TIME = int(0x04) # Includes the start time into the name of the trace file
TRACE_FILE_OVERWRITE = int(0x80) # Causes the overwriting of available traces (same name)
FEATURE_FD_CAPABLE = int(0x01) # Device supports flexible data-rate (CAN-FD)
FEATURE_DELAY_CAPABLE = int(0x02) # Device supports a delay between sending frames (FPGA based USB devices)
FEATURE_IO_CAPABLE = int(0x04) # Device supports I/O functionality for electronic circuits (USB-Chip devices)
SERVICE_STATUS_STOPPED = int(0x01) # The service is not running
SERVICE_STATUS_RUNNING = int(0x04) # The service is running
# Other constants
#
MAX_LENGTH_HARDWARE_NAME = int(33) # Maximum length of the name of a device: 32 characters + terminator
MAX_LENGTH_VERSION_STRING = int(256) # Maximum length of a version string: 255 characters + terminator
# PCAN message types
#
PCAN_MESSAGE_STANDARD = TPCANMessageType(0x00) # The PCAN message is a CAN Standard Frame (11-bit identifier)
PCAN_MESSAGE_RTR = TPCANMessageType(0x01) # The PCAN message is a CAN Remote-Transfer-Request Frame
PCAN_MESSAGE_EXTENDED = TPCANMessageType(0x02) # The PCAN message is a CAN Extended Frame (29-bit identifier)
PCAN_MESSAGE_FD = TPCANMessageType(0x04) # The PCAN message represents a FD frame in terms of CiA Specs
PCAN_MESSAGE_BRS = TPCANMessageType(0x08) # The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
PCAN_MESSAGE_ESI = TPCANMessageType(0x10) # The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
PCAN_MESSAGE_ECHO = TPCANMessageType(0x20) # The PCAN message represents an echo CAN Frame
PCAN_MESSAGE_ERRFRAME = TPCANMessageType(0x40) # The PCAN message represents an error frame
PCAN_MESSAGE_STATUS = TPCANMessageType(0x80) # The PCAN message represents a PCAN status message
# LookUp Parameters
#
LOOKUP_DEVICE_TYPE = b"devicetype" # Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
LOOKUP_DEVICE_ID = b"deviceid" # Lookup channel by device id
LOOKUP_CONTROLLER_NUMBER = b"controllernumber" # Lookup channel by CAN controller 0-based index
LOOKUP_IP_ADDRESS = b"ipaddress" # Lookup channel by IP address (LAN channels only)
# Frame Type / Initialization Mode
#
PCAN_MODE_STANDARD = PCAN_MESSAGE_STANDARD
PCAN_MODE_EXTENDED = PCAN_MESSAGE_EXTENDED
# Baud rate codes = BTR0/BTR1 register values for the CAN controller.
# You can define your own Baud rate with the BTROBTR1 register.
# Take a look at www.peak-system.com for our free software "BAUDTOOL"
# to calculate the BTROBTR1 register for every bit rate and sample point.
#
PCAN_BAUD_1M = TPCANBaudrate(0x0014) # 1 MBit/s
PCAN_BAUD_800K = TPCANBaudrate(0x0016) # 800 kBit/s
PCAN_BAUD_500K = TPCANBaudrate(0x001C) # 500 kBit/s
PCAN_BAUD_250K = TPCANBaudrate(0x011C) # 250 kBit/s
PCAN_BAUD_125K = TPCANBaudrate(0x031C) # 125 kBit/s
PCAN_BAUD_100K = TPCANBaudrate(0x432F) # 100 kBit/s
PCAN_BAUD_95K = TPCANBaudrate(0xC34E) # 95,238 kBit/s
PCAN_BAUD_83K = TPCANBaudrate(0x852B) # 83,333 kBit/s
PCAN_BAUD_50K = TPCANBaudrate(0x472F) # 50 kBit/s
PCAN_BAUD_47K = TPCANBaudrate(0x1414) # 47,619 kBit/s
PCAN_BAUD_33K = TPCANBaudrate(0x8B2F) # 33,333 kBit/s
PCAN_BAUD_20K = TPCANBaudrate(0x532F) # 20 kBit/s
PCAN_BAUD_10K = TPCANBaudrate(0x672F) # 10 kBit/s
PCAN_BAUD_5K = TPCANBaudrate(0x7F7F) # 5 kBit/s
# Represents the configuration for a CAN bit rate
# Note:
# * Each parameter and its value must be separated with a '='.
# * Each pair of parameter/value must be separated using ','.
#
# Example:
# f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
#
PCAN_BR_CLOCK = TPCANBitrateFD(b"f_clock")
PCAN_BR_CLOCK_MHZ = TPCANBitrateFD(b"f_clock_mhz")
PCAN_BR_NOM_BRP = TPCANBitrateFD(b"nom_brp")
PCAN_BR_NOM_TSEG1 = TPCANBitrateFD(b"nom_tseg1")
PCAN_BR_NOM_TSEG2 = TPCANBitrateFD(b"nom_tseg2")
PCAN_BR_NOM_SJW = TPCANBitrateFD(b"nom_sjw")
PCAN_BR_NOM_SAMPLE = TPCANBitrateFD(b"nom_sam")
PCAN_BR_DATA_BRP = TPCANBitrateFD(b"data_brp")
PCAN_BR_DATA_TSEG1 = TPCANBitrateFD(b"data_tseg1")
PCAN_BR_DATA_TSEG2 = TPCANBitrateFD(b"data_tseg2")
PCAN_BR_DATA_SJW = TPCANBitrateFD(b"data_sjw")
PCAN_BR_DATA_SAMPLE = TPCANBitrateFD(b"data_ssp_offset")
# Supported Non-PnP Hardware types
#
PCAN_TYPE_ISA = TPCANType(0x01) # PCAN-ISA 82C200
PCAN_TYPE_ISA_SJA = TPCANType(0x09) # PCAN-ISA SJA1000
PCAN_TYPE_ISA_PHYTEC = TPCANType(0x04) # PHYTEC ISA
PCAN_TYPE_DNG = TPCANType(0x02) # PCAN-Dongle 82C200
PCAN_TYPE_DNG_EPP = TPCANType(0x03) # PCAN-Dongle EPP 82C200
PCAN_TYPE_DNG_SJA = TPCANType(0x05) # PCAN-Dongle SJA1000
PCAN_TYPE_DNG_SJA_EPP = TPCANType(0x06) # PCAN-Dongle EPP SJA1000
# Represents a PCAN message
#
class TPCANMsg (Structure):
"""
Represents a PCAN message
"""
_fields_ = [ ("ID", c_uint), # 11/29-bit message identifier
("MSGTYPE", TPCANMessageType), # Type of the message
("LEN", c_ubyte), # Data Length Code of the message (0..8)
("DATA", c_ubyte * 8) ] # Data of the message (DATA[0]..DATA[7])
# Represents a timestamp of a received PCAN message
# Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
#
class TPCANTimestamp (Structure):
"""
Represents a timestamp of a received PCAN message
Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
"""
_fields_ = [ ("millis", c_uint), # Base-value: milliseconds: 0.. 2^32-1
("millis_overflow", c_ushort), # Roll-arounds of millis
("micros", c_ushort) ] # Microseconds: 0..999
# Represents a PCAN message from a FD capable hardware
#
class TPCANMsgFD (Structure):
"""
Represents a PCAN message
"""
_fields_ = [ ("ID", c_uint), # 11/29-bit message identifier
("MSGTYPE", TPCANMessageType), # Type of the message
("DLC", c_ubyte), # Data Length Code of the message (0..15)
("DATA", c_ubyte * 64) ] # Data of the message (DATA[0]..DATA[63])
# Describes an available PCAN channel
#
class TPCANChannelInformation (Structure):
"""
Describes an available PCAN channel
"""
_fields_ = [ ("channel_handle", TPCANHandle), # PCAN channel handle
("device_type", TPCANDevice), # Kind of PCAN device
("controller_number", c_ubyte), # CAN-Controller number
("device_features", c_uint), # Device capabilities flag (see FEATURE_*)
("device_name", c_char * MAX_LENGTH_HARDWARE_NAME), # Device name
("device_id", c_uint), # Device number
("channel_condition", c_uint) ] # Availability status of a PCAN-Channel
#///////////////////////////////////////////////////////////
# PCAN-Basic API function declarations
#///////////////////////////////////////////////////////////
# PCAN-Basic API class implementation
#
class PCANBasic:
"""
PCAN-Basic API class implementation
"""
def __init__(self):
# Loads the PCANBasic API
#
if platform.system() == 'Windows':
# Loads the API on Windows
self.__m_dllBasic = windll.LoadLibrary("PCANBasic")
elif platform.system() == 'Linux':
# Loads the API on Linux
self.__m_dllBasic = cdll.LoadLibrary("libpcanbasic.so")
elif platform.system() == 'Darwin':
# Loads the API on Mac
#
# NOTE:
# ~~~~~
# The macOS library for PCAN-USB interfaces from PEAK-System, PCBUSB library,
# is a third-party software creaded and mantained by the MacCAN project. For
# information and support, please contact MacCAN (info@mac-can).
#
self.__m_dllBasic = cdll.LoadLibrary("libPCBUSB.dylib")
if self.__m_dllBasic == None:
print ("Exception: The PCAN-Basic DLL couldn't be loaded!")
# Initializes a PCAN Channel
#
def Initialize(
self,
Channel,
Btr0Btr1,
HwType = TPCANType(0),
IOPort = c_uint(0),
Interrupt = c_ushort(0)):
"""
Initializes a PCAN Channel
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Btr0Btr1 : The speed for the communication (BTR0BTR1 code)
HwType : Non-PnP: The type of hardware and operation mode
IOPort : Non-PnP: The I/O address for the parallel port
Interrupt: Non-PnP: Interrupt number of the parallel port
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_Initialize(Channel,Btr0Btr1,HwType,IOPort,Interrupt)
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.Initialize")
raise
# Initializes a FD capable PCAN Channel
#
def InitializeFD(
self,
Channel,
BitrateFD):
"""
Initializes a FD capable PCAN Channel
Parameters:
Channel : The handle of a FD capable PCAN Channel
BitrateFD : The speed for the communication (FD bit rate string)
Remarks:
See PCAN_BR_* values.
* parameter and values must be separated by '='
* Couples of Parameter/value must be separated by ','
* Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
* Following Parameters are optional (not used yet): data_ssp_offset, nom_sam
Example:
f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_InitializeFD(Channel,BitrateFD)
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.InitializeFD")
raise
# Uninitializes one or all PCAN Channels initialized by CAN_Initialize
#
def Uninitialize(
self,
Channel):
"""
Uninitializes one or all PCAN Channels initialized by CAN_Initialize
Remarks:
Giving the TPCANHandle value "PCAN_NONEBUS", uninitialize all initialized channels
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_Uninitialize(Channel)
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.Uninitialize")
raise
# Resets the receive and transmit queues of the PCAN Channel
#
def Reset(
self,
Channel):
"""
Resets the receive and transmit queues of the PCAN Channel
Remarks:
A reset of the CAN controller is not performed
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_Reset(Channel)
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.Reset")
raise
# Gets the current status of a PCAN Channel
#
def GetStatus(
self,
Channel):
"""
Gets the current status of a PCAN Channel
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_GetStatus(Channel)
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.GetStatus")
raise
# Reads a CAN message from the receive queue of a PCAN Channel
#
def Read(
self,
Channel):
"""
Reads a CAN message from the receive queue of a PCAN Channel
Remarks:
The return value of this method is a 3-touple, where
the first value is the result (TPCANStatus) of the method.
The order of the values are:
[0]: A TPCANStatus error code
[1]: A TPCANMsg structure with the CAN message read
[2]: A TPCANTimestamp structure with the time when a message was read
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A touple with three values
"""
try:
msg = TPCANMsg()
timestamp = TPCANTimestamp()
res = self.__m_dllBasic.CAN_Read(Channel,byref(msg),byref(timestamp))
return TPCANStatus(res),msg,timestamp
except:
print ("Exception on PCANBasic.Read")
raise
# Reads a CAN message from the receive queue of a FD capable PCAN Channel
#
def ReadFD(
self,
Channel):
"""
Reads a CAN message from the receive queue of a FD capable PCAN Channel
Remarks:
The return value of this method is a 3-touple, where
the first value is the result (TPCANStatus) of the method.
The order of the values are:
[0]: A TPCANStatus error code
[1]: A TPCANMsgFD structure with the CAN message read
[2]: A TPCANTimestampFD that is the time when a message was read
Parameters:
Channel : The handle of a FD capable PCAN Channel
Returns:
A touple with three values
"""
try:
msg = TPCANMsgFD()
timestamp = TPCANTimestampFD()
res = self.__m_dllBasic.CAN_ReadFD(Channel,byref(msg),byref(timestamp))
return TPCANStatus(res),msg,timestamp
except:
print ("Exception on PCANBasic.ReadFD")
raise
# Transmits a CAN message
#
def Write(
self,
Channel,
MessageBuffer):
"""
Transmits a CAN message
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
MessageBuffer: A TPCANMsg representing the CAN message to be sent
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_Write(Channel,byref(MessageBuffer))
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.Write")
raise
# Transmits a CAN message over a FD capable PCAN Channel
#
def WriteFD(
self,
Channel,
MessageBuffer):
"""
Transmits a CAN message over a FD capable PCAN Channel
Parameters:
Channel : The handle of a FD capable PCAN Channel
MessageBuffer: A TPCANMsgFD buffer with the message to be sent
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_WriteFD(Channel,byref(MessageBuffer))
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.WriteFD")
raise
# Configures the reception filter
#
def FilterMessages(
self,
Channel,
FromID,
ToID,
Mode):
"""
Configures the reception filter
Remarks:
The message filter will be expanded with every call to this function.
If it is desired to reset the filter, please use the 'SetValue' function.
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
FromID : A c_uint value with the lowest CAN ID to be received
ToID : A c_uint value with the highest CAN ID to be received
Mode : A TPCANMode representing the message type (Standard, 11-bit
identifier, or Extended, 29-bit identifier)
Returns:
A TPCANStatus error code
"""
try:
res = self.__m_dllBasic.CAN_FilterMessages(Channel,FromID,ToID,Mode)
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.FilterMessages")
raise
# Retrieves a PCAN Channel value
#
def GetValue(
self,
Channel,
Parameter):
"""
Retrieves a PCAN Channel value
Remarks:
Parameters can be present or not according with the kind
of Hardware (PCAN Channel) being used. If a parameter is not available,
a PCAN_ERROR_ILLPARAMTYPE error will be returned.
The return value of this method is a 2-touple, where
the first value is the result (TPCANStatus) of the method and
the second one, the asked value
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Parameter : The TPCANParameter parameter to get
Returns:
A touple with 2 values
"""
try:
if Parameter == PCAN_API_VERSION or Parameter == PCAN_HARDWARE_NAME or Parameter == PCAN_CHANNEL_VERSION or Parameter == PCAN_LOG_LOCATION or Parameter == PCAN_TRACE_LOCATION or Parameter == PCAN_BITRATE_INFO_FD or Parameter == PCAN_IP_ADDRESS or Parameter == PCAN_FIRMWARE_VERSION or Parameter == PCAN_DEVICE_PART_NUMBER:
mybuffer = create_string_buffer(256)
elif Parameter == PCAN_ATTACHED_CHANNELS:
res = self.GetValue(Channel, PCAN_ATTACHED_CHANNELS_COUNT)
if TPCANStatus(res[0]) != PCAN_ERROR_OK:
return TPCANStatus(res[0]),
mybuffer = (TPCANChannelInformation * res[1])()
elif Parameter == PCAN_ACCEPTANCE_FILTER_11BIT or PCAN_ACCEPTANCE_FILTER_29BIT:
mybuffer = c_int64(0)
else:
mybuffer = c_int(0)
res = self.__m_dllBasic.CAN_GetValue(Channel,Parameter,byref(mybuffer),sizeof(mybuffer))
if Parameter == PCAN_ATTACHED_CHANNELS:
return TPCANStatus(res),mybuffer
else:
return TPCANStatus(res),mybuffer.value
except:
print ("Exception on PCANBasic.GetValue")
raise
# Returns a descriptive text of a given TPCANStatus
# error code, in any desired language
#
def SetValue(
self,
Channel,
Parameter,
Buffer):
"""
Configures or sets a PCAN Channel value
Remarks:
Parameters can be present or not according with the kind
of Hardware (PCAN Channel) being used. If a parameter is not available,
a PCAN_ERROR_ILLPARAMTYPE error will be returned.
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Parameter : The TPCANParameter parameter to set
Buffer : Buffer with the value to be set
BufferLength : Size in bytes of the buffer
Returns:
A TPCANStatus error code
"""
try:
if Parameter == PCAN_LOG_LOCATION or Parameter == PCAN_LOG_TEXT or Parameter == PCAN_TRACE_LOCATION:
mybuffer = create_string_buffer(256)
elif Parameter == PCAN_ACCEPTANCE_FILTER_11BIT or PCAN_ACCEPTANCE_FILTER_29BIT:
mybuffer = c_int64(0)
else:
mybuffer = c_int(0)
mybuffer.value = Buffer
res = self.__m_dllBasic.CAN_SetValue(Channel,Parameter,byref(mybuffer),sizeof(mybuffer))
return TPCANStatus(res)
except:
print ("Exception on PCANBasic.SetValue")
raise
def GetErrorText(
self,
Error,
Language = 0):
"""
Returns a descriptive text of a given TPCANStatus error
code, in any desired language
Remarks:
The current languages available for translation are:
Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
Italian (0x10) and French (0x0C)
The return value of this method is a 2-touple, where
the first value is the result (TPCANStatus) of the method and
the second one, the error text
Parameters:
Error : A TPCANStatus error code
Language : Indicates a 'Primary language ID' (Default is Neutral(0))
Returns:
A touple with 2 values
"""
try:
mybuffer = create_string_buffer(256)
res = self.__m_dllBasic.CAN_GetErrorText(Error,Language,byref(mybuffer))
return TPCANStatus(res),mybuffer.value
except:
print ("Exception on PCANBasic.GetErrorText")
raise
def LookUpChannel(
self,
Parameters):
"""
Finds a PCAN-Basic channel that matches with the given parameters
Remarks:
The return value of this method is a 2-touple, where
the first value is the result (TPCANStatus) of the method and
the second one a TPCANHandle value
Parameters:
Parameters : A comma separated string contained pairs of parameter-name/value
to be matched within a PCAN-Basic channel
Returns:
A touple with 2 values
"""
try:
mybuffer = TPCANHandle(0)
res = self.__m_dllBasic.CAN_LookUpChannel(Parameters,byref(mybuffer))
return TPCANStatus(res),mybuffer
except:
print ("Exception on PCANBasic.LookUpChannel")
raise
' PCANBasic.cs
'
' ~~~~~~~~~~~~
'
' PCAN-Basic API
'
' ~~~~~~~~~~~~
'
' ------------------------------------------------------------------
' Author : Keneth Wagner
' Last change: 2022-07-06
'
' Language: VB .NET
' ------------------------------------------------------------------
'
' Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
' more Info at http://www.peak-system.com
'
Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Imports TPCANHandle = System.UInt16
Imports TPCANBitrateFD = System.String
Imports TPCANTimestampFD = System.UInt64
Namespace Peak.Can.Basic
#Region "Enumerations"
''' <summary>
''' Represents a PCAN status/error code
''' </summary>
<Flags()> _
Public Enum TPCANStatus As UInt32
''' <summary>
''' No error
''' </summary>
PCAN_ERROR_OK = &H0
''' <summary>
''' Transmit buffer in CAN controller is full
''' </summary>
PCAN_ERROR_XMTFULL = &H1
''' <summary>
''' CAN controller was read too late
''' </summary>
PCAN_ERROR_OVERRUN = &H2
''' <summary>
''' Bus error: an error counter reached the 'light' limit
''' </summary>
PCAN_ERROR_BUSLIGHT = &H4
''' <summary>
''' Bus error: an error counter reached the 'heavy' limit
''' </summary>
PCAN_ERROR_BUSHEAVY = &H8
''' <summary>
''' Bus error: an error counter reached the 'warning' limit
''' </summary>
PCAN_ERROR_BUSWARNING = PCAN_ERROR_BUSHEAVY
''' <summary>
''' Bus error: the CAN controller is error passive
''' </summary>
PCAN_ERROR_BUSPASSIVE = &H40000
''' <summary>
''' Bus error: the CAN controller is in bus-off state
''' </summary>
PCAN_ERROR_BUSOFF = &H10
''' <summary>
''' Mask for all bus errors
''' </summary>
PCAN_ERROR_ANYBUSERR = (PCAN_ERROR_BUSWARNING Or PCAN_ERROR_BUSLIGHT Or PCAN_ERROR_BUSHEAVY Or PCAN_ERROR_BUSOFF Or PCAN_ERROR_BUSPASSIVE)
''' <summary>
''' Receive queue is empty
''' </summary>
PCAN_ERROR_QRCVEMPTY = &H20
''' <summary>
''' Receive queue was read too late
''' </summary>
PCAN_ERROR_QOVERRUN = &H40
''' <summary>
''' Transmit queue is full
''' </summary>
PCAN_ERROR_QXMTFULL = &H80
''' <summary>
''' Test of the CAN controller hardware registers failed (no hardware found)
''' </summary>
PCAN_ERROR_REGTEST = &H100
''' <summary>
''' Driver not loaded
''' </summary>
PCAN_ERROR_NODRIVER = &H200
''' <summary>
''' Hardware already in use by a Net
''' </summary>
PCAN_ERROR_HWINUSE = &H400
''' <summary>
''' A Client is already connected to the Net
''' </summary>
PCAN_ERROR_NETINUSE = &H800
''' <summary>
''' Hardware handle is invalid
''' </summary>
PCAN_ERROR_ILLHW = &H1400
''' <summary>
''' Net handle is invalid
''' </summary>
PCAN_ERROR_ILLNET = &H1800
''' <summary>
''' Client handle is invalid
''' </summary>
PCAN_ERROR_ILLCLIENT = &H1C00
''' <summary>
''' Mask for all handle errors
''' </summary>
PCAN_ERROR_ILLHANDLE = (PCAN_ERROR_ILLHW Or PCAN_ERROR_ILLNET Or PCAN_ERROR_ILLCLIENT)
''' <summary>
''' Resource (FIFO, Client, timeout) cannot be created
''' </summary>
PCAN_ERROR_RESOURCE = &H2000
''' <summary>
''' Invalid parameter
''' </summary>
PCAN_ERROR_ILLPARAMTYPE = &H4000
''' <summary>
''' Invalid parameter value
''' </summary>
PCAN_ERROR_ILLPARAMVAL = &H8000
''' <summary>
''' Unknown error
''' </summary>
PCAN_ERROR_UNKNOWN = &H10000
''' <summary>
''' Invalid data, function, or action.
''' </summary>
PCAN_ERROR_ILLDATA = &H20000
''' <summary>
''' Driver object state is wrong for the attempted operation
''' </summary>
PCAN_ERROR_ILLMODE = &H80000
''' <summary>
''' An operation was successfully carried out, however, irregularities were registered
''' </summary>
PCAN_ERROR_CAUTION = &H2000000
''' <summary>
''' Channel is not initialized
''' <remarks>Value was changed from 0x40000 to 0x4000000</remarks>
''' </summary>
PCAN_ERROR_INITIALIZE = &H4000000
''' <summary>
''' Invalid operation
''' <remarks>Value was changed from 0x80000 to 0x8000000</remarks>
''' </summary>
PCAN_ERROR_ILLOPERATION = &H8000000
End Enum
''' <summary>
''' Represents a PCAN device
''' </summary>
Public Enum TPCANDevice As Byte
''' <summary>
''' Undefined, unknown or not selected PCAN device value
''' </summary>
PCAN_NONE = 0
''' <summary>
''' PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
''' </summary>
PCAN_PEAKCAN = 1
''' <summary>
''' PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
''' </summary>
PCAN_ISA = 2
''' <summary>
''' PCAN-Dongle
''' </summary>
PCAN_DNG = 3
''' <summary>
''' PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
''' </summary>
PCAN_PCI = 4
''' <summary>
''' PCAN-USB and PCAN-USB Pro
''' </summary>
PCAN_USB = 5
''' <summary>
''' PCAN-PC Card
''' </summary>
PCAN_PCC = 6
''' <summary>
''' PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
''' </summary>
PCAN_VIRTUAL = 7
''' <summary>
''' PCAN Gateway devices
''' </summary>
PCAN_LAN = 8
End Enum
''' <summary>
''' Represents a PCAN parameter to be read or set
''' </summary>
Public Enum TPCANParameter As Byte
''' <summary>
''' Device identifier parameter
''' </summary>
PCAN_DEVICE_ID = 1
''' <summary>
''' DEPRECATED. Use PCAN_DEVICE_ID instead
''' </summary>
<Obsolete>
PCAN_DEVICE_NUMBER = PCAN_DEVICE_ID
''' <summary>
''' 5-Volt power parameter
''' </summary>
PCAN_5VOLTS_POWER = 2
''' <summary>
''' PCAN receive event handler parameter
''' </summary>
PCAN_RECEIVE_EVENT = 3
''' <summary>
''' PCAN message filter parameter
''' </summary>
PCAN_MESSAGE_FILTER = 4
''' <summary>
''' PCAN-Basic API version parameter
''' </summary>
PCAN_API_VERSION = 5
''' <summary>
''' PCAN device channel version parameter
''' </summary>
PCAN_CHANNEL_VERSION = 6
''' <summary>
''' PCAN Reset-On-Busoff parameter
''' </summary>
PCAN_BUSOFF_AUTORESET = 7
''' <summary>
''' PCAN Listen-Only parameter
''' </summary>
PCAN_LISTEN_ONLY = 8
''' <summary>
''' Directory path for log files
''' </summary>
PCAN_LOG_LOCATION = 9
''' <summary>
''' Debug-Log activation status
''' </summary>
PCAN_LOG_STATUS = 10
''' <summary>
''' Configuration of the debugged information (LOG_FUNCTION_***)
''' </summary>
PCAN_LOG_CONFIGURE = 11
''' <summary>
''' Custom insertion of text into the log file
''' </summary>
PCAN_LOG_TEXT = 12
''' <summary>
''' Availability status of a PCAN-Channel
''' </summary>
PCAN_CHANNEL_CONDITION = 13
''' <summary>
''' PCAN hardware name parameter
''' </summary>
PCAN_HARDWARE_NAME = 14
''' <summary>
''' Message reception status of a PCAN-Channel
''' </summary>
PCAN_RECEIVE_STATUS = 15
''' <summary>
''' CAN-Controller number of a PCAN-Channel
''' </summary>
PCAN_CONTROLLER_NUMBER = 16
''' <summary>
''' Directory path for PCAN trace files
''' </summary>
PCAN_TRACE_LOCATION = 17
''' <summary>
''' CAN tracing activation status
''' </summary>
PCAN_TRACE_STATUS = 18
''' <summary>
''' Configuration of the maximum file size of a CAN trace
''' </summary>
PCAN_TRACE_SIZE = 19
''' <summary>
''' Configuration of the trace file storing mode (TRACE_FILE_***)
''' </summary>
PCAN_TRACE_CONFIGURE = 20
''' <summary>
''' Physical identification of a USB based PCAN-Channel by blinking its associated LED
''' </summary>
PCAN_CHANNEL_IDENTIFYING = 21
''' <summary>
''' Capabilities of a PCAN device (FEATURE_***)
''' </summary>
PCAN_CHANNEL_FEATURES = 22
''' <summary>
''' Using of an existing bit rate (PCAN-View connected to a channel)
''' </summary>
PCAN_BITRATE_ADAPTING = 23
''' <summary>
''' Configured bit rate as Btr0Btr1 value
''' </summary>
PCAN_BITRATE_INFO = 24
''' <summary>
''' Configured bit rate as TPCANBitrateFD string
''' </summary>
PCAN_BITRATE_INFO_FD = 25
''' <summary>
''' Configured nominal CAN Bus speed as Bits per seconds
''' </summary>
PCAN_BUSSPEED_NOMINAL = 26
''' <summary>
''' Configured CAN data speed as Bits per seconds
''' </summary>
PCAN_BUSSPEED_DATA = 27
''' <summary>
''' Remote address of a LAN channel as string in IPv4 format
''' </summary>
PCAN_IP_ADDRESS = 28
''' <summary>
''' Status of the Virtual PCAN-Gateway Service
''' </summary>
PCAN_LAN_SERVICE_STATUS = 29
''' <summary>
''' Status messages reception status within a PCAN-Channel
''' </summary>
PCAN_ALLOW_STATUS_FRAMES = 30
''' <summary>
''' RTR messages reception status within a PCAN-Channel
''' </summary>
PCAN_ALLOW_RTR_FRAMES = 31
''' <summary>
''' Error messages reception status within a PCAN-Channel
''' </summary>
PCAN_ALLOW_ERROR_FRAMES = 32
''' <summary>
''' Delay, in microseconds, between sending frames
''' </summary>
PCAN_INTERFRAME_DELAY = 33
''' <summary>
''' Filter over code and mask patterns for 11-Bit messages
''' </summary>
PCAN_ACCEPTANCE_FILTER_11BIT = 34
''' <summary>
''' Filter over code and mask patterns for 29-Bit messages
''' </summary>
PCAN_ACCEPTANCE_FILTER_29BIT = 35
''' <summary>
''' Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
''' </summary>
PCAN_IO_DIGITAL_CONFIGURATION = 36
''' <summary>
''' Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
''' </summary>
PCAN_IO_DIGITAL_VALUE = 37
''' <summary>
''' Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
''' </summary>
PCAN_IO_DIGITAL_SET = 38
''' <summary>
''' Clear multiple digital I/O pins to 0
''' </summary>
PCAN_IO_DIGITAL_CLEAR = 39
''' <summary>
''' Get value of a single analog input pin
''' </summary>
PCAN_IO_ANALOG_VALUE = 40
''' <summary>
''' Get the version of the firmware used by the device associated with a PCAN-Channel
''' </summary>
PCAN_FIRMWARE_VERSION = 41
''' <summary>
''' Get the amount of PCAN channels attached to a system
''' </summary>
PCAN_ATTACHED_CHANNELS_COUNT = 42
''' <summary>
''' Get information about PCAN channels attached to a system
''' </summary>
PCAN_ATTACHED_CHANNELS = 43
''' <summary>
''' Echo messages reception status within a PCAN-Channel
''' </summary>
PCAN_ALLOW_ECHO_FRAMES = 44
''' <summary>
''' Get the part number associated to a device
''' </summary>
PCAN_DEVICE_PART_NUMBER = 45
End Enum
''' <summary>
''' Represents the type of a PCAN message
''' </summary>
<Flags()> _
Public Enum TPCANMessageType As Byte
''' <summary>
''' The PCAN message is a CAN Standard Frame (11-bit identifier)
''' </summary>
PCAN_MESSAGE_STANDARD = &H0
''' <summary>
''' The PCAN message is a CAN Remote-Transfer-Request Frame
''' </summary>
PCAN_MESSAGE_RTR = &H1
''' <summary>
''' The PCAN message is a CAN Extended Frame (29-bit identifier)
''' </summary>
PCAN_MESSAGE_EXTENDED = &H2
''' <summary>
''' The PCAN message represents a FD frame in terms of CiA Specs
''' </summary>
PCAN_MESSAGE_FD = &H4
''' <summary>
''' The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
''' </summary>
PCAN_MESSAGE_BRS = &H8
''' <summary>
''' The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
''' </summary>
PCAN_MESSAGE_ESI = &H10
''' <summary>
''' The PCAN message represents an echo CAN Frame
''' </summary>
PCAN_MESSAGE_ECHO = &H20
''' <summary>
''' The PCAN message represents an error frame
''' </summary>
PCAN_MESSAGE_ERRFRAME = &H40
''' <summary>
''' The PCAN message represents a PCAN status message
''' </summary>
PCAN_MESSAGE_STATUS = &H80
End Enum
''' <summary>
''' Represents a PCAN filter mode
''' </summary>
Public Enum TPCANMode As Byte
''' <summary>
''' Mode is Standard (11-bit identifier)
''' </summary>
PCAN_MODE_STANDARD = TPCANMessageType.PCAN_MESSAGE_STANDARD
''' <summary>
''' Mode is Extended (29-bit identifier)
''' </summary>
PCAN_MODE_EXTENDED = TPCANMessageType.PCAN_MESSAGE_EXTENDED
End Enum
''' <summary>
''' Represents a PCAN Baud rate register value
''' </summary>
Public Enum TPCANBaudrate As UInt16
''' <summary>
''' 1 MBit/s
''' </summary>
PCAN_BAUD_1M = &H14
''' <summary>
''' 800 kBit/s
''' </summary>
PCAN_BAUD_800K = &H16
''' <summary>
''' 500 kBit/s
''' </summary>
PCAN_BAUD_500K = &H1C
''' <summary>
''' 250 kBit/s
''' </summary>
PCAN_BAUD_250K = &H11C
''' <summary>
''' 125 kBit/s
''' </summary>
PCAN_BAUD_125K = &H31C
''' <summary>
''' 100 kBit/s
''' </summary>
PCAN_BAUD_100K = &H432F
''' <summary>
''' 95,238 kBit/s
''' </summary>
PCAN_BAUD_95K = &HC34E
''' <summary>
''' 83,333 kBit/s
''' </summary>
PCAN_BAUD_83K = &H852B
''' <summary>
''' 50 kBit/s
''' </summary>
PCAN_BAUD_50K = &H472F
''' <summary>
''' 47,619 kBit/s
''' </summary>
PCAN_BAUD_47K = &H1414
''' <summary>
''' 33,333 kBit/s
''' </summary>
PCAN_BAUD_33K = &H8B2F
''' <summary>
''' 20 kBit/s
''' </summary>
PCAN_BAUD_20K = &H532F
''' <summary>
''' 10 kBit/s
''' </summary>
PCAN_BAUD_10K = &H672F
''' <summary>
''' 5 kBit/s
''' </summary>
PCAN_BAUD_5K = &H7F7F
End Enum
''' <summary>
''' Represents the type of PCAN (Non-PnP) hardware to be initialized
''' </summary>
Public Enum TPCANType As Byte
''' <summary>
''' PCAN-ISA 82C200
''' </summary>
PCAN_TYPE_ISA = &H1
''' <summary>
''' PCAN-ISA SJA1000
''' </summary>
PCAN_TYPE_ISA_SJA = &H9
''' <summary>
''' PHYTEC ISA
''' </summary>
PCAN_TYPE_ISA_PHYTEC = &H4
''' <summary>
''' PCAN-Dongle 82C200
''' </summary>
PCAN_TYPE_DNG = &H2
''' <summary>
''' PCAN-Dongle EPP 82C200
''' </summary>
PCAN_TYPE_DNG_EPP = &H3
''' <summary>
''' PCAN-Dongle SJA1000
''' </summary>
PCAN_TYPE_DNG_SJA = &H5
''' <summary>
''' PCAN-Dongle EPP SJA1000
''' </summary>
PCAN_TYPE_DNG_SJA_EPP = &H6
End Enum
#End Region
#Region "Structures"
''' <summary>
''' Represents a PCAN message
''' </summary>
Public Structure TPCANMsg
''' <summary>
''' 11/29-bit message identifier
''' </summary>
Public ID As UInt32
''' <summary>
''' Type of the message
''' </summary>
<MarshalAs(UnmanagedType.U1)> _
Public MSGTYPE As TPCANMessageType
''' <summary>
''' Data Length Code of the message (0..8)
''' </summary>
Public LEN As Byte
''' <summary>
''' Data of the message (DATA[0]..DATA[7])
''' </summary>
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=8)> _
Public DATA As Byte()
End Structure
''' <summary>
''' Represents a timestamp of a received PCAN message.
''' Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
''' </summary>
Public Structure TPCANTimestamp
''' <summary>
''' Base-value: milliseconds: 0.. 2^32-1
''' </summary>
Public millis As UInt32
''' <summary>
''' Roll-arounds of millis
''' </summary>
Public millis_overflow As UInt16
''' <summary>
''' Microseconds: 0..999
''' </summary>
Public micros As UInt16
End Structure
''' <summary>
''' Represents a PCAN message from a FD capable hardware
''' </summary>
Public Structure TPCANMsgFD
''' <summary>
''' 11/29-bit message identifier
''' </summary>
Public ID As UInt32
''' <summary>
''' Type of the message
''' </summary>
<MarshalAs(UnmanagedType.U1)>
Public MSGTYPE As TPCANMessageType
''' <summary>
''' Data Length Code of the message (0..15)
''' </summary>
Public DLC As Byte
''' <summary>
''' Data of the message (DATA[0]..DATA[63])
''' </summary>
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=64)>
Public DATA As Byte()
End Structure
''' <summary>
''' Describes an available PCAN channel
''' </summary>
Public Structure TPCANChannelInformation
''' <summary>
''' PCAN channel handle
''' </summary>
<MarshalAs(UnmanagedType.U2)>
Public channel_handle As TPCANHandle
''' <summary>
''' Kind of PCAN device
''' </summary>
<MarshalAs(UnmanagedType.U1)>
Public device_type As TPCANDevice
''' <summary>
''' CAN-Controller number
''' </summary>
Public controller_number As Byte
''' <summary>
''' Device capabilities flag (see FEATURE_*)
''' </summary>
Public device_features As UInt32
''' <summary>
''' Device name
''' </summary>
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=PCANBasic.MAX_LENGTH_HARDWARE_NAME)>
Public device_name As String
''' <summary>
''' Device number
''' </summary>
Public device_id As UInt32
''' <summary>
''' Availability status of a PCAN-Channel
''' </summary>
Public channel_condition As UInt32
End Structure
#End Region
#Region "PCANBasic class"
''' <summary>
''' PCAN-Basic API class implementation
''' </summary>
Public NotInheritable Class PCANBasic
#Region "PCAN-BUS Handles Definition"
''' <summary>
''' Undefined/default value for a PCAN bus
''' </summary>
Public Const PCAN_NONEBUS As TPCANHandle = &H0
''' <summary>
''' PCAN-ISA interface, channel 1
''' </summary>
Public Const PCAN_ISABUS1 As TPCANHandle = &H21
''' <summary>
''' PCAN-ISA interface, channel 2
''' </summary>
Public Const PCAN_ISABUS2 As TPCANHandle = &H22
''' <summary>
''' PCAN-ISA interface, channel 3
''' </summary>
Public Const PCAN_ISABUS3 As TPCANHandle = &H23
''' <summary>
''' PCAN-ISA interface, channel 4
''' </summary>
Public Const PCAN_ISABUS4 As TPCANHandle = &H24
''' <summary>
''' PCAN-ISA interface, channel 5
''' </summary>
Public Const PCAN_ISABUS5 As TPCANHandle = &H25
''' <summary>
''' PCAN-ISA interface, channel 6
''' </summary>
Public Const PCAN_ISABUS6 As TPCANHandle = &H26
''' <summary>
''' PCAN-ISA interface, channel 7
''' </summary>
Public Const PCAN_ISABUS7 As TPCANHandle = &H27
''' <summary>
''' PCAN-ISA interface, channel 8
''' </summary>
Public Const PCAN_ISABUS8 As TPCANHandle = &H28
''' <summary>
''' PPCAN-Dongle/LPT interface, channel 1
''' </summary>
Public Const PCAN_DNGBUS1 As TPCANHandle = &H31
''' <summary>
''' PCAN-PCI interface, channel 1
''' </summary>
Public Const PCAN_PCIBUS1 As TPCANHandle = &H41
''' <summary>
''' PCAN-PCI interface, channel 2
''' </summary>
Public Const PCAN_PCIBUS2 As TPCANHandle = &H42
''' <summary>
''' PCAN-PCI interface, channel 3
''' </summary>
Public Const PCAN_PCIBUS3 As TPCANHandle = &H43
''' <summary>
''' PCAN-PCI interface, channel 4
''' </summary>
Public Const PCAN_PCIBUS4 As TPCANHandle = &H44
''' <summary>
''' PCAN-PCI interface, channel 5
''' </summary>
Public Const PCAN_PCIBUS5 As TPCANHandle = &H45
''' <summary>
''' PCAN-PCI interface, channel 6
''' </summary>
Public Const PCAN_PCIBUS6 As TPCANHandle = &H46
''' <summary>
''' PCAN-PCI interface, channel 7
''' </summary>
Public Const PCAN_PCIBUS7 As TPCANHandle = &H47
''' <summary>
''' PCAN-PCI interface, channel 8
''' </summary>
Public Const PCAN_PCIBUS8 As TPCANHandle = &H48
''' <summary>
''' PCAN-PCI interface, channel 9
''' </summary>
Public Const PCAN_PCIBUS9 As TPCANHandle = &H409
''' <summary>
''' PCAN-PCI interface, channel 10
''' </summary>
Public Const PCAN_PCIBUS10 As TPCANHandle = &H40A
''' <summary>
''' PCAN-PCI interface, channel 11
''' </summary>
Public Const PCAN_PCIBUS11 As TPCANHandle = &H40B
''' <summary>
''' PCAN-PCI interface, channel 12
''' </summary>
Public Const PCAN_PCIBUS12 As TPCANHandle = &H40C
''' <summary>
''' PCAN-PCI interface, channel 13
''' </summary>
Public Const PCAN_PCIBUS13 As TPCANHandle = &H40D
''' <summary>
''' PCAN-PCI interface, channel 14
''' </summary>
Public Const PCAN_PCIBUS14 As TPCANHandle = &H40E
''' <summary>
''' PCAN-PCI interface, channel 15
''' </summary>
Public Const PCAN_PCIBUS15 As TPCANHandle = &H40F
''' <summary>
''' PCAN-PCI interface, channel 16
''' </summary>
Public Const PCAN_PCIBUS16 As TPCANHandle = &H410
''' <summary>
''' PCAN-USB interface, channel 1
''' </summary>
Public Const PCAN_USBBUS1 As TPCANHandle = &H51
''' <summary>
''' PCAN-USB interface, channel 2
''' </summary>
Public Const PCAN_USBBUS2 As TPCANHandle = &H52
''' <summary>
''' PCAN-USB interface, channel 3
''' </summary>
Public Const PCAN_USBBUS3 As TPCANHandle = &H53
''' <summary>
''' PCAN-USB interface, channel 4
''' </summary>
Public Const PCAN_USBBUS4 As TPCANHandle = &H54
''' <summary>
''' PCAN-USB interface, channel 5
''' </summary>
Public Const PCAN_USBBUS5 As TPCANHandle = &H55
''' <summary>
''' PCAN-USB interface, channel 6
''' </summary>
Public Const PCAN_USBBUS6 As TPCANHandle = &H56
''' <summary>
''' PCAN-USB interface, channel 7
''' </summary>
Public Const PCAN_USBBUS7 As TPCANHandle = &H57
''' <summary>
''' PCAN-USB interface, channel 8
''' </summary>
Public Const PCAN_USBBUS8 As TPCANHandle = &H58
''' <summary>
''' PCAN-USB interface, channel 9
''' </summary>
Public Const PCAN_USBBUS9 As TPCANHandle = &H509
''' <summary>
''' PCAN-USB interface, channel 10
''' </summary>
Public Const PCAN_USBBUS10 As TPCANHandle = &H50A
''' <summary>
''' PCAN-USB interface, channel 11
''' </summary>
Public Const PCAN_USBBUS11 As TPCANHandle = &H50B
''' <summary>
''' PCAN-USB interface, channel 12
''' </summary>
Public Const PCAN_USBBUS12 As TPCANHandle = &H50C
''' <summary>
''' PCAN-USB interface, channel 13
''' </summary>
Public Const PCAN_USBBUS13 As TPCANHandle = &H50D
''' <summary>
''' PCAN-USB interface, channel 14
''' </summary>
Public Const PCAN_USBBUS14 As TPCANHandle = &H50E
''' <summary>
''' PCAN-USB interface, channel 15
''' </summary>
Public Const PCAN_USBBUS15 As TPCANHandle = &H50F
''' <summary>
''' PCAN-USB interface, channel 16
''' </summary>
Public Const PCAN_USBBUS16 As TPCANHandle = &H510
''' <summary>
''' PCAN-PC Card interface, channel 1
''' </summary>
Public Const PCAN_PCCBUS1 As TPCANHandle = &H61
''' <summary>
''' PCAN-PC Card interface, channel 2
''' </summary>
Public Const PCAN_PCCBUS2 As TPCANHandle = &H62
''' <summary>
''' PCAN-LAN interface, channel 1
''' </summary>
Public Const PCAN_LANBUS1 As TPCANHandle = &H801
''' <summary>
''' PCAN-LAN interface, channel 2
''' </summary>
Public Const PCAN_LANBUS2 As TPCANHandle = &H802
''' <summary>
''' PCAN-LAN interface, channel 3
''' </summary>
Public Const PCAN_LANBUS3 As TPCANHandle = &H803
''' <summary>
''' PCAN-LAN interface, channel 4
''' </summary>
Public Const PCAN_LANBUS4 As TPCANHandle = &H804
''' <summary>
''' PCAN-LAN interface, channel 5
''' </summary>
Public Const PCAN_LANBUS5 As TPCANHandle = &H805
''' <summary>
''' PCAN-LAN interface, channel 6
''' </summary>
Public Const PCAN_LANBUS6 As TPCANHandle = &H806
''' <summary>
''' PCAN-LAN interface, channel 7
''' </summary>
Public Const PCAN_LANBUS7 As TPCANHandle = &H807
''' <summary>
''' PCAN-LAN interface, channel 8
''' </summary>
Public Const PCAN_LANBUS8 As TPCANHandle = &H808
''' <summary>
''' PCAN-LAN interface, channel 9
''' </summary>
Public Const PCAN_LANBUS9 As TPCANHandle = &H809
''' <summary>
''' PCAN-LAN interface, channel 10
''' </summary>
Public Const PCAN_LANBUS10 As TPCANHandle = &H80A
''' <summary>
''' PCAN-LAN interface, channel 11
''' </summary>
Public Const PCAN_LANBUS11 As TPCANHandle = &H80B
''' <summary>
''' PCAN-LAN interface, channel 12
''' </summary>
Public Const PCAN_LANBUS12 As TPCANHandle = &H80C
''' <summary>
''' PCAN-LAN interface, channel 13
''' </summary>
Public Const PCAN_LANBUS13 As TPCANHandle = &H80D
''' <summary>
''' PCAN-LAN interface, channel 14
''' </summary>
Public Const PCAN_LANBUS14 As TPCANHandle = &H80E
''' <summary>
''' PCAN-LAN interface, channel 15
''' </summary>
Public Const PCAN_LANBUS15 As TPCANHandle = &H80F
''' <summary>
''' PCAN-LAN interface, channel 16
''' </summary>
Public Const PCAN_LANBUS16 As TPCANHandle = &H810
#End Region
#Region "FD Bit rate parameters"
''' <summary>
''' Clock frequency in Herz (80000000, 60000000, 40000000, 30000000, 24000000, 20000000)
''' </summary>
Public Const PCAN_BR_CLOCK As String = "f_clock"
''' <summary>
''' Clock frequency in Megaherz (80, 60, 40, 30, 24, 20)
''' </summary>
Public Const PCAN_BR_CLOCK_MHZ As String = "f_clock_mhz"
''' <summary>
''' Clock prescaler for nominal time quantum
''' </summary>
Public Const PCAN_BR_NOM_BRP As String = "nom_brp"
''' <summary>
''' TSEG1 segment for nominal bit rate in time quanta
''' </summary>
Public Const PCAN_BR_NOM_TSEG1 As String = "nom_tseg1"
''' <summary>
''' TSEG2 segment for nominal bit rate in time quanta
''' </summary>
Public Const PCAN_BR_NOM_TSEG2 As String = "nom_tseg2"
''' <summary>
''' Synchronization Jump Width for nominal bit rate in time quanta
''' </summary>
Public Const PCAN_BR_NOM_SJW As String = "nom_sjw"
''' <summary>
''' Sample point for nominal bit rate
''' </summary>
Public Const PCAN_BR_NOM_SAMPLE As String = "nom_sam"
''' <summary>
''' Clock prescaler for highspeed data time quantum
''' </summary>
Public Const PCAN_BR_DATA_BRP As String = "data_brp"
''' <summary>
''' TSEG1 segment for fast data bit rate in time quanta
''' </summary>
Public Const PCAN_BR_DATA_TSEG1 As String = "data_tseg1"
''' <summary>
''' TSEG2 segment for fast data bit rate in time quanta
''' </summary>
Public Const PCAN_BR_DATA_TSEG2 As String = "data_tseg2"
''' <summary>
''' Synchronization Jump Width for highspeed data bit rate in time quanta
''' </summary>
Public Const PCAN_BR_DATA_SJW As String = "data_sjw"
''' <summary>
''' Secondary sample point delay for highspeed data bit rate in cyles
''' </summary>
Public Const PCAN_BR_DATA_SAMPLE As String = "data_ssp_offset"
#End Region
#Region "Parameter values definition"
''' <summary>
''' The PCAN parameter is not set (inactive)
''' </summary>
Public Const PCAN_PARAMETER_OFF As Integer = 0
''' <summary>
''' The PCAN parameter is set (active)
''' </summary>
Public Const PCAN_PARAMETER_ON As Integer = 1
''' <summary>
''' The PCAN filter is closed. No messages will be received
''' </summary>
Public Const PCAN_FILTER_CLOSE As Integer = 0
''' <summary>
''' The PCAN filter is fully opened. All messages will be received
''' </summary>
Public Const PCAN_FILTER_OPEN As Integer = 1
''' <summary>
''' The PCAN filter is custom configured. Only registered
''' messages will be received
''' </summary>
Public Const PCAN_FILTER_CUSTOM As Integer = 2
''' <summary>
''' The PCAN-Channel handle is illegal, or its associated hardware is not available
''' </summary>
Public Const PCAN_CHANNEL_UNAVAILABLE As Integer = 0
''' <summary>
''' The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
''' </summary>
Public Const PCAN_CHANNEL_AVAILABLE As Integer = 1
''' <summary>
''' The PCAN-Channel handle is valid, and is already being used
''' </summary>
Public Const PCAN_CHANNEL_OCCUPIED As Integer = 2
''' <summary>
''' The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
''' </summary>
Public Const PCAN_CHANNEL_PCANVIEW As Integer = PCAN_CHANNEL_AVAILABLE Or PCAN_CHANNEL_OCCUPIED
''' <summary>
''' Logs system exceptions / errors
''' </summary>
Public Const LOG_FUNCTION_DEFAULT As Integer = &H0
''' <summary>
''' Logs the entries to the PCAN-Basic API functions
''' </summary>
Public Const LOG_FUNCTION_ENTRY As Integer = &H1
''' <summary>
''' Logs the parameters passed to the PCAN-Basic API functions
''' </summary>
Public Const LOG_FUNCTION_PARAMETERS As Integer = &H2
''' <summary>
''' Logs the exits from the PCAN-Basic API functions
''' </summary>
Public Const LOG_FUNCTION_LEAVE As Integer = &H4
''' <summary>
''' Logs the CAN messages passed to the CAN_Write function
''' </summary>
Public Const LOG_FUNCTION_WRITE As Integer = &H8
''' <summary>
''' Logs the CAN messages received within the CAN_Read function
''' </summary>
Public Const LOG_FUNCTION_READ As Integer = &H10
''' <summary>
''' Logs all possible information within the PCAN-Basic API functions
''' </summary>
Public Const LOG_FUNCTION_ALL As Integer = &HFFFF
''' <summary>
''' A single file is written until it size reaches PAN_TRACE_SIZE
''' </summary>
Public Const TRACE_FILE_SINGLE As Integer = &H0
''' <summary>
''' Traced data is distributed in several files with size PAN_TRACE_SIZE
''' </summary>
Public Const TRACE_FILE_SEGMENTED As Integer = &H1
''' <summary>
''' Includes the date into the name of the trace file
''' </summary>
Public Const TRACE_FILE_DATE As Integer = &H2
''' <summary>
''' Includes the start time into the name of the trace file
''' </summary>
Public Const TRACE_FILE_TIME As Integer = &H4
''' <summary>
''' Causes the overwriting of available traces (same name)
''' </summary>
Public Const TRACE_FILE_OVERWRITE As Integer = &H80
''' <summary>
''' Device supports flexible data-rate (CAN-FD)
''' </summary>
Public Const FEATURE_FD_CAPABLE As Integer = &H1
''' <summary>
''' Device supports a delay between sending frames (FPGA based USB devices)
''' </summary>
Public Const FEATURE_DELAY_CAPABLE As Integer = &H2
''' <summary>
''' Device supports I/O functionality for electronic circuits (USB-Chip devices)
''' </summary>
Public Const FEATURE_IO_CAPABLE As Integer = &H4
''' <summary>
''' The service is not running
''' </summary>
Public Const SERVICE_STATUS_STOPPED As Integer = &H1
''' <summary>
''' The service is running
''' </summary>
Public Const SERVICE_STATUS_RUNNING As Integer = &H4
#End Region
#Region "Lookup Parameters"
''' <summary>
''' Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
''' </summary>
Public Const LOOKUP_DEVICE_TYPE As String = "devicetype"
''' <summary>
''' Lookup channel by device id
''' </summary>
Public Const LOOKUP_DEVICE_ID As String = "deviceid"
''' <summary>
''' Lookup channel by CAN controller 0-based index
''' </summary>
Public Const LOOKUP_CONTROLLER_NUMBER As String = "controllernumber"
''' <summary>
''' Lookup channel by IP address (LAN channels only)
''' </summary>
Public Const LOOKUP_IP_ADDRESS As String = "ipaddress"
#End Region
#Region "Other Constants"
''' <summary>
''' Maximum length of the name of a device: 32 characters + terminator
''' </summary>
Public Const MAX_LENGTH_HARDWARE_NAME As Integer = 33
''' <summary>
''' ' Maximum length of a version string: 255 characters + terminator
''' </summary>
Public Const MAX_LENGTH_VERSION_STRING As Integer = 256
#End Region
#Region "PCANBasic API Implementation"
''' <summary>
''' Initializes a PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
''' <param name="HwType">Non-PnP: The type of hardware and operation mode</param>
''' <param name="IOPort">Non-PnP: The I/O address for the parallel port</param>
''' <param name="Interrupt">Non-PnP: Interrupt number of the parallel por</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_Initialize")> _
Public Shared Function Initialize( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
<MarshalAs(UnmanagedType.U2)> _
ByVal Btr0Btr1 As TPCANBaudrate, _
<MarshalAs(UnmanagedType.U1)> _
ByVal HwType As TPCANType, _
ByVal IOPort As UInt32, _
ByVal Interrupt As UInt16) As TPCANStatus
End Function
''' <summary>
''' Initializes a PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
''' <returns>A TPCANStatus error code</returns>
Public Shared Function Initialize( _
ByVal Channel As TPCANHandle, _
ByVal Btr0Btr1 As TPCANBaudrate) As TPCANStatus
Return Initialize(Channel, Btr0Btr1, 0, 0, 0)
End Function
''' <summary>
''' Initializes a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a FD capable PCAN Channel</param>
''' <param name="BitrateFD">The speed for the communication (FD bit rate string)</param>
''' <remarks> See PCAN_BR_* values
''' Bit rate string must follow the following construction rules:
''' * parameter and values must be separated by '='
''' * Couples of Parameter/value must be separated by ','
''' * Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
''' nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
''' * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam</remarks>
''' <example>f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1</example>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_InitializeFD")> _
Public Shared Function InitializeFD( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByVal BitrateFD As TPCANBitrateFD) As TPCANStatus
End Function
''' <summary>
''' Uninitializes one or all PCAN Channels initialized by CAN_Initialize
''' </summary>
''' <remarks>Giving the TPCANHandle value "PCAN_NONEBUS",
''' uninitialize all initialized channels</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_Uninitialize")> _
Public Shared Function Uninitialize( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle) As TPCANStatus
End Function
''' <summary>
''' Resets the receive and transmit queues of the PCAN Channel
''' </summary>
''' <remarks>A reset of the CAN controller is not performed</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_Reset")> _
Public Shared Function Reset( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle) As TPCANStatus
End Function
''' <summary>
''' Gets the current status of a PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_GetStatus")> _
Public Shared Function GetStatus( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle) As TPCANStatus
End Function
''' <summary>
''' Reads a CAN message from the receive queue of a PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
''' <param name="TimestampBuffer">A TPCANTimestamp structure buffer to get
''' the reception time of the message</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_Read")> _
Public Shared Function Read( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsg, _
ByRef TimestampBuffer As TPCANTimestamp) As TPCANStatus
End Function
<DllImport("PCANBasic.dll", EntryPoint:="CAN_Read")> _
Private Shared Function Read( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsg, _
ByVal BufferPointer As IntPtr) As TPCANStatus
End Function
''' <summary>
''' Reads a CAN message from the receive queue of a PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
''' <returns>A TPCANStatus error code</returns>
Public Shared Function Read( _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsg) As TPCANStatus
Return Read(Channel, MessageBuffer, IntPtr.Zero)
End Function
''' <summary>
''' Reads a CAN message from the receive queue of a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a FD capable PCAN Channel</param>
''' <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
''' <param name="TimestampBuffer">A TPCANTimestampFD buffer to get the
''' reception time of the message</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_ReadFD")> _
Public Shared Function ReadFD( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsgFD, _
ByRef TimestampBuffer As TPCANTimestampFD) As TPCANStatus
End Function
<DllImport("PCANBasic.dll", EntryPoint:="CAN_ReadFD")> _
Private Shared Function ReadFD( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsgFD, _
ByVal TimestampBuffer As IntPtr) As TPCANStatus
End Function
''' <summary>
''' Reads a CAN message from the receive queue of a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a FD capable PCAN Channel</param>
''' <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
''' <returns>A TPCANStatus error code</returns>
Public Shared Function ReadFD( _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsgFD) As TPCANStatus
Return ReadFD(Channel, MessageBuffer, IntPtr.Zero)
End Function
''' <summary>
''' Transmits a CAN message
''' </summary>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="MessageBuffer">A TPCANMsg buffer with the message to be sent</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_Write")> _
Public Shared Function Write( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsg) As TPCANStatus
End Function
''' <summary>
''' Transmits a CAN message over a FD capable PCAN Channel
''' </summary>
''' <param name="Channel">The handle of a FD capable PCAN Channel</param>
''' <param name="MessageBuffer">A TPCANMsgFD buffer with the message to be sent</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_WriteFD")> _
Public Shared Function WriteFD( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByRef MessageBuffer As TPCANMsgFD) As TPCANStatus
End Function
''' <summary>
''' Configures the reception filter
''' </summary>
''' <remarks>The message filter will be expanded with every call to
''' this function. If it is desired to reset the filter, please use
''' the 'SetValue' function</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="FromID">The lowest CAN ID to be received</param>
''' <param name="ToID">The highest CAN ID to be received</param>
''' <param name="Mode">Message type, Standard (11-bit identifier) or
''' Extended (29-bit identifier)</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_FilterMessages")> _
Public Shared Function FilterMessages( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
ByVal FromID As UInt32, _
ByVal ToID As UInt32, _
<MarshalAs(UnmanagedType.U1)> _
ByVal Mode As TPCANMode) As TPCANStatus
End Function
''' <summary>
''' Retrieves a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter">The TPCANParameter parameter to get</param>
''' <param name="StringBuffer">Buffer for the parameter value</param>
''' <param name="BufferLength">Size in bytes of the buffer</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_GetValue")> _
Public Shared Function GetValue( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
<MarshalAs(UnmanagedType.U1)> _
ByVal Parameter As TPCANParameter, _
ByVal StringBuffer As StringBuilder, _
ByVal BufferLength As UInt32) As TPCANStatus
End Function
''' <summary>
''' Retrieves a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter">The TPCANParameter parameter to get</param>
''' <param name="NumericBuffer">Buffer for the parameter value</param>
''' <param name="BufferLength">Size in bytes of the buffer</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_GetValue")>
Public Shared Function GetValue(
<MarshalAs(UnmanagedType.U2)>
ByVal Channel As TPCANHandle,
<MarshalAs(UnmanagedType.U1)>
ByVal Parameter As TPCANParameter,
ByRef NumericBuffer As UInt32,
ByVal BufferLength As UInt32) As TPCANStatus
End Function
''' <summary>
''' Retrieves a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter">The TPCANParameter parameter to get</param>
''' <param name="NumericBuffer">Buffer for the parameter value</param>
''' <param name="BufferLength">Size in bytes of the buffer</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_GetValue")>
Public Shared Function GetValue(
<MarshalAs(UnmanagedType.U2)>
ByVal Channel As TPCANHandle,
<MarshalAs(UnmanagedType.U1)>
ByVal Parameter As TPCANParameter,
ByRef NumericBuffer As UInt64,
ByVal BufferLength As UInt32) As TPCANStatus
End Function
<DllImport("PCANBasic.dll", EntryPoint:="CAN_GetValue")>
Private Shared Function GetValue(
<MarshalAs(UnmanagedType.U2)>
ByVal Channel As TPCANHandle,
<MarshalAs(UnmanagedType.U1)>
ByVal Parameter As TPCANParameter,
<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=3)>
<[In], Out> ByVal ChannelsBuffer() As TPCANChannelInformation,
ByVal BufferLength As UInt32) As TPCANStatus
End Function
''' <summary>
''' Retrieves a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter">The TPCANParameter parameter to get</param>
''' <param name="ChannelsBuffer">Buffer for the parameter value</param>
''' <returns>A TPCANStatus error code</returns>
Public Shared Function GetValue(
ByVal Channel As TPCANHandle,
ByVal Parameter As TPCANParameter,
ByVal ChannelsBuffer() As TPCANChannelInformation) As TPCANStatus
If (ChannelsBuffer Is Nothing) Then
Return TPCANStatus.PCAN_ERROR_ILLPARAMVAL
End If
Return GetValue(Channel, Parameter, ChannelsBuffer, ChannelsBuffer.Length * Marshal.SizeOf(GetType(TPCANChannelInformation)))
End Function
''' <summary>
''' Configures or sets a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter">The TPCANParameter parameter to set</param>
''' <param name="NumericBuffer">Buffer with the value to be set</param>
''' <param name="BufferLength">Size in bytes of the buffer</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_SetValue")>
Public Shared Function SetValue(
<MarshalAs(UnmanagedType.U2)>
ByVal Channel As TPCANHandle,
<MarshalAs(UnmanagedType.U1)>
ByVal Parameter As TPCANParameter,
ByRef NumericBuffer As UInt32,
ByVal BufferLength As UInt32) As TPCANStatus
End Function
''' <summary>
''' Configures or sets a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter">The TPCANParameter parameter to set</param>
''' <param name="NumericBuffer">Buffer with the value to be set</param>
''' <param name="BufferLength">Size in bytes of the buffer</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_SetValue")>
Public Shared Function SetValue(
<MarshalAs(UnmanagedType.U2)>
ByVal Channel As TPCANHandle,
<MarshalAs(UnmanagedType.U1)>
ByVal Parameter As TPCANParameter,
ByRef NumericBuffer As UInt64,
ByVal BufferLength As UInt32) As TPCANStatus
End Function
''' <summary>
''' Configures or sets a PCAN Channel value
''' </summary>
''' <remarks>Parameters can be present or not according with the kind
''' of Hardware (PCAN Channel) being used. If a parameter is not available,
''' a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
''' <param name="Channel">The handle of a PCAN Channel</param>
''' <param name="Parameter"></param>
''' <param name="StringBuffer">Buffer with the value to be set</param>
''' <param name="BufferLength">Size in bytes of the buffer</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_SetValue")> _
Public Shared Function SetValue( _
<MarshalAs(UnmanagedType.U2)> _
ByVal Channel As TPCANHandle, _
<MarshalAs(UnmanagedType.U1)> _
ByVal Parameter As TPCANParameter, _
<MarshalAs(UnmanagedType.LPStr, SizeParamIndex:=3)> _
ByVal StringBuffer As String, _
ByVal BufferLength As UInt32) As TPCANStatus
End Function
''' <summary>
''' Returns a descriptive text of a given TPCANStatus error
''' code, in any desired language
''' </summary>
''' <remarks>The current languages available for translation are:
''' Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
''' Italian (0x10) and French (0x0C)</remarks>
''' <param name="anError">A TPCANStatus error code</param>
''' <param name="Language">Indicates a 'Primary language ID'</param>
''' <param name="StringBuffer">Buffer for the text (must be at least 256 in length)</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_GetErrorText")>
Public Shared Function GetErrorText(
<MarshalAs(UnmanagedType.U4)>
ByVal anError As TPCANStatus,
ByVal Language As UInt16,
ByVal StringBuffer As StringBuilder) As TPCANStatus
End Function
''' <summary>
''' Finds a PCAN-Basic channel that matches with the given parameters
''' </summary>
''' <param name="Parameters">A comma separated string contained pairs of
''' parameter-name/value to be matched within a PCAN-Basic channel</param>
''' <param name="FoundChannel">Buffer for returning the PCAN-Basic channel,
''' when found</param>
''' <returns>A TPCANStatus error code</returns>
<DllImport("PCANBasic.dll", EntryPoint:="CAN_LookUpChannel")>
Public Shared Function LookUpChannel(
ByVal Parameters As String,
ByRef FoundChannel As TPCANHandle) As TPCANStatus
End Function
#End Region
End Class
#End Region
End Namespace
// PCANBasicCLR.h
//
// ~~~~~~~~~~~~
//
// PCAN-Basic API
//
// ~~~~~~~~~~~~
//
// ------------------------------------------------------------------
// Author : Keneth Wagner
// Last change: 2022-07-06
//
// Language: C++/CLR
// ------------------------------------------------------------------
//
// Copyright (C) 1999-2022 PEAK-System Technik GmbH, Darmstadt
// more Info at http://www.peak-system.com
//
using namespace System;
using namespace System::Text;
using namespace System::Runtime::InteropServices;
////////////////////////////////////////////////////////////
// Type definitions
////////////////////////////////////////////////////////////
#define TPCANHandle System::UInt16 // Represents a PCAN hardware channel handle
#define TPCANBitrateFD System::String^ // Represents a bit rate String (Flexible Data rate)
#define TPCANTimestampFD System::UInt64 // Represents a timestamp in microseconds
namespace Peak
{
namespace Can
{
namespace Basic
{
#pragma region Other Constants
/// <summary>
/// Maximum length of the name of a device: 32 characters + terminator
/// </summary>
static const int MAX_LENGTH_HARDWARE_NAME = 33;
/// <summary>
/// Maximum length of a version string: 255 characters + terminator
/// </summary>
static const int MAX_LENGTH_VERSION_STRING = 256;
#pragma endregion
#pragma region Enumerations
/// <summary>
/// Represents a PCAN status/error code
/// </summary>
[Flags]
public enum class TPCANStatus : UInt32
{
/// <summary>
/// No error
/// </summary>
PCAN_ERROR_OK = 0x00000,
/// <summary>
/// Transmit buffer in CAN controller is full
/// </summary>
PCAN_ERROR_XMTFULL = 0x00001,
/// <summary>
/// CAN controller was read too late
/// </summary>
PCAN_ERROR_OVERRUN = 0x00002,
/// <summary>
/// Bus error: an error counter reached the 'light' limit
/// </summary>
PCAN_ERROR_BUSLIGHT = 0x00004,
/// <summary>
/// Bus error: an error counter reached the 'heavy' limit
/// </summary>
PCAN_ERROR_BUSHEAVY = 0x00008,
/// <summary>
/// Bus error: an error counter reached the 'warning' limit
/// </summary>
PCAN_ERROR_BUSWARNING = PCAN_ERROR_BUSHEAVY,
/// <summary>
/// Bus error: the CAN controller is error passive
/// </summary>
PCAN_ERROR_BUSPASSIVE = 0x40000,
/// <summary>
/// Bus error: the CAN controller is in bus-off state
/// </summary>
PCAN_ERROR_BUSOFF = 0x00010,
/// <summary>
/// Mask for all bus errors
/// </summary>
PCAN_ERROR_ANYBUSERR = (PCAN_ERROR_BUSWARNING | PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY | PCAN_ERROR_BUSOFF | PCAN_ERROR_BUSPASSIVE),
/// <summary>
/// Receive queue is empty
/// </summary>
PCAN_ERROR_QRCVEMPTY = 0x00020,
/// <summary>
/// Receive queue was read too late
/// </summary>
PCAN_ERROR_QOVERRUN = 0x00040,
/// <summary>
/// Transmit queue is full
/// </summary>
PCAN_ERROR_QXMTFULL = 0x00080,
/// <summary>
/// Test of the CAN controller hardware registers failed (no hardware found)
/// </summary>
PCAN_ERROR_REGTEST = 0x00100,
/// <summary>
/// Driver not loaded
/// </summary>
PCAN_ERROR_NODRIVER = 0x00200,
/// <summary>
/// Hardware already in use by a Net
/// </summary>
PCAN_ERROR_HWINUSE = 0x00400,
/// <summary>
/// A Client is already connected to the Net
/// </summary>
PCAN_ERROR_NETINUSE = 0x00800,
/// <summary>
/// Hardware handle is invalid
/// </summary>
PCAN_ERROR_ILLHW = 0x01400,
/// <summary>
/// Net handle is invalid
/// </summary>
PCAN_ERROR_ILLNET = 0x01800,
/// <summary>
/// Client handle is invalid
/// </summary>
PCAN_ERROR_ILLCLIENT = 0x01C00,
/// <summary>
/// Mask for all handle errors
/// </summary>
PCAN_ERROR_ILLHANDLE = (PCAN_ERROR_ILLHW | PCAN_ERROR_ILLNET | PCAN_ERROR_ILLCLIENT),
/// <summary>
/// Resource (FIFO, Client, timeout) cannot be created
/// </summary>
PCAN_ERROR_RESOURCE = 0x02000,
/// <summary>
/// Invalid parameter
/// </summary>
PCAN_ERROR_ILLPARAMTYPE = 0x04000,
/// <summary>
/// Invalid parameter value
/// </summary>
PCAN_ERROR_ILLPARAMVAL = 0x08000,
/// <summary>
/// Unknown error
/// </summary>
PCAN_ERROR_UNKNOWN = 0x10000,
/// <summary>
/// Invalid data, function, or action.
/// </summary>
PCAN_ERROR_ILLDATA = 0x20000,
/// <summary>
/// Driver object state is wrong for the attempted operation
/// </summary>
PCAN_ERROR_ILLMODE = 0x80000,
/// <summary>
/// An operation was successfully carried out, however, irregularities were registered
/// </summary>
PCAN_ERROR_CAUTION = 0x2000000,
/// <summary>
/// Channel is not initialized
/// <remarks>Value was changed from 0x40000 to 0x4000000</remarks>
/// </summary>
PCAN_ERROR_INITIALIZE = 0x4000000,
/// <summary>
/// Invalid operation
/// <remarks>Value was changed from 0x80000 to 0x8000000</remarks>
/// </summary>
PCAN_ERROR_ILLOPERATION = 0x8000000,
};
/// <summary>
/// Represents a PCAN device
/// </summary>
public enum class TPCANDevice : Byte
{
/// <summary>
/// Undefined, unknown or not selected PCAN device value
/// </summary>
PCAN_NONE = 0,
/// <summary>
/// PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
/// </summary>
PCAN_PEAKCAN = 1,
/// <summary>
/// PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
/// </summary>
PCAN_ISA = 2,
/// <summary>
/// PCAN-Dongle
/// </summary>
PCAN_DNG = 3,
/// <summary>
/// PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
/// </summary>
PCAN_PCI = 4,
/// <summary>
/// PCAN-USB and PCAN-USB Pro
/// </summary>
PCAN_USB = 5,
/// <summary>
/// PCAN-PC Card
/// </summary>
PCAN_PCC = 6,
/// <summary>
/// PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
/// </summary>
PCAN_VIRTUAL = 7,
/// <summary>
/// PCAN Gateway devices
/// </summary>
PCAN_LAN = 8
};
/// <summary>
/// Represents a PCAN parameter to be read or set
/// </summary>
public enum class TPCANParameter : Byte
{
/// <summary>
/// Device identifier parameter
/// </summary>
PCAN_DEVICE_ID = 1,
/// <summary>
/// DEPRECATED. Use PCAN_DEVICE_ID instead
/// </summary>
[Obsolete]
PCAN_DEVICE_NUMBER = PCAN_DEVICE_ID,
/// <summary>
/// 5-Volt power parameter
/// </summary>
PCAN_5VOLTS_POWER = 2,
/// <summary>
/// PCAN receive event handler parameter
/// </summary>
PCAN_RECEIVE_EVENT = 3,
/// <summary>
/// PCAN message filter parameter
/// </summary>
PCAN_MESSAGE_FILTER = 4,
/// <summary>
/// PCAN-Basic API version parameter
/// </summary>
PCAN_API_VERSION = 5,
/// <summary>
/// PCAN device channel version parameter
/// </summary>
PCAN_CHANNEL_VERSION = 6,
/// <summary>
/// PCAN Reset-On-Busoff parameter
/// </summary>
PCAN_BUSOFF_AUTORESET = 7,
/// <summary>
/// PCAN Listen-Only parameter
/// </summary>
PCAN_LISTEN_ONLY = 8,
/// <summary>
/// Directory path for log files
/// </summary>
PCAN_LOG_LOCATION = 9,
/// <summary>
/// Debug-Log activation status
/// </summary>
PCAN_LOG_STATUS = 10,
/// <summary>
/// Configuration of the debugged information (LOG_FUNCTION_***)
/// </summary>
PCAN_LOG_CONFIGURE = 11,
/// <summary>
/// Custom insertion of text into the log file
/// </summary>
PCAN_LOG_TEXT = 12,
/// <summary>
/// Availability status of a PCAN-Channel
/// </summary>
PCAN_CHANNEL_CONDITION = 13,
/// <summary>
/// PCAN hardware name parameter
/// </summary>
PCAN_HARDWARE_NAME = 14,
/// <summary>
/// Message reception status of a PCAN-Channel
/// </summary>
PCAN_RECEIVE_STATUS = 15,
/// <summary>
/// CAN-Controller number of a PCAN-Channel
/// </summary>
PCAN_CONTROLLER_NUMBER = 16,
/// <summary>
/// Directory path for PCAN trace files
/// </summary>
PCAN_TRACE_LOCATION = 17,
/// <summary>
/// CAN tracing activation status
/// </summary>
PCAN_TRACE_STATUS = 18,
/// <summary>
/// Configuration of the maximum file size of a CAN trace
/// </summary>
PCAN_TRACE_SIZE = 19,
/// <summary>
/// Configuration of the trace file storing mode (TRACE_FILE_***)
/// </summary>
PCAN_TRACE_CONFIGURE = 20,
/// <summary>
/// Physical identification of a USB based PCAN-Channel by blinking its associated LED
/// </summary>
PCAN_CHANNEL_IDENTIFYING = 21,
/// <summary>
/// Capabilities of a PCAN device (FEATURE_***)
/// </summary>
PCAN_CHANNEL_FEATURES = 22,
/// <summary>
/// Using of an existing bit rate (PCAN-View connected to a channel)
/// </summary>
PCAN_BITRATE_ADAPTING = 23,
/// <summary>
/// Configured bit rate as Btr0Btr1 value
/// </summary>
PCAN_BITRATE_INFO = 24,
/// <summary>
/// Configured bit rate as TPCANBitrateFD string
/// </summary>
PCAN_BITRATE_INFO_FD = 25,
/// <summary>
/// Configured nominal CAN Bus speed as Bits per seconds
/// </summary>
PCAN_BUSSPEED_NOMINAL = 26,
/// <summary>
/// Configured CAN data speed as Bits per seconds
/// </summary>
PCAN_BUSSPEED_DATA = 27,
/// <summary>
/// Remote address of a LAN channel as string in IPv4 format
/// </summary>
PCAN_IP_ADDRESS = 28,
/// <summary>
/// Status of the Virtual PCAN-Gateway Service
/// </summary>
PCAN_LAN_SERVICE_STATUS = 29,
/// <summary>
/// Status messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_STATUS_FRAMES = 30,
/// <summary>
/// RTR messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_RTR_FRAMES = 31,
/// <summary>
/// Error messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_ERROR_FRAMES = 32,
/// <summary>
/// Delay, in microseconds, between sending frames
/// </summary>
PCAN_INTERFRAME_DELAY = 33,
/// <summary>
/// Filter over code and mask patterns for 11-Bit messages
/// </summary>
PCAN_ACCEPTANCE_FILTER_11BIT = 34,
/// <summary>
/// Filter over code and mask patterns for 29-Bit messages
/// </summary>
PCAN_ACCEPTANCE_FILTER_29BIT = 35,
/// <summary>
/// Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
/// </summary>
PCAN_IO_DIGITAL_CONFIGURATION = 36,
/// <summary>
/// Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
/// </summary>
PCAN_IO_DIGITAL_VALUE = 37,
/// <summary>
/// Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
/// </summary>
PCAN_IO_DIGITAL_SET = 38,
/// <summary>
/// Clear multiple digital I/O pins to 0
/// </summary>
PCAN_IO_DIGITAL_CLEAR = 39,
/// <summary>
/// Get value of a single analog input pin
/// </summary>
PCAN_IO_ANALOG_VALUE = 40,
/// <summary>
/// Get the version of the firmware used by the device associated with a PCAN-Channel
/// </summary>
PCAN_FIRMWARE_VERSION = 41,
/// <summary>
/// Get the amount of PCAN channels attached to a system
/// </summary>
PCAN_ATTACHED_CHANNELS_COUNT = 42,
/// <summary>
/// Get information about PCAN channels attached to a system
/// </summary>
PCAN_ATTACHED_CHANNELS = 43,
/// <summary>
/// Echo messages reception status within a PCAN-Channel
/// </summary>
PCAN_ALLOW_ECHO_FRAMES = 44,
/// <summary>
/// Get the part number associated to a device
/// </summary>
PCAN_DEVICE_PART_NUMBER = 45,
};
/// Represents the type of a PCAN message
/// </summary>
[Flags]
public enum class TPCANMessageType : Byte
{
/// <summary>
/// The PCAN message is a CAN Standard Frame (11-bit identifier)
/// </summary>
PCAN_MESSAGE_STANDARD = 0x00,
/// <summary>
/// The PCAN message is a CAN Remote-Transfer-Request Frame
/// </summary>
PCAN_MESSAGE_RTR = 0x01,
/// <summary>
/// The PCAN message is a CAN Extended Frame (29-bit identifier)
/// </summary>
PCAN_MESSAGE_EXTENDED = 0x02,
/// <summary>
/// The PCAN message represents a FD frame in terms of CiA Specs
/// </summary>
PCAN_MESSAGE_FD = 0x04,
/// <summary>
/// The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
/// </summary>
PCAN_MESSAGE_BRS = 0x08,
/// <summary>
/// The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
/// </summary>
PCAN_MESSAGE_ESI = 0x10,
/// <summary>
/// The PCAN message represents an echo CAN Frame
/// </summary>
PCAN_MESSAGE_ECHO = 0x20,
/// <summary>
/// The PCAN message represents an error frame
/// </summary>
PCAN_MESSAGE_ERRFRAME = 0x40,
/// <summary>
/// The PCAN message represents a PCAN status message
/// <summary>
/// </summary>
PCAN_MESSAGE_STATUS = 0x80,
};
/// <summary>
/// Represents a PCAN filter mode
/// </summary>
public enum class TPCANMode : Byte
{
/// <summary>
/// Mode is Standard (11-bit identifier)
/// </summary>
PCAN_MODE_STANDARD = TPCANMessageType::PCAN_MESSAGE_STANDARD,
/// <summary>
/// Mode is Extended (29-bit identifier)
/// </summary>
PCAN_MODE_EXTENDED = TPCANMessageType::PCAN_MESSAGE_EXTENDED,
};
/// <summary>
/// Represents a PCAN Baud rate register value
/// </summary>
public enum class TPCANBaudrate : UInt16
{
/// <summary>
/// 1 MBit/s
/// </summary>
PCAN_BAUD_1M = 0x0014,
/// <summary>
/// 800 kBit/s
/// </summary>
PCAN_BAUD_800K = 0x0016,
/// <summary>
/// 500 kBit/s
/// </summary>
PCAN_BAUD_500K = 0x001C,
/// <summary>
/// 250 kBit/s
/// </summary>
PCAN_BAUD_250K = 0x011C,
/// <summary>
/// 125 kBit/s
/// </summary>
PCAN_BAUD_125K = 0x031C,
/// <summary>
/// 100 kBit/s
/// </summary>
PCAN_BAUD_100K = 0x432F,
/// <summary>
/// 95,238 kBit/s
/// </summary>
PCAN_BAUD_95K = 0xC34E,
/// <summary>
/// 83,333 kBit/s
/// </summary>
PCAN_BAUD_83K = 0x852B,
/// <summary>
/// 50 kBit/s
/// </summary>
PCAN_BAUD_50K = 0x472F,
/// <summary>
/// 47,619 kBit/s
/// </summary>
PCAN_BAUD_47K = 0x1414,
/// <summary>
/// 33,333 kBit/s
/// </summary>
PCAN_BAUD_33K = 0x8B2F,
/// <summary>
/// 20 kBit/s
/// </summary>
PCAN_BAUD_20K = 0x532F,
/// <summary>
/// 10 kBit/s
/// </summary>
PCAN_BAUD_10K = 0x672F,
/// <summary>
/// 5 kBit/s
/// </summary>
PCAN_BAUD_5K = 0x7F7F,
};
/// <summary>
/// Represents the type of PCAN (Non-PnP) hardware to be initialized
/// </summary>
public enum class TPCANType : Byte
{
/// <summary>
/// PCAN-ISA 82C200
/// </summary>
PCAN_TYPE_ISA = 0x01,
/// <summary>
/// PCAN-ISA SJA1000
/// </summary>
PCAN_TYPE_ISA_SJA = 0x09,
/// <summary>
/// PHYTEC ISA
/// </summary>
PCAN_TYPE_ISA_PHYTEC = 0x04,
/// <summary>
/// PCAN-Dongle 82C200
/// </summary>
PCAN_TYPE_DNG = 0x02,
/// <summary>
/// PCAN-Dongle EPP 82C200
/// </summary>
PCAN_TYPE_DNG_EPP = 0x03,
/// <summary>
/// PCAN-Dongle SJA1000
/// </summary>
PCAN_TYPE_DNG_SJA = 0x05,
/// <summary>
/// PCAN-Dongle EPP SJA1000
/// </summary>
PCAN_TYPE_DNG_SJA_EPP = 0x06,
};
#pragma endregion
#pragma region Strutures
/// <summary>
/// Represents a PCAN message
/// </summary>
public value struct TPCANMsg
{
/// <summary>
/// 11/29-bit message identifier
/// </summary>
UInt32 ID;
/// <summary>
/// Type of the message
/// </summary>
[MarshalAs(UnmanagedType::U1)]
TPCANMessageType MSGTYPE;
/// <summary>
/// Data Length Code of the message (0..8)
/// </summary>
Byte LEN;
/// <summary>
/// Data of the message (DATA[0]..DATA[7])
/// </summary>
[MarshalAs(UnmanagedType::ByValArray, SizeConst = 8)]
array<Byte>^ DATA;
};
/// <summary>
/// Represents a timestamp of a received PCAN message.
/// Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
/// </summary>
public value struct TPCANTimestamp
{
/// <summary>
/// Base-value: milliseconds: 0.. 2^32-1
/// </summary>
UInt32 millis;
/// <summary>
/// Roll-arounds of millis
/// </summary>
UInt16 millis_overflow;
/// <summary>
/// Microseconds: 0..999
/// </summary>
UInt16 micros;
};
/// <summary>
/// Represents a PCAN message from a FD capable hardware
/// </summary>
public value struct TPCANMsgFD
{
/// <summary>
/// 11/29-bit message identifier
/// </summary>
UInt32 ID;
/// <summary>
/// Type of the message
/// </summary>
[MarshalAs(UnmanagedType::U1)]
TPCANMessageType MSGTYPE;
/// <summary>
/// Data Length Code of the message (0..15)
/// </summary>
Byte DLC;
/// <summary>
/// Data of the message (DATA[0]..DATA[63])
/// </summary>
[MarshalAs(UnmanagedType::ByValArray, SizeConst = 64)]
array<Byte>^ DATA;
};
/// <summary>
/// Describes an available PCAN channel
/// </summary>
public value struct TPCANChannelInformation
{
/// <summary>
/// PCAN channel handle
/// </summary>
[MarshalAs(UnmanagedType::U2)]
TPCANHandle channel_handle;
/// <summary>
/// Kind of PCAN device
/// </summary>
[MarshalAs(UnmanagedType::U1)]
TPCANDevice device_type;
/// <summary>
/// CAN-Controller number
/// </summary>
Byte controller_number;
/// <summary>
/// Device capabilities flag (see FEATURE_*)
/// </summary>
UInt32 device_features;
/// <summary>
/// Device name
/// </summary>
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_LENGTH_HARDWARE_NAME)]
String^ device_name;
/// <summary>
/// Device number
/// </summary>
UInt32 device_id;
/// <summary>
/// Availability status of a PCAN-Channel
/// </summary>
UInt32 channel_condition;
};
#pragma endregion
#pragma region PCANBasic class
/// <summary>
/// PCAN-Basic API class implementation
/// </summary>
public ref class PCANBasic abstract sealed
{
public:
#pragma region PCAN-BUS Handles Definition
/// <summary>
/// Undefined/default value for a PCAN bus
/// </summary>
static const TPCANHandle PCAN_NONEBUS = 0x00;
/// <summary>
/// PCAN-ISA interface, channel 1
/// </summary>
static const TPCANHandle PCAN_ISABUS1 = 0x21;
/// <summary>
/// PCAN-ISA interface, channel 2
/// </summary>
static const TPCANHandle PCAN_ISABUS2 = 0x22;
/// <summary>
/// PCAN-ISA interface, channel 3
/// </summary>
static const TPCANHandle PCAN_ISABUS3 = 0x23;
/// <summary>
/// PCAN-ISA interface, channel 4
/// </summary>
static const TPCANHandle PCAN_ISABUS4 = 0x24;
/// <summary>
/// PCAN-ISA interface, channel 5
/// </summary>
static const TPCANHandle PCAN_ISABUS5 = 0x25;
/// <summary>
/// PCAN-ISA interface, channel 6
/// </summary>
static const TPCANHandle PCAN_ISABUS6 = 0x26;
/// <summary>
/// PCAN-ISA interface, channel 7
/// </summary>
static const TPCANHandle PCAN_ISABUS7 = 0x27;
/// <summary>
/// PCAN-ISA interface, channel 8
/// </summary>
static const TPCANHandle PCAN_ISABUS8 = 0x28;
/// <summary>
/// PPCAN-Dongle/LPT interface, channel 1
/// </summary>
static const TPCANHandle PCAN_DNGBUS1 = 0x31;
/// <summary>
/// PCAN-PCI interface, channel 1
/// </summary>
static const TPCANHandle PCAN_PCIBUS1 = 0x41;
/// <summary>
/// PCAN-PCI interface, channel 2
/// </summary>
static const TPCANHandle PCAN_PCIBUS2 = 0x42;
/// <summary>
/// PCAN-PCI interface, channel 3
/// </summary>
static const TPCANHandle PCAN_PCIBUS3 = 0x43;
/// <summary>
/// PCAN-PCI interface, channel 4
/// </summary>
static const TPCANHandle PCAN_PCIBUS4 = 0x44;
/// <summary>
/// PCAN-PCI interface, channel 5
/// </summary>
static const TPCANHandle PCAN_PCIBUS5 = 0x45;
/// <summary>
/// PCAN-PCI interface, channel 6
/// </summary>
static const TPCANHandle PCAN_PCIBUS6 = 0x46;
/// <summary>
/// PCAN-PCI interface, channel 7
/// </summary>
static const TPCANHandle PCAN_PCIBUS7 = 0x47;
/// <summary>
/// PCAN-PCI interface, channel 8
/// </summary>
static const TPCANHandle PCAN_PCIBUS8 = 0x48;
/// <summary>
/// PCAN-PCI interface, channel 9
/// </summary>
static const TPCANHandle PCAN_PCIBUS9 = 0x409;
/// <summary>
/// PCAN-PCI interface, channel 10
/// </summary>
static const TPCANHandle PCAN_PCIBUS10 = 0x40A;
/// <summary>
/// PCAN-PCI interface, channel 11
/// </summary>
static const TPCANHandle PCAN_PCIBUS11 = 0x40B;
/// <summary>
/// PCAN-PCI interface, channel 12
/// </summary>
static const TPCANHandle PCAN_PCIBUS12 = 0x40C;
/// <summary>
/// PCAN-PCI interface, channel 13
/// </summary>
static const TPCANHandle PCAN_PCIBUS13 = 0x40D;
/// <summary>
/// PCAN-PCI interface, channel 14
/// </summary>
static const TPCANHandle PCAN_PCIBUS14 = 0x40E;
/// <summary>
/// PCAN-PCI interface, channel 15
/// </summary>
static const TPCANHandle PCAN_PCIBUS15 = 0x40F;
/// <summary>
/// PCAN-PCI interface, channel 16
/// </summary>
static const TPCANHandle PCAN_PCIBUS16 = 0x410;
/// <summary>
/// PCAN-USB interface, channel 1
/// </summary>
static const TPCANHandle PCAN_USBBUS1 = 0x51;
/// <summary>
/// PCAN-USB interface, channel 2
/// </summary>
static const TPCANHandle PCAN_USBBUS2 = 0x52;
/// <summary>
/// PCAN-USB interface, channel 3
/// </summary>
static const TPCANHandle PCAN_USBBUS3 = 0x53;
/// <summary>
/// PCAN-USB interface, channel 4
/// </summary>
static const TPCANHandle PCAN_USBBUS4 = 0x54;
/// <summary>
/// PCAN-USB interface, channel 5
/// </summary>
static const TPCANHandle PCAN_USBBUS5 = 0x55;
/// <summary>
/// PCAN-USB interface, channel 6
/// </summary>
static const TPCANHandle PCAN_USBBUS6 = 0x56;
/// <summary>
/// PCAN-USB interface, channel 7
/// </summary>
static const TPCANHandle PCAN_USBBUS7 = 0x57;
/// <summary>
/// PCAN-USB interface, channel 8
/// </summary>
static const TPCANHandle PCAN_USBBUS8 = 0x58;
/// <summary>
/// PCAN-USB interface, channel 9
/// </summary>
static const TPCANHandle PCAN_USBBUS9 = 0x509;
/// <summary>
/// PCAN-USB interface, channel 10
/// </summary>
static const TPCANHandle PCAN_USBBUS10 = 0x50A;
/// <summary>
/// PCAN-USB interface, channel 11
/// </summary>
static const TPCANHandle PCAN_USBBUS11 = 0x50B;
/// <summary>
/// PCAN-USB interface, channel 12
/// </summary>
static const TPCANHandle PCAN_USBBUS12 = 0x50C;
/// <summary>
/// PCAN-USB interface, channel 13
/// </summary>
static const TPCANHandle PCAN_USBBUS13 = 0x50D;
/// <summary>
/// PCAN-USB interface, channel 14
/// </summary>
static const TPCANHandle PCAN_USBBUS14 = 0x50E;
/// <summary>
/// PCAN-USB interface, channel 15
/// </summary>
static const TPCANHandle PCAN_USBBUS15 = 0x50F;
/// <summary>
/// PCAN-USB interface, channel 16
/// </summary>
static const TPCANHandle PCAN_USBBUS16 = 0x510;
/// <summary>
/// PCAN-PC Card interface, channel 1
/// </summary>
static const TPCANHandle PCAN_PCCBUS1 = 0x61;
/// <summary>
/// PCAN-PC Card interface, channel 2
/// </summary>
static const TPCANHandle PCAN_PCCBUS2 = 0x62;
/// <summary>
/// PCAN-LAN interface, channel 1
/// </summary>
static const TPCANHandle PCAN_LANBUS1 = 0x801;
/// <summary>
/// PCAN-LAN interface, channel 2
/// </summary>
static const TPCANHandle PCAN_LANBUS2 = 0x802;
/// <summary>
/// PCAN-LAN interface, channel 3
/// </summary>
static const TPCANHandle PCAN_LANBUS3 = 0x803;
/// <summary>
/// PCAN-LAN interface, channel 4
/// </summary>
static const TPCANHandle PCAN_LANBUS4 = 0x804;
/// <summary>
/// PCAN-LAN interface, channel 5
/// </summary>
static const TPCANHandle PCAN_LANBUS5 = 0x805;
/// <summary>
/// PCAN-LAN interface, channel 6
/// </summary>
static const TPCANHandle PCAN_LANBUS6 = 0x806;
/// <summary>
/// PCAN-LAN interface, channel 7
/// </summary>
static const TPCANHandle PCAN_LANBUS7 = 0x807;
/// <summary>
/// PCAN-LAN interface, channel 8
/// </summary>
static const TPCANHandle PCAN_LANBUS8 = 0x808;
/// <summary>
/// PCAN-LAN interface, channel 9
/// </summary>
static const TPCANHandle PCAN_LANBUS9 = 0x809;
/// <summary>
/// PCAN-LAN interface, channel 10
/// </summary>
static const TPCANHandle PCAN_LANBUS10 = 0x80A;
/// <summary>
/// PCAN-LAN interface, channel 11
/// </summary>
static const TPCANHandle PCAN_LANBUS11 = 0x80B;
/// <summary>
/// PCAN-LAN interface, channel 12
/// </summary>
static const TPCANHandle PCAN_LANBUS12 = 0x80C;
/// <summary>
/// PCAN-LAN interface, channel 13
/// </summary>
static const TPCANHandle PCAN_LANBUS13 = 0x80D;
/// <summary>
/// PCAN-LAN interface, channel 14
/// </summary>
static const TPCANHandle PCAN_LANBUS14 = 0x80E;
/// <summary>
/// PCAN-LAN interface, channel 15
/// </summary>
static const TPCANHandle PCAN_LANBUS15 = 0x80F;
/// <summary>
/// PCAN-LAN interface, channel 16
/// </summary>
static const TPCANHandle PCAN_LANBUS16 = 0x810;
#pragma endregion
#pragma region FD Bit rate definition
/// <summary>
/// Clock frequency in Herz (80000000, 60000000, 40000000, 30000000, 24000000, 20000000)
/// </summary>
static const String^ PCAN_BR_CLOCK = "f_clock";
/// <summary>
/// Clock frequency in Megaherz (80, 60, 40, 30, 24, 20)
/// </summary>
static const String^ PCAN_BR_CLOCK_MHZ = "f_clock_mhz";
/// <summary>
/// Clock prescaler for nominal time quantum
/// </summary>
static const String^ PCAN_BR_NOM_BRP = "nom_brp";
/// <summary>
/// TSEG1 segment for nominal bit rate in time quanta
/// </summary>
static const String^ PCAN_BR_NOM_TSEG1 = "nom_tseg1";
/// <summary>
/// TSEG2 segment for nominal bit rate in time quanta
/// </summary>
static const String^ PCAN_BR_NOM_TSEG2 = "nom_tseg2";
/// <summary>
/// Synchronization Jump Width for nominal bit rate in time quanta
/// </summary>
static const String^ PCAN_BR_NOM_SJW = "nom_sjw";
/// <summary>
/// Sample point for nominal bit rate
/// </summary>
static const String^ PCAN_BR_NOM_SAMPLE = "nom_sam";
/// <summary>
/// Clock prescaler for highspeed data time quantum
/// </summary>
static const String^ PCAN_BR_DATA_BRP = "data_brp";
/// <summary>
/// TSEG1 segment for fast data bit rate in time quanta
/// </summary>
static const String^ PCAN_BR_DATA_TSEG1 = "data_tseg1";
/// <summary>
/// TSEG2 segment for fast data bit rate in time quanta
/// </summary>
static const String^ PCAN_BR_DATA_TSEG2 = "data_tseg2";
/// <summary>
/// Synchronization Jump Width for highspeed data bit rate in time quanta
/// </summary>
static const String^ PCAN_BR_DATA_SJW = "data_sjw";
/// <summary>
/// Secondary sample point delay for highspeed data bit rate in cyles
/// </summary>
static const String^ PCAN_BR_DATA_SAMPLE = "data_ssp_offset";
#pragma endregion
#pragma region Parameter values definition
/// <summary>
/// The PCAN parameter is not set (inactive)
/// </summary>
static const int PCAN_PARAMETER_OFF = 0;
/// <summary>
/// The PCAN parameter is set (active)
/// </summary>
static const int PCAN_PARAMETER_ON = 1;
/// <summary>
/// The PCAN filter is closed. No messages will be received
/// </summary>
static const int PCAN_FILTER_CLOSE = 0;
/// <summary>
/// The PCAN filter is fully opened. All messages will be received
/// </summary>
static const int PCAN_FILTER_OPEN = 1;
/// <summary>
/// The PCAN filter is custom configured. Only registered
/// messages will be received
/// </summary>
static const int PCAN_FILTER_CUSTOM = 2;
/// <summary>
/// The PCAN-Channel handle is illegal, or its associated hardware is not available
/// </summary>
static const int PCAN_CHANNEL_UNAVAILABLE = 0;
/// <summary>
/// The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
/// </summary>
static const int PCAN_CHANNEL_AVAILABLE = 1;
/// <summary>
/// The PCAN-Channel handle is valid, and is already being used
/// </summary>
static const int PCAN_CHANNEL_OCCUPIED = 2;
/// <summary>
/// The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
/// </summary>
static const int PCAN_CHANNEL_PCANVIEW = PCAN_CHANNEL_AVAILABLE | PCAN_CHANNEL_OCCUPIED;
/// <summary>
/// Logs system exceptions / errors
/// </summary>
static const int LOG_FUNCTION_DEFAULT = 0x00;
/// <summary>
/// Logs the entries to the PCAN-Basic API functions
/// </summary>
static const int LOG_FUNCTION_ENTRY = 0x01;
/// <summary>
/// Logs the parameters passed to the PCAN-Basic API functions
/// </summary>
static const int LOG_FUNCTION_PARAMETERS = 0x02;
/// <summary>
/// Logs the exits from the PCAN-Basic API functions
/// </summary>
static const int LOG_FUNCTION_LEAVE = 0x04;
/// <summary>
/// Logs the CAN messages passed to the CAN_Write function
/// </summary>
static const int LOG_FUNCTION_WRITE = 0x08;
/// <summary>
/// Logs the CAN messages received within the CAN_Read function
/// </summary>
static const int LOG_FUNCTION_READ = 0x10;
/// <summary>
/// Logs all possible information within the PCAN-Basic API functions
/// </summary>
static const int LOG_FUNCTION_ALL = 0xFFFF;
/// <summary>
/// A single file is written until it size reaches PAN_TRACE_SIZE
/// </summary>
static const int TRACE_FILE_SINGLE = 0x00;
/// <summary>
/// Traced data is distributed in several files with size PAN_TRACE_SIZE
/// </summary>
static const int TRACE_FILE_SEGMENTED = 0x01;
/// <summary>
/// Includes the date into the name of the trace file
/// </summary>
static const int TRACE_FILE_DATE = 0x02;
/// <summary>
/// Includes the start time into the name of the trace file
/// </summary>
static const int TRACE_FILE_TIME = 0x04;
/// <summary>
/// Causes the overwriting of available traces (same name)
/// </summary>
static const int TRACE_FILE_OVERWRITE = 0x80;
/// <summary>
/// Device supports flexible data-rate (CAN-FD)
/// </summary>
static const int FEATURE_FD_CAPABLE = 0x01;
/// <summary>
/// Device supports a delay between sending frames (FPGA based USB devices)
/// </summary>
static const int FEATURE_DELAY_CAPABLE = 0x02;
/// <summary>
/// Device supports I/O functionality for electronic circuits (USB-Chip devices)
/// </summary>
static const int FEATURE_IO_CAPABLE = 0x04;
/// The service is not running
/// <summary>
/// </summary>
static const int SERVICE_STATUS_STOPPED = 0x01;
/// <summary>
/// The service is running
/// </summary>
static const int SERVICE_STATUS_RUNNING = 0x04;
#pragma endregion
#pragma region Lookup Parameters
/// <summary>
/// Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
/// </summary>
static const String^ LOOKUP_DEVICE_TYPE = "devicetype";
/// <summary>
/// Lookup channel by device id
/// </summary>
static const String^ LOOKUP_DEVICE_ID = "deviceid";
/// <summary>
/// Lookup channel by CAN controller 0-based index
/// </summary>
static const String^ LOOKUP_CONTROLLER_NUMBER = "controllernumber";
/// <summary>
/// Lookup channel by IP address (LAN channels only)
/// </summary>
static const String^ LOOKUP_IP_ADDRESS = "ipaddress";
#pragma endregion
#pragma region PCANBasic API Implementation
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
/// <param name="HwType">Non-PnP: The type of hardware and operation mode</param>
/// <param name="IOPort">Non-PnP: The I/O address for the parallel port</param>
/// <param name="Interrupt">Non-PnP: Interrupt number of the parallel por</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Initialize")]
static TPCANStatus Initialize(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U2)]
TPCANBaudrate Btr0Btr1,
[MarshalAs(UnmanagedType::U1)]
TPCANType HwType,
UInt32 IOPort,
UInt16 Interrupt);
/// <summary>
/// Initializes a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Btr0Btr1">The speed for the communication (BTR0BTR1 code)</param>
/// <returns>A TPCANStatus error code</returns>
static TPCANStatus Initialize(
TPCANHandle Channel,
TPCANBaudrate Btr0Btr1)
{
return Initialize(Channel, Btr0Btr1, (TPCANType)0, 0, 0);
}
/// <summary>
/// Initializes a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="BitrateFD">The speed for the communication (FD bit rate string)</param>
/// <remarks> See PCAN_BR_* values
/// Bit rate string must follow the following construction rules:
/// * parameter and values must be separated by '='
/// * Couples of Parameter/value must be separated by ','
/// * Following Parameter must be filled out: f_clock, data_brp, data_sjw, data_tseg1, data_tseg2,
/// nom_brp, nom_sjw, nom_tseg1, nom_tseg2.
/// * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam</remarks>
/// <example>f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1</example>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_InitializeFD")]
static TPCANStatus InitializeFD(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANBitrateFD BitrateFD);
/// <summary>
/// Uninitializes one or all PCAN Channels initialized by CAN_Initialize
/// </summary>
/// <remarks>Giving the TPCANHandle value "PCAN_NONEBUS",
/// uninitialize all initialized channels</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Uninitialize")]
static TPCANStatus Uninitialize(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel);
/// <summary>
/// Resets the receive and transmit queues of the PCAN Channel
/// </summary>
/// <remarks>A reset of the CAN controller is not performed</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Reset")]
static TPCANStatus Reset(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel);
/// <summary>
/// Gets the current status of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetStatus")]
static TPCANStatus GetStatus(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel);
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestamp structure buffer to get
/// the reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
static TPCANStatus Read(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANMsg %MessageBuffer,
TPCANTimestamp %TimestampBuffer);
private:
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Read")]
static TPCANStatus Read(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANMsg %MessageBuffer,
IntPtr bufferPointer);
public:
/// <summary>
/// Reads a CAN message from the receive queue of a PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg structure buffer to store the CAN message</param>
/// <returns>A TPCANStatus error code</returns>
static TPCANStatus Read(
TPCANHandle Channel,
TPCANMsg %MessageBuffer)
{
return Read(Channel, MessageBuffer, IntPtr::Zero);
}
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestampFD buffer to get the
/// reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_ReadFD")]
static TPCANStatus ReadFD(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANMsgFD %MessageBuffer,
TPCANTimestampFD %TimestampBuffer);
private:
[DllImport("PCANBasic.dll", EntryPoint = "CAN_ReadFD")]
static TPCANStatus ReadFD(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANMsgFD %MessageBuffer,
IntPtr bufferPointer);
public:
/// <summary>
/// Reads a CAN message from the receive queue of a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD structure buffer to store the CAN message</param>
/// <param name="TimestampBuffer">A TPCANTimestampFD buffer to get the
/// reception time of the message</param>
/// <returns>A TPCANStatus error code</returns>
static TPCANStatus ReadFD(
TPCANHandle Channel,
TPCANMsgFD %MessageBuffer)
{
return ReadFD(Channel, MessageBuffer, IntPtr::Zero);
}
/// <summary>
/// Transmits a CAN message
/// </summary>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsg buffer with the message to be sent</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_Write")]
static TPCANStatus Write(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANMsg %MessageBuffer);
/// <summary>
/// Transmits a CAN message over a FD capable PCAN Channel
/// </summary>
/// <param name="Channel">The handle of a FD capable PCAN Channel</param>
/// <param name="MessageBuffer">A TPCANMsgFD buffer with the message to be sent</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_WriteFD")]
static TPCANStatus WriteFD(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
TPCANMsgFD %MessageBuffer);
/// <summary>
/// Configures the reception filter
/// </summary>
/// <remarks>The message filter will be expanded with every call to
/// this function. If it is desired to reset the filter, please use
/// the 'SetValue' function</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="FromID">The lowest CAN ID to be received</param>
/// <param name="ToID">The highest CAN ID to be received</param>
/// <param name="Mode">Message type, Standard (11-bit identifier) or
/// Extended (29-bit identifier)</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_FilterMessages")]
static TPCANStatus FilterMessages(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
UInt32 FromID,
UInt32 ToID,
[MarshalAs(UnmanagedType::U1)]
TPCANMode Mode);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="StringBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
static TPCANStatus GetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
StringBuilder^ StringBuffer,
UInt32 BufferLength);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="NumericBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
static TPCANStatus GetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
UInt32 %NumericBuffer,
UInt32 BufferLength);
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="NumericBuffer">Buffer for the parameter value</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
static TPCANStatus GetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
UInt64 %NumericBuffer,
UInt32 BufferLength);
private:
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetValue")]
static TPCANStatus GetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
[MarshalAs(UnmanagedType::LPArray, SizeParamIndex=3)]
[In, Out]array<TPCANChannelInformation> ^ChannelBuffer,
UInt32 BufferLength);
public:
/// <summary>
/// Retrieves a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to get</param>
/// <param name="ChannelsBuffer">Buffer for the parameter value</param>
/// <returns>A TPCANStatus error code</returns>
static TPCANStatus GetValue(
TPCANHandle Channel,
TPCANParameter Parameter,
array<TPCANChannelInformation> ^ChannelsBuffer)
{
if(ChannelsBuffer == nullptr)
return TPCANStatus::PCAN_ERROR_ILLPARAMVAL;
return GetValue(Channel, Parameter, ChannelsBuffer, ChannelsBuffer->Length * Marshal::SizeOf(TPCANChannelInformation::typeid));
}
/// <summary>
/// Configures a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="NumericBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_SetValue")]
static TPCANStatus SetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
UInt32% NumericBuffer,
UInt32 BufferLength);
/// <summary>
/// Configures a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter">The TPCANParameter parameter to set</param>
/// <param name="NumericBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_SetValue")]
static TPCANStatus SetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
UInt64% NumericBuffer,
UInt32 BufferLength);
/// <summary>
/// Configures a PCAN Channel value
/// </summary>
/// <remarks>Parameters can be present or not according with the kind
/// of Hardware (PCAN Channel) being used. If a parameter is not available,
/// a PCAN_ERROR_ILLPARAMTYPE error will be returned</remarks>
/// <param name="Channel">The handle of a PCAN Channel</param>
/// <param name="Parameter"></param>
/// <param name="StringBuffer">Buffer with the value to be set</param>
/// <param name="BufferLength">Size in bytes of the buffer</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_SetValue")]
static TPCANStatus SetValue(
[MarshalAs(UnmanagedType::U2)]
TPCANHandle Channel,
[MarshalAs(UnmanagedType::U1)]
TPCANParameter Parameter,
[MarshalAs(UnmanagedType::LPStr,SizeParamIndex=3)]
String^ StringBuffer,
UInt32 BufferLength);
/// <summary>
/// Returns a descriptive text of a given TPCANStatus error
/// code, in any desired language
/// </summary>
/// <remarks>The current languages available for translation are:
/// Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
/// Italian (0x10) and French (0x0C)</remarks>
/// <param name="Error">A TPCANStatus error code</param>
/// <param name="Language">Indicates a 'Primary language ID'</param>
/// <param name="StringBuffer">Buffer for the text (must be at least 256 in length)</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_GetErrorText")]
static TPCANStatus GetErrorText(
[MarshalAs(UnmanagedType::U4)]
TPCANStatus Error,
UInt16 Language,
StringBuilder^ StringBuffer);
/// <summary>
/// Finds a PCAN-Basic channel that matches with the given parameters
/// </summary>
/// <param name="Parameters">A comma separated string contained pairs of
/// parameter-name/value to be matched within a PCAN-Basic channel</param>
/// <param name="FoundChannel">Buffer for returning the PCAN-Basic channel,
/// when found</param>
/// <returns>A TPCANStatus error code</returns>
[DllImport("PCANBasic.dll", EntryPoint = "CAN_LookUpChannel")]
static TPCANStatus LookUpChannel(
String^ Parameters,
TPCANHandle% FoundChannel);
#pragma endregion
};
#pragma endregion
}
}
}
\ No newline at end of file
#ifndef RM_DEFINE_H
#define RM_DEFINE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#define ARM_DOF 7
#define M_PI 3.14159265358979323846
#define RM_MOVE_NBLOCK 0 ///<机械臂运动设置,非阻塞模式
#define RM_MOVE_MULTI_BLOCK 1 ///<机械臂运动设置,多线程阻塞模式
static inline int RM_MOVE_SINGLE_BLOCK(int timeout){return timeout;} ///<机械臂运动设置,单线程阻塞模式超时时间
/**
* @brief 线程模式
* @ingroup Init_Class
*/
typedef enum {
RM_SINGLE_MODE_E, ///< 单线程模式,单线程非阻塞等待数据返回
RM_DUAL_MODE_E, ///< 双线程模式,增加接收线程监测队列中的数据
RM_TRIPLE_MODE_E, ///< 三线程模式,在双线程模式基础上增加线程监测UDP接口数据
}rm_thread_mode_e;
/**
* @brief 机械臂型号
* @ingroup Algo
*/
typedef enum{
RM_MODEL_RM_65_E, ///< RM_65
RM_MODEL_RM_75_E, ///< RM_75
RM_MODEL_RM_63_I_E, ///< RML_63I(已弃用)
RM_MODEL_RM_63_II_E, ///< RML_63II
RM_MODEL_RM_63_III_E, ///< RML_63III
RM_MODEL_ECO_65_E, ///< ECO_65
RM_MODEL_ECO_62_E, ///< ECO_62
RM_MODEL_GEN_72_E, ///< GEN_72
RM_MODEL_ECO_63_E, ///< ECO63
RM_MODEL_UNIVERSAL_E
}rm_robot_arm_model_e;
/**
* @brief 机械臂末端力传感器版本
* @ingroup Algo
*/
typedef enum{
RM_MODEL_RM_B_E, ///< 标准版
RM_MODEL_RM_ZF_E, ///< 一维力版
RM_MODEL_RM_SF_E, ///< 六维力版
RM_MODEL_RM_ISF_E, ///< 一体化六维力版
}rm_force_type_e;
/**
* @brief 事件类型
* @ingroup Init_Class
*/
typedef enum
{
RM_NONE_EVENT_E, ///< 无事件
RM_CURRENT_TRAJECTORY_STATE_E, ///< 当前轨迹到位
RM_PROGRAM_RUN_FINISH_E, ///< 在线编程运行结束
} rm_event_type_e;
/**
* @brief 事件信息
* @ingroup Init_Class
*/
typedef struct
{
int handle_id; ///< 返回消息的机械臂id
rm_event_type_e event_type; ///< 事件类型,包含无事件、当前轨迹到位、在线编程运行结束
bool trajectory_state; ///< 当前轨迹到位状态
int device; ///< 到位设备,0:关节 1:夹爪 2:灵巧手 3:升降机构 4:扩展关节 其他:保留
int trajectory_connect; ///< 是否连接下一条轨迹,0:全部到位,1:连接下一条轨迹
int program_id; ///< 运行结束的在线编程程序id
}rm_event_push_data_t;
/**
* @brief 机械臂当前规划类型
*
*/
typedef enum
{
RM_NO_PLANNING_E, ///< 无规划
RM_JOINT_SPACE_PLANNING_E, ///< 关节空间规划
RM_CARTESIAN_LINEAR_PLANNING_E, ///< 笛卡尔空间直线规划
RM_CARTESIAN_ARC_PLANNING_E, ///< 笛卡尔空间圆弧规划
RM_SPLINE_CURVE_MOTION_PLANNING_E, ///< 样条曲线运动规划
RM_TRAJECTORY_REPLAY_PLANNING_E, ///< 示教轨迹复现规划
}rm_arm_current_trajectory_e;
typedef struct
{
int joint_speed; ///< 关节速度。
int lift_state; ///< 升降关节信息。1:上报;0:关闭上报;-1:不设置,保持之前的状态
int expand_state; ///< 扩展关节信息(升降关节和扩展关节为二选一,优先显示升降关节)1:上报;0:关闭上报;-1:不设置,保持之前的状态
int hand_state; ///< 灵巧手状态。1:上报;0:关闭上报;-1:不设置,保持之前的状态(1.7.0版本无这个)
int arm_current_status; ///< 机械臂当前状态。1:上报;0:关闭上报;-1:不设置,保持之前的状态
int aloha_state; ///< aloha主臂状态是否上报。1:上报;0:关闭上报;-1:不设置,保持之前的状态
int plus_base; ///< 末端设备基础信息。1:上报;0:关闭上报;-1:不设置,保持之前的状态
int plus_state; ///< 末端设备实时信息。1:上报;0:关闭上报;-1:不设置,保持之前的状态
}rm_udp_custom_config_t;
/**
* @brief 机械臂主动上报接口配置
* @ingroup UdpConfig
*/
typedef struct {
int cycle; ///< 广播周期,5ms的倍数
bool enable; ///< 使能,是否主动上报
int port; ///< 广播的端口号
int force_coordinate; ///< 系统外受力数据的坐标系,-1不支持力传感器 0为传感器坐标系 1为当前工作坐标系 2为当前工具坐标系
char ip[28]; ///< 自定义的上报目标IP地址
rm_udp_custom_config_t custom_config; ///< 自定义项内容
} rm_realtime_push_config_t;
/**
* @brief 四元数
*
*/
typedef struct
{
float w;
float x;
float y;
float z;
} rm_quat_t;
/**
* @brief 位置坐标
*
*/
typedef struct
{
float x; //* unit: m
float y;
float z;
} rm_position_t;
/**
* @brief 欧拉角
*
*/
typedef struct
{
float rx; //* unit: rad
float ry;
float rz;
} rm_euler_t;
/**
* @brief 机械臂位置姿态结构体
* @ingroup Algo
*/
typedef struct
{
rm_position_t position; ///< 位置,单位:m
rm_quat_t quaternion; ///< 四元数
rm_euler_t euler; ///< 欧拉角,单位:rad
}rm_pose_t;
/**
* @brief 坐标系名称
* 不超过10个字符
* @ingroup ToolCoordinateConfig
* @ingroup WorkCoordinateConfig
*/
typedef struct
{
char name[12];
}rm_frame_name_t;
/**
* @brief 坐标系
* @ingroup Algo
* @ingroup ToolCoordinateConfig
* @ingroup WorkCoordinateConfig
*/
typedef struct
{
char frame_name[12]; ///< 坐标系名称
rm_pose_t pose; ///< 坐标系位姿
float payload; ///< 坐标系末端负载重量,单位:kg
float x; ///< 坐标系末端负载质心位置,单位:m
float y; ///< 坐标系末端负载质心位置,单位:m
float z; ///< 坐标系末端负载质心位置,单位:m
}rm_frame_t;
typedef struct{
char build_time[20]; ///< 编译时间
char version[20]; ///< 版本号
}rm_ctrl_version_t;
typedef struct{
char model_version[5]; ///< 动力学模型版本号
}rm_dynamic_version_t;
typedef struct{
char build_time[20]; ///<编译时间
char version[20]; ///< 版本号
}rm_planinfo_t;
typedef struct {
char version[20]; ///< 算法库版本号
}rm_algorithm_version_t;
typedef struct {
char build_time[20]; ///<编译时间
char version[20]; ///< 版本号
}rm_software_build_info_t;
/**
* @brief 机械臂软件信息
*
*/
typedef struct
{
char product_version[20]; ///< 机械臂型号
char robot_controller_version[10]; ///< 机械臂控制器版本,若为四代控制器,则该字段为"4.0"
rm_algorithm_version_t algorithm_info; ///< 算法库信息
rm_software_build_info_t ctrl_info; ///< ctrl 层软件信息
rm_dynamic_version_t dynamic_info; ///< 动力学版本(三代)
rm_software_build_info_t plan_info; ///< plan 层软件信息(三代)
rm_software_build_info_t com_info; ///< communication 模块软件信息(四代)
rm_software_build_info_t program_info; ///< 流程图编程模块软件信息(四代)
}rm_arm_software_version_t;
/**
* @brief 错误代码结构体
*
*/
typedef struct
{
uint8_t err_len; ///< 错误代码个数
int err[24]; ///< 错误代码数组
}rm_err_t;
/**
* @brief 机械臂当前状态
*
*/
typedef struct
{
rm_pose_t pose; ///< 机械臂当前位姿
float joint[ARM_DOF]; ///< 机械臂当前关节角度
rm_err_t err;
}rm_current_arm_state_t;
/**
* @brief 机械臂关节状态参数
*
*/
typedef struct
{
float joint_current[ARM_DOF]; ///< 关节电流,单位mA,精度:0.001mA
bool joint_en_flag[ARM_DOF]; ///< 当前关节使能状态 ,1为上使能,0为掉使能
uint16_t joint_err_code[ARM_DOF]; ///< 当前关节错误码
float joint_position[ARM_DOF]; ///< 关节角度,单位°,精度:0.001°
float joint_temperature[ARM_DOF]; ///< 当前关节温度,精度0.001℃
float joint_voltage[ARM_DOF]; ///< 当前关节电压,精度0.001V
float joint_speed[ARM_DOF]; ///< 当前关节速度,精度0.01RPM。
}rm_joint_status_t;
/**
* @brief 位置示教方向
*
*/
typedef enum
{
RM_X_DIR_E, ///< 位置示教,x轴方向
RM_Y_DIR_E, ///< 位置示教,y轴方向
RM_Z_DIR_E, ///< 位置示教,z轴方向
}rm_pos_teach_type_e;
/**
* @brief 姿态示教方向
*
*/
typedef enum
{
RM_RX_ROTATE_E, ///< 姿态示教,绕x轴旋转
RM_RY_ROTATE_E, ///< 姿态示教,绕y轴旋转
RM_RZ_ROTATE_E, ///< 姿态示教,绕z轴旋转
}rm_ort_teach_type_e;
/**
* @brief 数字IO配置结构体
* io_mode:模式,0-通用输入模式、1-通用输出模式、2-输入开始功能复用模式、3-输入暂停功能复用模式、
* 4-输入继续功能复用模式、5-输入急停功能复用模式、6-输入进入电流环拖动复用模式
* 7-输入进入力只动位置拖动模式(六维力版本可配置)、8-输入进入力只动姿态拖动模式(六维力版本可配置)
* 9-输入进入力位姿结合拖动复用模式(六维力版本可配置)、10-输入外部轴最大软限位复用模式(外部轴模式可配置)
* 11-输入外部轴最小软限位复用模式(外部轴模式可配置)、12-输入初始位姿功能复用模式
* 13-输出碰撞功能复用模式、14-实时调速功能复用模式
* io_state:数字io状态(0低 1高)(该成员在set时无效)
* io_real_time_config_t:实时调速功能,io配置
* speed:速度取值范围0-100 (当io_mode不为14时,默认值为-1)
* mode :模式取值范围1或2 (当io_mode不为14时,默认值为-1)
* 1表示单次触发模式,单次触发模式下当IO拉低速度设置为speed参数值,IO恢复高电平速度设置为初始值
* 2表示连续触发模式,连续触发模式下IO拉低速度设置为speed参数值,IO恢复高电平速度维持当前值
*/
typedef struct
{
int io_mode; // io_mode:模式0~14
struct
{
int speed; // speed:速度取值范围0-100
int mode; // mode :模式取值范围1或2
}io_real_time_config_t;
}rm_io_config_t;
/**
* @brief 数字IO状态获取结构体
* io_state:数字io状态(0低 1高)(该成员在set时无效)
* io_config:io配置结构体
*/
typedef struct
{
int io_state; // io_state:数字io状态(0低 1高)
rm_io_config_t io_config; // io_config:数字io配置结构体
}rm_io_get_t;
/**
* @brief 复合模式拖动示教参数
*
*/
typedef struct{
int free_axes[6]; ///< 自由驱动方向[x,y,z,rx,ry,rz],0-在参考坐标系对应方向轴上不可拖动,1-在参考坐标系对应方向轴上可拖动
int frame; ///< 参考坐标系,0-工作坐标系 1-工具坐标系。
int singular_wall; ///< 仅在六维力模式拖动示教中生效,用于指定是否开启拖动奇异墙,0表示关闭拖动奇异墙,1表示开启拖动奇异墙,若无配置参数,默认启动拖动奇异墙
}rm_multi_drag_teach_t;
/**
* @brief 力位混合控制传感器枚举
*
*/
typedef enum{
RM_FP_OF_SENSOR_E = 0, ///<一维力
RM_FP_SF_SENSOR_E, ///<六维力
}rm_force_position_sensor_e;
/**
* @brief 力位混合控制模式枚举
*
*/
typedef enum{
RM_FP_BASE_COORDINATE_E = 0, ///<基坐标系力控
RM_FP_TOOL_COORDINATE_E, ///<工具坐标系力控
}rm_force_position_mode_e;
/**
* @brief 力位混合控制模式(单方向)力控方向枚举
*
*/
typedef enum{
RM_FP_X_E = 0, ///<沿X轴
RM_FP_Y_E, ///<沿Y轴
RM_FP_Z_E, ///<沿Z轴
RM_FP_RX_E, ///<沿RX姿态方向
RM_FP_RY_E, ///<沿RY姿态方向
RM_FP_RZ_E, ///<沿RZ姿态方向
}rm_force_position_dir_e;
/**
* @brief 力位混合控制参数
*
*/
typedef struct
{
int sensor; ///< 传感器,0-一维力;1-六维力
int mode; ///< 0-基坐标系力控;1-工具坐标系力控;
int control_mode[6]; ///< 6个力控方向(Fx Fy Fz Mx My Mz)的模式 0-固定模式 1-浮动模式 2-弹簧模式 3-运动模 4-力跟踪模式 8-力跟踪+姿态自适应模式
float desired_force[6]; ///< 力控轴维持的期望力/力矩,力控轴的力控模式为力跟踪模式时,期望力/力矩设置才会生效 ,精度0.1N。
float limit_vel[6]; ///< 力控轴的最大线速度和最大角速度限制,只对开启力控方向生效。
}rm_force_position_t;
/**
* @brief 透传力位混合补偿参数
* 建议初始化方式,避免一些未知错误
* rm_force_position_move_t my_fp_move = (rm_force_position_move_t){ 0 };
*/
typedef struct
{
int flag; ///< 0-下发目标角度,1-下发目标位姿
rm_pose_t pose; ///< 当前坐标系下的目标位姿,支持四元数/欧拉角表示姿态。位置精度:0.001mm,欧拉角表示姿态,姿态精度:0.001rad,四元数方式表示姿态,姿态精度:0.000001
float joint[ARM_DOF]; ///< 目标关节角度,单位:°,精度:0.001°
int sensor; ///< 传感器,0-一维力;1-六维力
int mode; ///< 0-基坐标系力控;1-工具坐标系力控;
bool follow; ///< 表示驱动器的运动跟随效果,true 为高跟随,false 为低跟随。
int control_mode[6]; ///< 6个力控方向的模式 0-固定模式 1-浮动模式 2-弹簧模式 3-运动模式 4-力跟踪模式 5-浮动+运动模式 6-弹簧+运动模式 7-力跟踪+运动模式 8-姿态自适应模式
float desired_force[6]; ///< 力控轴维持的期望力/力矩,力控轴的力控模式为力跟踪模式时,期望力/力矩设置才会生效 ,精度0.1N。
float limit_vel[6]; ///< 力控轴的最大线速度和最大角速度限制,只对开启力控方向生效。
int trajectory_mode; ///< 高跟随模式下,0-完全透传模式、1-曲线拟合模式、2-滤波模式
int radio; ///< 曲线拟合模式0-100和滤波模式下的平滑系数(数值越大效果越好),滤波模式下取值范围0~1000,曲线拟合模式下取值范围0~100
}rm_force_position_move_t;
/**
* @brief 角度透传模式结构体
* 建议初始化方式,避免一些未知错误
* rm_movej_canfd_mode_t my_j_canfd = (rm_movej_canfd_mode_t){ 0 };
*/
typedef struct
{
float* joint; // 关节角度(若为六轴机械臂,那么最后一个元素无效),单位°
float expand; // 扩展关节角度(若没有扩展关节,那么此成员值无效)
bool follow; // 跟随模式,0-低跟随,1-高跟随,若使用高跟随,透传周期要求不超过 10ms
int trajectory_mode; // 高跟随模式下,0-完全透传模式、1-曲线拟合模式、2-滤波模式
int radio; // 曲线拟合模式和滤波模式下的平滑系数(数值越大效果越好),滤波模式下取值范围0~1000,曲线拟合模式下取值范围0~100
}rm_movej_canfd_mode_t;
/**
* @brief 姿态透传模式结构体
* 建议初始化方式,避免一些未知错误
* rm_movep_canfd_mode_t my_p_canfd = (rm_movep_canfd_mode_t){ 0 };
*/
typedef struct
{
rm_pose_t pose; // 位姿 (优先采用四元数表达)
bool follow; // 跟随模式,0-低跟随,1-高跟随,若使用高跟随,透传周期要求不超过 10ms
int trajectory_mode; // 高跟随模式下,0-完全透传模式、1-曲线拟合模式、2-滤波模式
int radio; // 曲线拟合模式和滤波模式下的平滑系数(数值越大效果越好),滤波模式下取值范围0~1000,曲线拟合模式下取值范围0~100
}rm_movep_canfd_mode_t;
/**
* @brief 无线网络信息结构体
*
*/
typedef struct{
int channel; ///< 如果是 AP 模式,则存在此字段,标识 wifi 热点的物理信道号
char ip[16]; ///< IP 地址
char mac[18]; ///< MAC 地址
char mask[16]; ///< 子网掩码
char mode[5]; ///< ap 代表热点模式,sta 代表联网模式,off 代表未开启无线模式
char password[16]; ///< 密码
char ssid[32]; ///< 网络名称 (SSID)
}rm_wifi_net_t;
/**
* @brief 机械臂所有状态参数
*
*/
typedef struct
{
float joint_current[ARM_DOF]; ///< 关节电流,单位mA
int joint_en_flag[ARM_DOF]; ///< 关节使能状态
float joint_temperature[ARM_DOF]; ///< 关节温度,单位℃
float joint_voltage[ARM_DOF]; ///< 关节电压,单位V
int joint_err_code[ARM_DOF]; ///< 关节错误码
rm_err_t err; ///< 错误代码
}rm_arm_all_state_t;
/**
* @brief 夹爪状态
*
*/
typedef struct
{
int enable_state; ///< 夹爪使能标志,0 表示未使能,1 表示使能
int status; ///< 夹爪在线状态,0 表示离线, 1表示在线
int error; ///< 夹爪错误信息,低8位表示夹爪内部的错误信息bit5-7 保留bit4 内部通bit3 驱动器bit2 过流 bit1 过温bit0 堵转
int mode; ///< 当前工作状态:1 夹爪张开到最大且空闲,2 夹爪闭合到最小且空闲,3 夹爪停止且空闲,4 夹爪正在闭合,5 夹爪正在张开,6 夹爪闭合过程中遇到力控停止
int current_force; ///< 夹爪当前的压力,单位g
int temperature; ///< 当前温度,单位℃
int actpos; ///< 夹爪开口度
}rm_gripper_state_t;
/**
* @brief 六维力传感器数据结构体
*
*/
typedef struct {
float force_data[6]; ///< 当前力传感器原始数据,力的单位为N;力矩单位为Nm。
float zero_force_data[6]; ///< 当前力传感器系统外受力数据,力的单位为N;力矩单位为Nm。
float work_zero_force_data[6]; ///< 当前工作坐标系下系统外受力原始数据,力的单位为N;力矩单位为Nm。
float tool_zero_force_data[6]; ///< 当前工具坐标系下系统外受力原始数据,力的单位为N;力矩单位为Nm。
} rm_force_data_t;
/**
* @brief 一维力传感器数据结构体
*
*/
typedef struct {
float Fz; ///< 原始数据
float zero_Fz; ///< 传感器坐标系下系统外受力数据,力的单位为N;力矩单位为Nm。
float work_zero_Fz; ///< 当前工作坐标系下系统外受力原始数据,力的单位为N;力矩单位为Nm。
float tool_zero_Fz; ///< 当前工具坐标系下系统外受力原始数据,力的单位为N;力矩单位为Nm。
} rm_fz_data_t;
/**
* @brief 外设数据读写参数结构体
*
*/
typedef struct {
int port; ///< 通讯端口,0-控制器RS485端口,1-末端接口板RS485接口,3-控制器ModbusTCP设备
int address; ///< 数据起始地址
int device; ///< 外设设备地址
int num; ///< 要读的数据的数量
} rm_peripheral_read_write_params_t;
/**
* @brief 升降机构、扩展关节状态结构体
*
*/
typedef struct {
int pos; ///< 扩展关节角度,单位度,精度 0.001°(若为升降机构高度,则单位:mm,精度:1mm,范围:0 ~2300)
int current; ///< 驱动电流,单位:mA,精度:1mA
int err_flag; ///< 驱动错误代码,错误代码类型参考关节错误代码
int mode; ///< 当前状态,0-空闲,1-正方向速度运动,2-正方向位置运动,3-负方向速度运动,4-负方向位置运动
} rm_expand_state_t;
/**
* @brief 文件下发
* @ingroup OnlineProgramming
*/
typedef struct {
char project_path[300]; ///< 下发文件路径文件名
int project_path_len; ///< 名称长度
int plan_speed; ///< 规划速度比例系数
int only_save; ///< 0-保存并运行文件,1-仅保存文件,不运行
int save_id; ///< 保存到控制器中的编号
int step_flag; ///< 设置单步运行方式模式,1-设置单步模式 0-设置正常运动模式
int auto_start; ///< 设置默认在线编程文件,1-设置默认 0-设置非默认
int project_type; ///< 下发文件类型。0-在线编程文件,1-拖动示教轨迹文件
// int err_line; ///< 若运行失败,该参数返回有问题的工程行数,err_line 为 0,则代表校验数据长度不对
} rm_send_project_t;
/**
* @brief 在线编程存储信息
* @ingroup OnlineProgramming
*/
typedef struct {
int id; ///< 在线编程文件id
int size; ///< 文件大小
int speed; ///< 默认运行速度
char trajectory_name[32]; ///< 文件名称
}rm_trajectory_data_t;
/**
* @brief 查询在线编程列表
* @ingroup OnlineProgramming
*/
typedef struct
{
int page_num; // 页码
int page_size; // 每页大小
int list_size; //返回总数量
char vague_search[32]; // 模糊搜索
rm_trajectory_data_t trajectory_list[100]; // 符合的在线编程列表
}rm_program_trajectorys_t;
/**
* @brief 在线编程运行状态
* @ingroup OnlineProgramming
*/
typedef struct
{
int run_state; ///< 运行状态 0 未开始 1运行中 2暂停中
int id; ///< 运行轨迹编号
int edit_id; ///< 上次编辑的在线编程编号 id
int plan_num; ///< 运行行数
int total_loop; ///< 循环指令数量
int step_mode; ///< 单步模式,1 为单步模式,0 为非单步模式
int plan_speed; ///< 全局规划速度比例 1-100
int loop_num[100]; ///< 循环行数
int loop_cont[100]; ///< 对应循环次数
}rm_program_run_state_t;
/**
* @brief 流程图程序运行状态
*/
typedef struct
{
int run_state; ///< 运行状态 0 未开始 1运行中 2暂停中
int id; ///< 当前使能的文件id。
char name[32]; ///< 当前使能的文件名称。
int plan_speed; ///< 当前使能的文件全局规划速度比例 1-100。
int step_mode; ///< 单步模式,0为空,1为正常, 2为单步。
char modal_id[50]; ///< 运行到的流程图块的id。未运行则不返回
}rm_flowchart_run_state_t;
/**
* @brief 全局路点存储信息
* @ingroup OnlineProgramming
*/
typedef struct
{
char point_name[20]; ///< 路点名称
float joint[ARM_DOF]; ///< 关节角度
rm_pose_t pose; ///< 位姿信息
char work_frame[12]; ///< 工作坐标系名称
char tool_frame[12]; ///< 工具坐标系名称
char time[50]; ///< 路点新增或修改时间
}rm_waypoint_t;
/**
* @brief 全局路点列表
* @ingroup OnlineProgramming
*/
typedef struct{
int page_num; ///< 页码
int page_size; ///< 每页大小
int total_size; ///< 列表长度
char vague_search[32]; ///< 模糊搜索
int list_len; ///<返回符合的全局路点列表长度
rm_waypoint_t points_list[100]; ///< 返回符合的全局路点列表
}rm_waypoint_list_t;
/**
* @brief 几何模型长方体参数
* @ingroup Electronic_Fence
*/
typedef struct{
float x_min_limit; ///< 长方体基于世界坐标系 X 方向最小位置,单位 m
float x_max_limit; ///< 长方体基于世界坐标系 X 方向最大位置,单位 m
float y_min_limit; ///< 长方体基于世界坐标系 Y 方向最小位置,单位 m
float y_max_limit; ///< 长方体基于世界坐标系 Y 方向最大位置,单位 m
float z_min_limit; ///< 长方体基于世界坐标系 Z 方向最小位置,单位 m
float z_max_limit; ///< 长方体基于世界坐标系 Z 方向最大位置,单位 m
}rm_fence_config_cube_t;
/**
* @brief 几何模型点面矢量平面参数
* @ingroup Electronic_Fence
*/
typedef struct{
float x1, y1, z1; ///< 点面矢量平面三点法中的第一个点坐标,单位 m
float x2, y2, z2; ///< 点面矢量平面三点法中的第二个点坐标,单位 m
float x3, y3, z3; ///< 点面矢量平面三点法中的第三个点坐标,单位 m
}rm_fence_config_plane_t;
/**
* @brief 几何模型球体参数
* @ingroup Electronic_Fence
*/
typedef struct{
float x; ///< 表示球心在世界坐标系 X 轴的坐标,单位 m
float y; ///< 表示球心在世界坐标系 Y 轴的坐标,单位 m
float z; ///< 表示球心在世界坐标系 Z 轴的坐标,单位 m
float radius; ///< 表示半径,单位 m
}rm_fence_config_sphere_t;
/**
* @brief 几何模型参数
* @ingroup Electronic_Fence
*/
typedef struct{
int form; ///< 形状,1 表示长方体,2 表示点面矢量平面,3 表示球体
char name[12]; ///< 电子围栏名称,不超过 10 个字节,支持字母、数字、下划线
rm_fence_config_cube_t cube; ///< 长方体参数
rm_fence_config_plane_t plan; ///< 点面矢量平面参数
rm_fence_config_sphere_t sphere; ///< 球体参数
}rm_fence_config_t;
/**
* @brief 几何模型名称结构体
* @ingroup Electronic_Fence
*/
typedef struct
{
char name[12]; ///< 几何模型名称,不超过10个字符
}rm_fence_names_t;
/**
* @brief 几何模型参数列表
* @ingroup Electronic_Fence
*/
typedef struct
{
rm_fence_config_t config[10];
}rm_fence_config_list_t;
/**
* @brief 包络球参数
*
*/
typedef struct{
char name[12]; ///< 工具包络球体的名称,1-10 个字节,支持字母数字下划线
float radius; ///< 工具包络球体的半径,单位 m
float x; ///< 工具包络球体球心基于末端法兰坐标系的 X 轴坐标,单位 m
float y; ///< 工具包络球体球心基于末端法兰坐标系的 Y 轴坐标,单位 m
float z; ///< 工具包络球体球心基于末端法兰坐标系的 Z 轴坐标,单位 m
}rm_envelopes_ball_t;
/**
* @brief 包络球参数集合
*
*/
typedef struct{
rm_envelopes_ball_t balls[5];///< 包络参数列表,每个工具最多支持 5 个包络球,可以没有包络
int size; ///< 包络球数量
char tool_name[12];///< 控制器中已存在的工具坐标系名称,如果不存在该字段,则为临时设置当前包络参数
}rm_envelope_balls_list_t;
/**
* @brief 电子围栏/虚拟墙使能状态参数
*
*/
typedef struct
{
bool enable_state; ///< 电子围栏/虚拟墙使能状态,true 代表使能,false 代表禁使能
int in_out_side; ///< 0-机器人在电子围栏/虚拟墙内部,1-机器人在电子围栏外部
int effective_region; ///< 0-电子围栏针对整臂区域生效,1-虚拟墙针对末端生效
}rm_electronic_fence_enable_t;
/**
* @brief (UDP主动上报机械臂信息)力传感器数据结构体
*
*/
typedef struct {
float force[6]; ///< 当前力传感器原始数据,0.001N或0.001Nm
float zero_force[6]; ///< 当前力传感器系统外受力数据,0.001N或0.001Nm
int coordinate; ///< 系统外受力数据的坐标系,0为传感器坐标系 1为当前工作坐标系 2为当前工具坐标系
} rm_force_sensor_t;
/***
* 扩展关节数据
*
*/
typedef struct {
float pos; ///< 当前角度 精度 0.001°,单位:°
int current; ///< 当前驱动电流,单位:mA,精度:1mA
int err_flag; ///< 驱动错误代码,错误代码类型参考关节错误代码
int en_flag; ///< 当前关节使能状态 ,1 为上使能,0 为掉使能
int joint_id; ///< 关节id号
int mode; ///< 当前升降状态,0-空闲,1-正方向速度运动,2-正方向位置运动,3-负方向速度运动,4-负方向位置运动
} rm_udp_expand_state_t;
/***
* 升降机构状态
*
*/
typedef struct {
int height; ///< 当前升降机构高度,单位:mm,精度:1mm
float pos; ///< 当前角度 精度 0.001°,单位:°
int current; ///< 当前驱动电流,单位:mA,精度:1mA
int err_flag; ///< 驱动错误代码,错误代码类型参考关节错误代码
int en_flag; ///< 当前关节使能状态 ,1 为上使能,0 为掉使能
} rm_udp_lift_state_t;
/***
* 灵巧手状态
*
*/
typedef struct {
int hand_pos[6]; ///< 表示灵巧手位置
int hand_angle[6]; ///< 表示灵巧手角度
int hand_force[6]; ///< 表示灵巧手自由度力,单位mN
int hand_state[6]; ///< 表示灵巧手自由度状态,由灵巧手厂商定义状态含义
int hand_err; ///< 表示灵巧手系统错误,由灵巧手厂商定义错误含义,例如因时状态码如下:1表示有错误,0表示无错误
} rm_udp_hand_state_t;
/***
*
* 轨迹连接配置
*/
typedef enum{
RM_TRAJECTORY_DISCONNECT_E = 0, ///<立即规划并执行轨迹,不连接后续轨迹
RM_TRAJECTORY_CONNECT_E ///<将当前轨迹与下一条轨迹一起规划
}rm_trajectory_connect_config_e;
/**
* @brief 机械臂当前状态
*
*/
typedef enum {
RM_IDLE_E, // 使能但空闲状态
RM_MOVE_L_E, // move L运动中状态
RM_MOVE_J_E, // move J运动中状态
RM_MOVE_C_E, // move C运动中状态
RM_MOVE_S_E, // move S运动中状态
RM_MOVE_THROUGH_JOINT_E, // 角度透传状态
RM_MOVE_THROUGH_POSE_E, // 位姿透传状态
RM_MOVE_THROUGH_FORCE_POSE_E, // 力控透传状态
RM_MOVE_THROUGH_CURRENT_E, // 电流环透传状态
RM_STOP_E, // 急停状态
RM_SLOW_STOP_E, // 缓停状态
RM_PAUSE_E, // 暂停状态
RM_CURRENT_DRAG_E, // 电流环拖动状态
RM_SENSOR_DRAG_E, // 六维力拖动状态
RM_TECH_DEMONSTRATION_E // 示教状态
} rm_udp_arm_current_status_e;
/***
* aloha主臂状态
*
*/
typedef struct {
int io1_state; ///< IO1状态(手柄光电检测),0为按键未触发,1为按键触发。
int io2_state; ///< IO2状态(手柄光电检测),0为按键未触发,1为按键触发。
} rm_udp_aloha_state_t;
/**
* 末端设备基础信息(末端生态协议支持)
*/
typedef struct{
char manu[10]; // 设备厂家
int type; // 设备类型 1:两指夹爪 2:五指灵巧手 3:三指夹爪
char hv[10]; // 硬件版本
char sv[10]; // 软件版本
char bv[10]; // boot版本
int id; // 设备ID
int dof; // 自由度
int check; // 自检开关
int bee; // 蜂鸣器开关
bool force; // 力控支持
bool touch; // 触觉支持
int touch_num; // 触觉个数
int touch_sw; // 触觉开关
int hand; // 手方向 1 :左手 2: 右手
int pos_up[12]; // 位置上限,单位:无量纲
int pos_low[12]; // 位置下限,单位:无量纲
int angle_up[12]; // 角度上限,单位:0.01度
int angle_low[12]; // 角度下限,单位:0.01度
int speed_up[12]; // 速度上限,单位:无量纲
int speed_low[12]; // 速度下限,单位:无量纲
int force_up[12]; // 力上限,单位:0.001N
int force_low[12]; // 力下限,单位:0.001N
} rm_plus_base_info_t;
// 单位:无量纲
/**
* 末端设备实时信息(末端生态协议支持)
*/
typedef struct{
int sys_state; // 系统状态:0正常1设备故障
int dof_state[12]; // 各自由度当前状态:0正在松开1正在闭合2位置到位停止3力控到位停止4触觉到位停止5电流保护停止6发生故障
int dof_err[12]; // 各自由度错误信息
int pos[12]; // 各自由度当前位置,单位:无量纲
int speed[12]; //各自由度当前速度,闭合正,松开负,单位:无量纲
int angle[12]; // 各自由度当前角度,单位:0.01度
int current[12]; // 各自由度当前电流,单位:mA
int normal_force[18]; // 自由度触觉三维力的法向力,1-6自由度触觉三维力的法向力*3
int tangential_force[18]; // 自由度触觉三维力的切向力
int tangential_force_dir[18]; // 自由度触觉三维力的切向力方向
uint32_t tsa[12]; // 自由度触觉自接近
uint32_t tma[12]; // 自由度触觉互接近
int touch_data[18]; // 触觉传感器原始数据(示例中有,但未显示数据的JSON情况)
int force[12]; //自由度力矩,闭合正,松开负,单位0.001N
} rm_plus_state_info_t;
/**
* @brief udp主动上报机械臂信息
*
*/
typedef struct
{
int errCode; ///< 数据解析错误码,-3为数据解析错误,代表推送的数据不完整或格式不正确
char arm_ip[16]; ///< 推送数据的机械臂的IP地址
rm_joint_status_t joint_status; ///< 关节状态
rm_force_sensor_t force_sensor; ///< 力数据(六维力或一维力版本支持)
rm_err_t err; ///< 错误码
rm_pose_t waypoint; ///< 当前路点信息
rm_udp_lift_state_t liftState; ///< 升降关节数据
rm_udp_expand_state_t expandState; ///< 扩展关节数据
rm_udp_hand_state_t handState; ///< 灵巧手数据
rm_udp_arm_current_status_e arm_current_status; ///< 机械臂状态
rm_udp_aloha_state_t aloha_state; ///< aloha主臂状态
int rm_plus_state; ///< 末端设备状态,0-设备在线,1-表示协议未开启,2-表示协议开启但是设备不在线
rm_plus_base_info_t plus_base_info; ///< 末端设备基础信息
rm_plus_state_info_t plus_state_info; ///< 末端设备实时信息
}rm_realtime_arm_joint_state_t;
/**
* @brief 逆解参数
* @ingroup Algo
*/
typedef struct {
float q_in[ARM_DOF]; ///< 上一时刻关节角度,单位°
rm_pose_t q_pose; ///< 目标位姿
uint8_t flag; ///< 姿态参数类别:0-四元数;1-欧拉角
} rm_inverse_kinematics_params_t;
typedef struct {
int result; // 0:成功,1:逆解失败,-1:上一时刻关节角度输入为空或超关节限位,-2:目标位姿四元数不合法, -3:当前机器人非六自由度,当前仅支持六自由度机器人
int num; // number of solutions
float q_ref[8]; // 参考关节角度,通常是当前关节角度, 单位 °
float q_solve[8][8]; // 关节角全解, 单位 °
} rm_inverse_kinematics_all_solve_t;
/**
* @brief 包络球描述数据结构
*/
typedef struct
{
float radius; // 球体半径(单位:m)
float centrePoint[3]; // 球体中心位置(单位:m,以法兰坐标系为参考坐标系)
} rm_tool_sphere_t; // 工具包络球参数
/**
* @brief 旋转矩阵
* @ingroup Algo
*/
typedef struct
{
short irow;
short iline;
float data[4][4];
} rm_matrix_t;
/**
* @brief 机械臂事件回调函数
* @ingroup Init_Class
*/
typedef void (*rm_event_callback_ptr)(rm_event_push_data_t data);
/**
* @brief UDP机械臂状态主动上报回调函数
* @ingroup Init_Class
*/
typedef void (*rm_realtime_arm_state_callback_ptr)(rm_realtime_arm_joint_state_t data);
/**
* @brief 机械臂基本信息
* @ingroup Init_Class
*/
typedef struct
{
uint8_t arm_dof; ///< 机械臂自由度
rm_robot_arm_model_e arm_model; ///< 机械臂型号
rm_force_type_e force_type; ///< 末端力传感器版本
uint8_t robot_controller_version; ///< 机械臂控制器版本,4:四代控制器,3:三代控制器。
}rm_robot_info_t;
/**
* @brief 机械臂控制句柄
* @ingroup Init_Class
*/
typedef struct {
int id; ///< 句柄id,连接成功id大于0,连接失败返回-1
}rm_robot_handle;
typedef struct
{
float d[8]; //* unit: m
float a[8]; //* unit: m
float alpha[8]; //* unit: °
float offset[8]; //* unit: °
} rm_dh_t;
/**
* @brief 版本号结构体
* 不超过10个字符
* @ingroup ToolCoordinateConfig
* @ingroup WorkCoordinateConfig
*/
typedef struct {
char version[10];
} rm_version_t;
/**
* @brief 轨迹信息结构体
*/
typedef struct {
int point_num; ///< 轨迹点数量
char name[20]; ///< 轨迹名称
char create_time[20]; ///< 创建时间
}rm_trajectory_info_t;
/**
* @brief 轨迹列表结构体
* @ingroup OnlineProgramming
*/
typedef struct{
int page_num; ///< 页码
int page_size; ///< 每页大小
int total_size; ///< 列表长度
char vague_search[32]; ///< 模糊搜索
int list_len; ///<返回符合的轨迹列表长度
rm_trajectory_info_t tra_list[100]; ///< 返回符合的轨迹列表
}rm_trajectory_list_t;
/**
* @brief Modbus TCP主站信息结构体
*/
typedef struct {
char master_name[20]; // Modbus 主站名称,最大长度15个字符,不超过15个字符
char ip[16]; // TCP主站 IP 地址
int port; // TCP主站端口号
}rm_modbus_tcp_master_info_t;
/**
* @brief Modbus TCP主站列表结构体
*/
typedef struct{
int page_num; ///< 页码
int page_size; ///< 每页大小
int total_size; ///< 列表长度
char vague_search[32]; ///< 模糊搜索
int list_len; ///<返回符合的TCP主站列表长度
rm_modbus_tcp_master_info_t master_list[100]; ///< 返回符合的TCP主站列表
}rm_modbus_tcp_master_list_t;
/**
* @brief Modbus RTU读数据参数结构体
*/
typedef struct {
int address; ///< 数据起始地址
int device; ///< 外设设备地址
int type; ///< 0-控制器端modbus主机;1-工具端modbus主机。
int num; ///< 要读的数据的数量,数据长度不超过109
}rm_modbus_rtu_read_params_t;
/**
* @brief Modbus RTU写数据结构体
*/
typedef struct {
int address; ///< 数据起始地址
int device; ///< 外设设备地址
int type; ///< 0-控制器端modbus主机;1-工具端modbus主机。
int num; ///< 要写的数据的数量,最大不超过100
int data[120]; ///< 要写的数据,数据长度不超过100
}rm_modbus_rtu_write_params_t;
/**
* @brief Modbus TCP读数据参数结构体
*/
typedef struct {
int address; // 数据起始地址
char master_name[20]; // Modbus 主站名称,最大长度15个字符,不超过15个字符(master_name与IP二选一,若有IP和port优先使用IP和port)
char ip[16]; // 主机连接的 IP 地址(master_name与IP二选一,若有IP和port优先使用IP和port)
int port; // 主机连接的端口号
int num; // 读取数据数量,最大不超过100
}rm_modbus_tcp_read_params_t;
/**
* @brief Modbus TCP写数据结构体
*/
typedef struct {
int address; // 数据起始地址
char master_name[20]; // Modbus 主站名称,最大长度15个字符,不超过15个字符(master_name与IP二选一,若有IP和port优先使用IP和port)
char ip[16]; // 主机连接的 IP 地址(master_name与IP二选一,若有IP和port优先使用IP和port)
int port; // 主机连接的端口号
int num; // 写入数据数量,最大不超过100
int data[120]; // 写入的数据,数据长度不超过100
}rm_modbus_tcp_write_params_t;
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
#ifndef RM_INTERFACE_GLOBAL_H
#define RM_INTERFACE_GLOBAL_H
#ifdef __linux
#define RM_INTERFACE_EXPORT
#endif
#if _WIN32
#if defined(RM_INTERFACE_LIBRARY)
# define RM_INTERFACE_EXPORT __declspec(dllexport)
#else
# define RM_INTERFACE_EXPORT __declspec(dllexport)
#endif
#endif
#endif // RM_INTERFACE_GLOBAL_H
This source diff could not be displayed because it is too large. You can view the blob instead.
#ifndef RM_VERSION_H
#define RM_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif
#define SDK_VERSION ("1.1.0")
#ifdef __cplusplus
}
#endif
#endif
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment