Compare commits
66
Commits
1a54aed0ee
...
v1.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1fd0d4b2f | ||
|
|
1c3e48d59f | ||
|
|
bac53a3e45 | ||
|
|
fa1f547e81 | ||
|
|
12e837c941 | ||
|
|
675d01f444 | ||
|
|
ccde2f73e9 | ||
|
|
3b44bd97f7 | ||
|
|
c5fea61784 | ||
|
|
07c4aa316a | ||
|
|
5d1ef621db | ||
|
|
8fe1b36cdc | ||
|
|
b717c5f163 | ||
|
|
5ddc63abdf | ||
|
|
4e61ef5655 | ||
|
|
361158c343 | ||
|
|
5fd55496bf | ||
|
|
f0d0c4fb1e | ||
|
|
26862bf05f | ||
|
|
b90c98d3ad | ||
|
|
04770e5df2 | ||
|
|
5a92e2ccfa | ||
|
|
b98236466c | ||
|
|
badb4ebf61 | ||
|
|
5aba22d8e9 | ||
|
|
052df2fc21 | ||
|
|
8c670003b8 | ||
|
|
dee130197c | ||
|
|
d0500151ab | ||
|
|
9258ced2d0 | ||
|
|
7ba20659b2 | ||
|
|
b3578b0b53 | ||
|
|
6144b93e10 | ||
|
|
e8ee92110b | ||
|
|
714281dbf1 | ||
|
|
9bce4b12cf | ||
|
|
e3c40c822b | ||
|
|
f6684bebc9 | ||
|
|
924c33fedf | ||
|
|
89c4e770d5 | ||
|
|
1027d47e04 | ||
|
|
323b6bd464 | ||
|
|
f5cb361ffe | ||
|
|
29c49057b4 | ||
|
|
03039bd493 | ||
|
|
0d06f797f8 | ||
|
|
0e0047b946 | ||
|
|
0779e9171f | ||
|
|
18bc4eb08f | ||
|
|
a9f0f995de | ||
|
|
62fd8c0685 | ||
|
|
f280a4d383 | ||
|
|
07a6397764 | ||
|
|
b5d4963ca8 | ||
|
|
e00bda534b | ||
|
|
4e43d7e3a4 | ||
|
|
8dbda93e3f | ||
|
|
9b5b479560 | ||
|
|
2a4a9510b8 | ||
|
|
cfee4cb939 | ||
|
|
48bd749251 | ||
|
|
09809b0eb1 | ||
|
|
51e081118a | ||
|
|
7f537108b5 | ||
|
|
c3af3ae4e2 | ||
|
|
2e8e05494b |
@@ -0,0 +1,34 @@
|
|||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
host:
|
||||||
|
runs-on: ubuntu-builder
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Host build + tests
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build-host \
|
||||||
|
-DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON
|
||||||
|
cmake --build build-host
|
||||||
|
ctest --test-dir build-host --output-on-failure
|
||||||
|
|
||||||
|
cortex-m:
|
||||||
|
runs-on: ubuntu-builder
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install ARM GCC
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gcc-arm-none-eabi
|
||||||
|
|
||||||
|
- name: Cortex-M compile matrix (DR_COMPILE_CHECK)
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build-matrix -DDR_COMPILE_CHECK=ON
|
||||||
|
cmake --build build-matrix --parallel $(nproc)
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
name: Release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-builder
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
# ── 自动标签:从合并进来的 PR body 提取 v*.*.* ──
|
||||||
|
- name: Auto-tag from merged PR
|
||||||
|
id: autotag
|
||||||
|
run: |
|
||||||
|
# 已有标签 → 跳过
|
||||||
|
EXISTING=$(git tag --points-at HEAD | grep '^v' | head -n1)
|
||||||
|
if [ -n "$EXISTING" ]; then
|
||||||
|
echo "Tag $EXISTING already exists"
|
||||||
|
echo "tag=$EXISTING" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 非 merge commit → 跳过
|
||||||
|
PARENTS=$(git log --format="%P" -1 | wc -w)
|
||||||
|
if [ "$PARENTS" -lt 2 ]; then
|
||||||
|
echo "Not a merge commit, skip auto-tag"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 从 merge commit message 提取 PR 号
|
||||||
|
COMMIT_MSG=$(git log --format="%B" -1)
|
||||||
|
PR_NUM=$(echo "$COMMIT_MSG" | grep -oP '#\K\d+' | head -1) || true
|
||||||
|
if [ -z "$PR_NUM" ]; then
|
||||||
|
echo "No PR number found in merge message"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "Merge commit for PR #$PR_NUM"
|
||||||
|
|
||||||
|
# 通过 Gitea API 获取 PR body,提取版本号
|
||||||
|
API="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/pulls/${PR_NUM}"
|
||||||
|
TOKEN="${{ gitea.token }}"
|
||||||
|
PR_BODY=$(curl -s -H "Authorization: token ${TOKEN}" "${API}" | \
|
||||||
|
python3 -c "import sys,json,re;pr=json.load(sys.stdin);body=pr.get('body','') or '';m=re.search(r'v\d+\.\d+\.\d+',body);print(m.group() if m else '')")
|
||||||
|
|
||||||
|
if [ -z "$PR_BODY" ]; then
|
||||||
|
echo "No version pattern v*.*.* found in PR body"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION="$PR_BODY"
|
||||||
|
echo "Found version: $VERSION"
|
||||||
|
|
||||||
|
# 创建本地标签(不推送远端)
|
||||||
|
# Gitea Create Release API 会自动在远端创建标签
|
||||||
|
git config user.email "ci@datarouter"
|
||||||
|
git config user.name "DataRouter CI"
|
||||||
|
git tag -a "$VERSION" -m "Release $VERSION" 2>/dev/null || true
|
||||||
|
echo "Created local tag: $VERSION"
|
||||||
|
echo "tag=$VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# ── 读取标签(已有标签 / auto-tag 创建的标签)──
|
||||||
|
- name: Read tag from HEAD
|
||||||
|
id: tag
|
||||||
|
run: |
|
||||||
|
TAG=$(git tag --points-at HEAD | grep '^v' | head -n1)
|
||||||
|
[ -n "$TAG" ] || { echo "No version tag on HEAD"; exit 78; }
|
||||||
|
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Install cross-compilers
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
gcc-arm-linux-gnueabihf \
|
||||||
|
gcc-aarch64-linux-gnu \
|
||||||
|
gcc-mingw-w64-x86-64 \
|
||||||
|
gcc-arm-none-eabi
|
||||||
|
|
||||||
|
- name: Build all targets
|
||||||
|
run: |
|
||||||
|
for entry in \
|
||||||
|
"linux-amd64|ON|" \
|
||||||
|
"linux-arm64|OFF|-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-linux-arm64.cmake" \
|
||||||
|
"linux-armhf|OFF|-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-linux-armhf.cmake" \
|
||||||
|
"windows-amd64|OFF|-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-windows-amd64.cmake -DBUILD_EXAMPLES=OFF" \
|
||||||
|
"baremetal-arm32|OFF|-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-baremetal-arm32.cmake -DBUILD_EXAMPLES=OFF"
|
||||||
|
do
|
||||||
|
IFS='|' read -r name testing extra <<< "$entry"
|
||||||
|
echo ">>> Building $name"
|
||||||
|
cmake -S . -B "build-$name" -DBUILD_TESTING=$testing $extra
|
||||||
|
cmake --build "build-$name"
|
||||||
|
[ "$testing" = "ON" ] && ctest --test-dir "build-$name" --output-on-failure
|
||||||
|
|
||||||
|
pkg="datarouter-$name"
|
||||||
|
cmake --install "build-$name" --prefix "dist/$pkg"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Cortex-M build & package
|
||||||
|
run: |
|
||||||
|
for name in cm3 cm4-soft cm4-hard cm7-soft cm7-hard; do
|
||||||
|
case $name in
|
||||||
|
cm3) flags="-mcpu=cortex-m3 -mthumb -mfloat-abi=soft" ;;
|
||||||
|
cm4-soft) flags="-mcpu=cortex-m4 -mthumb -mfloat-abi=soft" ;;
|
||||||
|
cm4-hard) flags="-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard" ;;
|
||||||
|
cm7-soft) flags="-mcpu=cortex-m7 -mthumb -mfloat-abi=soft" ;;
|
||||||
|
cm7-hard) flags="-mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard" ;;
|
||||||
|
esac
|
||||||
|
echo ">>> Building $name"
|
||||||
|
cmake -S . -B "build-$name" \
|
||||||
|
-DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF \
|
||||||
|
-DCMAKE_C_COMPILER=arm-none-eabi-gcc \
|
||||||
|
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
|
||||||
|
-DCMAKE_C_FLAGS="$flags"
|
||||||
|
cmake --build "build-$name"
|
||||||
|
cmake --install "build-$name" --prefix "dist/datarouter-$name"
|
||||||
|
done
|
||||||
|
echo "--- Cortex-M package build: all variants passed ---"
|
||||||
|
|
||||||
|
- name: Create release & upload assets
|
||||||
|
run: |
|
||||||
|
TAG="${{ steps.tag.outputs.tag }}"
|
||||||
|
API="${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases"
|
||||||
|
TOKEN="${{ gitea.token }}"
|
||||||
|
|
||||||
|
# Check if release already exists
|
||||||
|
echo "=== Checking existing releases for $TAG ==="
|
||||||
|
EXISTING=$(curl -s -H "Authorization: token ${TOKEN}" "${API}" | \
|
||||||
|
python3 -c "import sys,json;rels=json.load(sys.stdin);print(next((r['id'] for r in rels if r['tag_name']=='${TAG}'),''))")
|
||||||
|
|
||||||
|
if [ -n "$EXISTING" ]; then
|
||||||
|
ID="$EXISTING"
|
||||||
|
echo "Release already exists (ID=$ID), updating it"
|
||||||
|
else
|
||||||
|
echo "=== Creating release $TAG ==="
|
||||||
|
RESP=$(curl -s -X POST \
|
||||||
|
-H "Authorization: token ${TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"tag_name\":\"${TAG}\",\"name\":\"DataRouter ${TAG}\"}" \
|
||||||
|
"$API")
|
||||||
|
ID=$(echo "$RESP" | python3 -c "import sys,json;d=json.loads(sys.stdin.read());print(d['id'])")
|
||||||
|
fi
|
||||||
|
|
||||||
|
for dir in dist/*/; do
|
||||||
|
name="$(basename "$dir").tar.gz"
|
||||||
|
tar czf "/tmp/$name" -C "$dir" .
|
||||||
|
echo "Uploading $name"
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token ${TOKEN}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"/tmp/$name" \
|
||||||
|
"${API}/${ID}/assets?name=${name}"
|
||||||
|
done
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CidrCTestProjectState">
|
||||||
|
<ctestState>
|
||||||
|
<lineNumber testId="path:null test:datarouter" value="28" />
|
||||||
|
</ctestState>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+247
@@ -1,6 +1,253 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="BackendCodeEditorSettings">
|
<component name="BackendCodeEditorSettings">
|
||||||
|
<option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Component_0020Designer_0020generated_0020code/@EntryIndexedValue" value="Component Designer generated code" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Designer_0020generated_0020code/@EntryIndexedValue" value="Designer generated code" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Web_0020Form_0020Designer_0020generated_0020code/@EntryIndexedValue" value="Web Form Designer generated code" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=Windows_0020Form_0020Designer_0020generated_0020code/@EntryIndexedValue" value="Windows Form Designer generated code" type="string" />
|
||||||
|
<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="DO_NOT_SHOW" 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/=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/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" 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/=CppModulePartitionWithSeveralPartitionUnits/@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" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+1
@@ -4,4 +4,5 @@
|
|||||||
<option name="pythonIntegrationState" value="YES" />
|
<option name="pythonIntegrationState" value="YES" />
|
||||||
</component>
|
</component>
|
||||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
<component name="WestSettings"><![CDATA[{}]]></component>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### ⚠ Breaking Changes
|
||||||
|
|
||||||
|
- **API 前缀重命名**:所有 `datarouter_*` / `DATAROUTER_*` 改为 `dr_*` / `DR_*`
|
||||||
|
- `datarouter_init()` → `dr_init()`
|
||||||
|
- `datarouter_port_create()` → `dr_port_create()`
|
||||||
|
- `datarouter_send_<id>()` → `dr_send_<id>()`
|
||||||
|
- `datarouter_on_recv_<id>()` → `dr_on_recv_<id>()`
|
||||||
|
- `DATAROUTER_SEND_sensor` → `DR_SEND_sensor`
|
||||||
|
- `datarouter_port_t` → `dr_port_t`
|
||||||
|
- 配置宏 `DATAROUTER_SEND(...)` / `DATAROUTER_RECV(...)` → `DR_SEND(...)` / `DR_RECV(...)`
|
||||||
|
- **发送函数不再接收 port_id**:`dr_send_<id>(data, len)` 自动广播到所有 send_type 匹配的端口
|
||||||
|
- **端口移除 `recv_type`**:端口只保留 `send_type` + handler 列表,接收侧由用户自行调用 `dr_on_recv_<id>()`
|
||||||
|
|
||||||
|
### 🚀 新功能
|
||||||
|
|
||||||
|
- **自动广播路由**:调用 `dr_send_<id>(data, len)` 时遍历所有端口,自动匹配 `send_type`,逐一调用 handler
|
||||||
|
- **外部配置覆盖**:`datarouter.h` 通过 `__has_include(<datarouter_config.h>)` 优先加载用户配置,找不到时回退到库默认配置
|
||||||
|
- **配置模板**:新增 `datarouter_config_template.h` 供用户快速自定义
|
||||||
|
- **CMake Presets**:新增 `CMakePresets.json`,覆盖 7 种构建配置
|
||||||
|
- **Cortex-M 编译矩阵**:`DR_COMPILE_CHECK=ON` 自动检测 `arm-none-eabi-gcc`,验证 CM3 / CM4(soft/hard) / CM7(soft/hard-sp/hard-dp) 6 个变体的编译兼容性
|
||||||
|
- **嵌入式源文件直用模式**:`DR_SOURCE_ONLY=ON` 只暴露源码路径,用户将 `datarouter.c` 加入自身 target 以继承全部编译标志,消除 VFP/Thumb ABI 不匹配
|
||||||
|
- **Gitea CI 工作流**:新增 `.gitea/workflows/ci.yml`,PR/推送时执行 host 测试 + Cortex-M 编译矩阵
|
||||||
|
- **Release 工作流更新**:`.gitea/workflows/release.yml` 新增 Cortex-M compile matrix 步骤
|
||||||
|
|
||||||
|
### ✨ 增强
|
||||||
|
|
||||||
|
- 支持一个端口注册多个 handler(默认上限 4),发送时逐一调用
|
||||||
|
- 运行时通过 `dr_port_remove_handler()` / `dr_port_clear_handlers()` 动态改变路由
|
||||||
|
- 发送能力和接收能力分开声明,按需组合
|
||||||
|
|
||||||
|
### 📚 文档
|
||||||
|
|
||||||
|
- 新增 `DESIGN.md`(含 8 幅 PlantUML 架构图)
|
||||||
|
- 新增 `TEST_CASES.md`(22 个测试用例文档)
|
||||||
|
- 新增 `CHANGELOG.md`
|
||||||
|
- `README.md` 全面更新,覆盖嵌入式构建、Preset 用法、API 参考
|
||||||
|
- 所有源文件添加中文 Doxygen 注释
|
||||||
|
|
||||||
|
### 🧪 测试
|
||||||
|
|
||||||
|
- 22 个单元测试,覆盖端口管理、send_type/handler 设置、自动广播路由、类型过滤、移除/删除后路由、接收回调、能力元数据
|
||||||
|
|
||||||
|
### 🐛 修复
|
||||||
|
|
||||||
|
- 修复 ARM 交叉编译时 VFP 参数不匹配问题(通过 `DR_SOURCE_ONLY` 模式)
|
||||||
|
- 修复 `#undef` 宏名称残留旧前缀
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.0.0] - 2024-01-01
|
||||||
|
|
||||||
|
### 🚀 新功能
|
||||||
|
|
||||||
|
- 初始版本发布
|
||||||
|
- X-macro 代码生成:编译期声明通道,自动生成枚举、发送函数、回调声明
|
||||||
|
- 动态端口管理:创建、删除、运行时切换能力
|
||||||
|
- 弱符号回调默认实现
|
||||||
|
- Gitea Release 工作流:自动化构建 linux-amd64 / linux-arm64 / linux-armhf / windows-amd64 / baremetal-arm32
|
||||||
+121
-3
@@ -1,6 +1,124 @@
|
|||||||
cmake_minimum_required(VERSION 4.3)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(DataRouter C)
|
project(DataRouter VERSION 1.1.0 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
add_library(DataRouter STATIC library.c)
|
# ── 选项 ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
option(DR_SOURCE_ONLY "Provide source/include vars instead of building lib" OFF)
|
||||||
|
option(DR_COMPILE_CHECK "Build compile-compatibility tests for each Cortex-M variant" OFF)
|
||||||
|
|
||||||
|
# 源码路径变量:嵌入式项目直接 target_sources() 使用
|
||||||
|
set(DR_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/datarouter.c CACHE INTERNAL "")
|
||||||
|
set(DR_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
|
||||||
|
|
||||||
|
# 预编译包使用者可用 find_package(DataRouter CONFIG) 从此路径加载
|
||||||
|
set(DataRouter_CMAKE_CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/cmake CACHE INTERNAL "")
|
||||||
|
|
||||||
|
# ── 编译兼容性矩阵 (仅在 host 编译器和 ARM GCC 均可用时生效) ──
|
||||||
|
|
||||||
|
if(DR_COMPILE_CHECK)
|
||||||
|
find_program(ARM_GCC arm-none-eabi-gcc)
|
||||||
|
if(ARM_GCC)
|
||||||
|
message(STATUS "ARM GCC found: ${ARM_GCC}")
|
||||||
|
set(VARIANTS cm3 cm4-soft cm4-hard cm7-soft cm7-hard)
|
||||||
|
set(FLAG_LIST
|
||||||
|
"-mcpu=cortex-m3 -mthumb -mfloat-abi=soft"
|
||||||
|
"-mcpu=cortex-m4 -mthumb -mfloat-abi=soft"
|
||||||
|
"-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard"
|
||||||
|
"-mcpu=cortex-m7 -mthumb -mfloat-abi=soft"
|
||||||
|
"-mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard"
|
||||||
|
)
|
||||||
|
list(LENGTH VARIANTS VN)
|
||||||
|
math(EXPR VN "${VN} - 1")
|
||||||
|
foreach(I RANGE ${VN})
|
||||||
|
list(GET VARIANTS ${I} V)
|
||||||
|
list(GET FLAG_LIST ${I} F)
|
||||||
|
set(TGT "check_${V}")
|
||||||
|
add_custom_target(${TGT}
|
||||||
|
COMMAND ${ARM_GCC} ${F}
|
||||||
|
-c ${CMAKE_CURRENT_SOURCE_DIR}/datarouter.c
|
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
-o ${CMAKE_CURRENT_BINARY_DIR}/${TGT}.o
|
||||||
|
COMMENT "Compile check: ${V} (${F})"
|
||||||
|
)
|
||||||
|
message(STATUS " compile check: ${V} (make ${TGT})")
|
||||||
|
endforeach()
|
||||||
|
else()
|
||||||
|
message(WARNING "arm-none-eabi-gcc not found; skipping ARM compile checks")
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── 源码直用模式(嵌入式项目) ──────────────────────────────
|
||||||
|
|
||||||
|
if(DR_SOURCE_ONLY)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── 常规库构建 ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
add_library(DataRouter STATIC datarouter.c)
|
||||||
|
target_include_directories(DataRouter PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
|
)
|
||||||
|
|
||||||
|
if(BUILD_EXAMPLES OR NOT DEFINED BUILD_EXAMPLES)
|
||||||
|
add_executable(example example.c)
|
||||||
|
target_link_libraries(example DataRouter)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_TESTING OR NOT DEFINED BUILD_TESTING)
|
||||||
|
enable_testing()
|
||||||
|
add_executable(test_datarouter tests/test_datarouter.c)
|
||||||
|
target_link_libraries(test_datarouter DataRouter)
|
||||||
|
add_test(NAME datarouter COMMAND test_datarouter)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── 安装规则(用于打包发布) ─────────────────────────────
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
set(DataRouter_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/DataRouter")
|
||||||
|
|
||||||
|
install(TARGETS DataRouter
|
||||||
|
EXPORT DataRouterTargets
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/datarouter.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/datarouter_config.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/datarouter_config_template.h
|
||||||
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# ── CMake 包配置文件(find_package(DataRouter) 用) ────
|
||||||
|
|
||||||
|
set(PACKAGE_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
set(PACKAGE_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/cmake/DataRouterConfig.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/DataRouterConfig.cmake
|
||||||
|
INSTALL_DESTINATION ${DataRouter_INSTALL_CMAKEDIR}
|
||||||
|
PATH_VARS PACKAGE_INCLUDE_INSTALL_DIR PACKAGE_LIB_INSTALL_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/DataRouterConfigVersion.cmake
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
install(EXPORT DataRouterTargets
|
||||||
|
FILE DataRouterTargets.cmake
|
||||||
|
DESTINATION ${DataRouter_INSTALL_CMAKEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/DataRouterConfig.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/DataRouterConfigVersion.cmake
|
||||||
|
DESTINATION ${DataRouter_INSTALL_CMAKEDIR}
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"displayName": "Host (native) build",
|
||||||
|
"description": "Build with host compiler for development, testing, and examples",
|
||||||
|
"binaryDir": "${sourceDir}/build/default",
|
||||||
|
"cacheVariables": {
|
||||||
|
"BUILD_TESTING": "ON",
|
||||||
|
"BUILD_EXAMPLES": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cm3",
|
||||||
|
"displayName": "Cortex-M3 (soft-float)",
|
||||||
|
"description": "ARM Cortex-M3, no FPU, software float ABI. Requires arm-none-eabi-gcc in PATH.",
|
||||||
|
"binaryDir": "${sourceDir}/build/cm3",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_FLAGS": "-mcpu=cortex-m3 -mthumb -mfloat-abi=soft -Wall -Werror",
|
||||||
|
"DR_SOURCE_ONLY": "ON",
|
||||||
|
"BUILD_TESTING": "OFF",
|
||||||
|
"BUILD_EXAMPLES": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cm4-soft",
|
||||||
|
"displayName": "Cortex-M4 (soft-float)",
|
||||||
|
"description": "ARM Cortex-M4, FPU present but soft-float ABI. Requires arm-none-eabi-gcc.",
|
||||||
|
"binaryDir": "${sourceDir}/build/cm4-soft",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_FLAGS": "-mcpu=cortex-m4 -mthumb -mfloat-abi=soft -Wall -Werror",
|
||||||
|
"DR_SOURCE_ONLY": "ON",
|
||||||
|
"BUILD_TESTING": "OFF",
|
||||||
|
"BUILD_EXAMPLES": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cm4-hard",
|
||||||
|
"displayName": "Cortex-M4F (hard-float, FPv4-SP-D16)",
|
||||||
|
"description": "ARM Cortex-M4 with single-precision FPU, hard-float ABI. Requires arm-none-eabi-gcc.",
|
||||||
|
"binaryDir": "${sourceDir}/build/cm4-hard",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_FLAGS": "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -Wall -Werror",
|
||||||
|
"DR_SOURCE_ONLY": "ON",
|
||||||
|
"BUILD_TESTING": "OFF",
|
||||||
|
"BUILD_EXAMPLES": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cm7-soft",
|
||||||
|
"displayName": "Cortex-M7 (soft-float)",
|
||||||
|
"description": "ARM Cortex-M7, FPU present but soft-float ABI. Requires arm-none-eabi-gcc.",
|
||||||
|
"binaryDir": "${sourceDir}/build/cm7-soft",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_FLAGS": "-mcpu=cortex-m7 -mthumb -mfloat-abi=soft -Wall -Werror",
|
||||||
|
"DR_SOURCE_ONLY": "ON",
|
||||||
|
"BUILD_TESTING": "OFF",
|
||||||
|
"BUILD_EXAMPLES": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cm7-hard-sp",
|
||||||
|
"displayName": "Cortex-M7F (hard-float, FPv5-SP-D16, single)",
|
||||||
|
"description": "ARM Cortex-M7 with single-precision FPU, hard-float ABI. Requires arm-none-eabi-gcc.",
|
||||||
|
"binaryDir": "${sourceDir}/build/cm7-hard-sp",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_FLAGS": "-mcpu=cortex-m7 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard -Wall -Werror",
|
||||||
|
"DR_SOURCE_ONLY": "ON",
|
||||||
|
"BUILD_TESTING": "OFF",
|
||||||
|
"BUILD_EXAMPLES": "OFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cm7-hard-dp",
|
||||||
|
"displayName": "Cortex-M7F (hard-float, FPv5-D16, double)",
|
||||||
|
"description": "ARM Cortex-M7 with double-precision FPU, hard-float ABI. Requires arm-none-eabi-gcc.",
|
||||||
|
"binaryDir": "${sourceDir}/build/cm7-hard-dp",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_FLAGS": "-mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard -Wall -Werror",
|
||||||
|
"DR_SOURCE_ONLY": "ON",
|
||||||
|
"BUILD_TESTING": "OFF",
|
||||||
|
"BUILD_EXAMPLES": "OFF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buildPresets": [
|
||||||
|
{ "name": "default", "configurePreset": "default" },
|
||||||
|
{ "name": "cm3", "configurePreset": "cm3" },
|
||||||
|
{ "name": "cm4-soft", "configurePreset": "cm4-soft" },
|
||||||
|
{ "name": "cm4-hard", "configurePreset": "cm4-hard" },
|
||||||
|
{ "name": "cm7-soft", "configurePreset": "cm7-soft" },
|
||||||
|
{ "name": "cm7-hard-sp", "configurePreset": "cm7-hard-sp" },
|
||||||
|
{ "name": "cm7-hard-dp", "configurePreset": "cm7-hard-dp" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
# DataRouter 详细设计文档
|
||||||
|
|
||||||
|
## 1. 设计目标
|
||||||
|
|
||||||
|
轻量级 C 语言数据路由库。发送能力与接收能力分开声明,端口可独立设置 `send_type` 和 `recv_type`。发送时自动广播到所有匹配端口,接收时通过 `dr_port_dispatch()` 查表自动路由到回调。
|
||||||
|
|
||||||
|
### 核心设计
|
||||||
|
|
||||||
|
```
|
||||||
|
发送: dr_send_sensor(data, len)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
遍历端口表 → send_type 匹配?
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
for each handler(port, data) ─── UART / TCP / CAN
|
||||||
|
|
||||||
|
接收: dr_port_dispatch(port, data, len)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
查 recv_table[port.recv_type]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
dr_on_recv_rtcm(port, data, len) ← 用户实现
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 数据结构
|
||||||
|
|
||||||
|
### 2.1 `port_entry_t`
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define DR_MAX_HANDLERS_PER_PORT 4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int send_type; // DR_SEND_xxx / -1
|
||||||
|
int recv_type; // DR_RECV_xxx / -1
|
||||||
|
dr_send_handler_t handlers[DR_MAX_HANDLERS_PER_PORT];
|
||||||
|
int count;
|
||||||
|
uint8_t in_use;
|
||||||
|
} port_entry_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 接收回调函数指针表
|
||||||
|
|
||||||
|
```c
|
||||||
|
// 编译期由 X-macro 生成,DR_RECV_rtcm 的枚举值即为数组下标
|
||||||
|
static void (*const recv_table[DR_RECV_CAP_COUNT])(uint32_t, const void*, size_t) = {
|
||||||
|
dr_on_recv_rtcm,
|
||||||
|
dr_on_recv_command,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 端口表
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define DR_MAX_PORTS 64
|
||||||
|
static port_entry_t ports[DR_MAX_PORTS];
|
||||||
|
static uint8_t initialized;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. API
|
||||||
|
|
||||||
|
### 3.1 端口管理
|
||||||
|
|
||||||
|
```c
|
||||||
|
dr_port_t dr_port_create(void);
|
||||||
|
void dr_port_delete(dr_port_t port);
|
||||||
|
|
||||||
|
void dr_port_set_send_type(port, int cap_id);
|
||||||
|
int dr_port_get_send_type(port);
|
||||||
|
void dr_port_set_recv_type(port, int cap_id);
|
||||||
|
int dr_port_get_recv_type(port);
|
||||||
|
|
||||||
|
int dr_port_add_handler(port, handler);
|
||||||
|
int dr_port_remove_handler(port, handler);
|
||||||
|
void dr_port_clear_handlers(port);
|
||||||
|
int dr_port_handler_count(port);
|
||||||
|
|
||||||
|
void dr_port_dispatch(port, data, len); // ← 自动路由接收
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 发送触发
|
||||||
|
|
||||||
|
```c
|
||||||
|
int dr_send_sensor(const void *data, size_t len);
|
||||||
|
int dr_send_status(const void *data, size_t len);
|
||||||
|
```
|
||||||
|
|
||||||
|
返回值:0 成功 / -1 未初始化 / -2 无匹配端口
|
||||||
|
|
||||||
|
### 3.3 接收回调
|
||||||
|
|
||||||
|
```c
|
||||||
|
void dr_on_recv_rtcm(uint32_t port_id, const void *data, size_t len);
|
||||||
|
void dr_on_recv_command(uint32_t port_id, const void *data, size_t len);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 核心流程
|
||||||
|
|
||||||
|
### 4.1 发送
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
actor App
|
||||||
|
participant dr_send_sensor as Send
|
||||||
|
participant ports[] as Table
|
||||||
|
participant handlers[] as H
|
||||||
|
|
||||||
|
App -> Send : send_sensor("temp", 9)
|
||||||
|
loop for p in 0..MAX_PORTS-1
|
||||||
|
Send -> Table : in_use && send_type == SENSOR ?
|
||||||
|
alt 匹配
|
||||||
|
loop for h in handlers
|
||||||
|
Send -> H : handlers[h](p, data, len)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
alt 至少调了一次
|
||||||
|
Send --> App : return 0
|
||||||
|
else 无匹配
|
||||||
|
Send --> App : return -2
|
||||||
|
end
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 接收(dispatch)
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
actor 外设ISR as Dev
|
||||||
|
participant dr_port_dispatch as Dispatch
|
||||||
|
participant recv_table[] as Table
|
||||||
|
participant dr_on_recv_rtcm as Cb
|
||||||
|
|
||||||
|
Dev -> Dispatch : dispatch(port, data, len)
|
||||||
|
Dispatch -> Table : 查 recv_table[port.recv_type]
|
||||||
|
Dispatch -> Cb : recv_table[rid](port, data, len)
|
||||||
|
Cb --> Dev : void
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Dispatch 实现
|
||||||
|
|
||||||
|
`dr_port_dispatch` 是零分支的查表路由:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void dr_port_dispatch(dr_port_t port, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return;
|
||||||
|
int rid = ports[port].recv_type;
|
||||||
|
if (rid < 0 || rid >= DR_RECV_CAP_COUNT) return;
|
||||||
|
recv_table[rid]((uint32_t)port, data, len); // 直接函数指针调用
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`recv_table[]` 是 `const` 数组,编译期由 X-macro 生成。`DR_RECV_rtcm` 的枚举值等于数组下标,查表时间为 O(1),无分支预测开销,适合 ISR。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 错误码
|
||||||
|
|
||||||
|
| 返回值 | 含义 |
|
||||||
|
|:------:|------|
|
||||||
|
| 0 | 成功 |
|
||||||
|
| -1 | 库未初始化 |
|
||||||
|
| -2 | 无端口匹配该 send_type |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 约束
|
||||||
|
|
||||||
|
| 约束 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 能力声明 | 编译期固定,修改需重新编译 |
|
||||||
|
| 最大端口数 | 默认 64,通过 `-D` 覆盖 |
|
||||||
|
| 每端口 handler 上限 | 默认 4,通过 `-D` 覆盖 |
|
||||||
|
| 线程安全 | 不支持(无锁),多线程需外部加锁 |
|
||||||
|
| 弱符号 | GCC/Clang 原生支持 |
|
||||||
|
| 内存分配 | 纯静态,无 malloc/free |
|
||||||
@@ -1,2 +1,138 @@
|
|||||||
# DataRouter
|
# DataRouter
|
||||||
|
|
||||||
|
轻量级 C 语言数据路由库。发送能力和接收能力分开声明,端口绑定 `send_type` + `recv_type` + handler 列表。发送时自动广播到所有匹配端口,接收时 `dr_port_dispatch()` 自动路由到对应回调。
|
||||||
|
|
||||||
|
## 概念
|
||||||
|
|
||||||
|
| 术语 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **发送能力** | 编译期声明的可发送报文类型,生成 `dr_send_<id>(data, len)` |
|
||||||
|
| **接收能力** | 编译期声明的可接收报文类型,生成 `dr_on_recv_<id>(port, data, len)` |
|
||||||
|
| **端口** | 运行期连接点,包含 `send_type` + `recv_type` + handler 列表 |
|
||||||
|
| **Handler** | 用户实现的物理外设发送函数,一个端口可注册多个(默认上限 4) |
|
||||||
|
| **Dispatch** | `dr_port_dispatch(port, data, len)` 根据端口的 `recv_type` 自动路由到回调 |
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 声明能力
|
||||||
|
|
||||||
|
创建自己的 `datarouter_config.h`(可参考 `datarouter_config_template.h`):
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define DR_SEND_CAPABILITIES \
|
||||||
|
DR_SEND(sensor, "Sensor data report") \
|
||||||
|
DR_SEND(status, "Device status report")
|
||||||
|
|
||||||
|
#define DR_RECV_CAPABILITIES \
|
||||||
|
DR_RECV(rtcm, "RTCM correction data") \
|
||||||
|
DR_RECV(command, "Remote control command")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 实现 handler 和回调
|
||||||
|
|
||||||
|
```c
|
||||||
|
static void uart_write(uint32_t port_id, const void *data, size_t len) {
|
||||||
|
HAL_UART_Transmit(&huart1, data, len, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_on_recv_rtcm(uint32_t port_id, const void *data, size_t len) {
|
||||||
|
apply_rtcm_correction(data, len);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 创建端口
|
||||||
|
|
||||||
|
```c
|
||||||
|
dr_init();
|
||||||
|
|
||||||
|
dr_port_t uart = dr_port_create();
|
||||||
|
dr_port_set_send_type(uart, DR_SEND_sensor);
|
||||||
|
dr_port_set_recv_type(uart, DR_RECV_rtcm);
|
||||||
|
dr_port_add_handler(uart, uart_write);
|
||||||
|
dr_port_add_handler(uart, tcp_write);
|
||||||
|
|
||||||
|
/* 发送:自动广播到所有 send_type=sensor 的端口 */
|
||||||
|
dr_send_sensor("temperature:25.3", 16);
|
||||||
|
|
||||||
|
/* 接收:外设中断中一行 dispatch,自动调 dr_on_recv_rtcm() */
|
||||||
|
dr_port_dispatch(uart, data, len);
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 一览
|
||||||
|
|
||||||
|
### 初始化
|
||||||
|
|
||||||
|
```c
|
||||||
|
void dr_init(void);
|
||||||
|
void dr_reset(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 端口管理
|
||||||
|
|
||||||
|
```c
|
||||||
|
dr_port_t dr_port_create(void);
|
||||||
|
void dr_port_delete(dr_port_t port);
|
||||||
|
|
||||||
|
void dr_port_set_send_type(port, int cap_id);
|
||||||
|
int dr_port_get_send_type(port);
|
||||||
|
void dr_port_set_recv_type(port, int cap_id);
|
||||||
|
int dr_port_get_recv_type(port);
|
||||||
|
|
||||||
|
int dr_port_add_handler(port, handler);
|
||||||
|
int dr_port_remove_handler(port, handler);
|
||||||
|
void dr_port_clear_handlers(port);
|
||||||
|
int dr_port_handler_count(port);
|
||||||
|
|
||||||
|
void dr_port_dispatch(port, data, len); /* 自动路由接收 */
|
||||||
|
```
|
||||||
|
|
||||||
|
### 发送触发
|
||||||
|
|
||||||
|
```c
|
||||||
|
int dr_send_sensor(const void *data, size_t len); // 0 成功
|
||||||
|
int dr_send_status(const void *data, size_t len); // -1 未初始化
|
||||||
|
// -2 无匹配端口
|
||||||
|
```
|
||||||
|
|
||||||
|
### 接收回调
|
||||||
|
|
||||||
|
```c
|
||||||
|
void dr_on_recv_rtcm(uint32_t port_id, const void *data, size_t len);
|
||||||
|
void dr_on_recv_command(uint32_t port_id, const void *data, size_t len);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 能力元数据
|
||||||
|
|
||||||
|
```c
|
||||||
|
int dr_send_cap_count(void);
|
||||||
|
const char *dr_send_cap_name(int cap_id);
|
||||||
|
const char *dr_send_cap_desc(int cap_id);
|
||||||
|
|
||||||
|
int dr_recv_cap_count(void);
|
||||||
|
const char *dr_recv_cap_name(int cap_id);
|
||||||
|
const char *dr_recv_cap_desc(int cap_id);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 路由模型
|
||||||
|
|
||||||
|
```
|
||||||
|
发送:dr_send_sensor("temp:25.3", 9)
|
||||||
|
│
|
||||||
|
├─→ port A (send_type=sensor) handlers = [uart_write, tcp_write]
|
||||||
|
└─→ port B (send_type=sensor) handlers = [can_write]
|
||||||
|
|
||||||
|
接收:dr_port_dispatch(uart1, data, len)
|
||||||
|
│
|
||||||
|
└─→ uart1.recv_type = DR_RECV_rtcm
|
||||||
|
└─→ dr_on_recv_rtcm(uart1, data, len) ← 查表调用
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build
|
||||||
|
ctest --test-dir build
|
||||||
|
./build/test_datarouter
|
||||||
|
```
|
||||||
|
|
||||||
|
当前 24 个测试用例,覆盖端口管理、send_type/recv_type、handler、自动广播、dispatch、能力元数据。
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# DataRouter 单元测试用例文档
|
||||||
|
|
||||||
|
## 测试环境
|
||||||
|
|
||||||
|
| 项目 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 语言标准 | C11 |
|
||||||
|
| 编译器 | GCC 11.4.0 |
|
||||||
|
| 测试框架 | 自定义轻量框架(宏 + goto cleanup) |
|
||||||
|
| 构建系统 | CMake ≥ 3.10 |
|
||||||
|
| 发送能力 | `sensor` / `status` |
|
||||||
|
| 接收能力 | `rtcm` / `command` |
|
||||||
|
|
||||||
|
## 运行方式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -S . -B build
|
||||||
|
cmake --build build
|
||||||
|
ctest --test-dir build
|
||||||
|
./build/test_datarouter
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试用例列表
|
||||||
|
|
||||||
|
### 1. 未初始化(1 个)
|
||||||
|
|
||||||
|
| # | 测试名 | 描述 | 步骤 | 预期 |
|
||||||
|
|---|--------|------|------|------|
|
||||||
|
| 1 | `error_uninit` | 未 init 时发送 | `dr_send_sensor("d", 1)` | 返回 -1 |
|
||||||
|
|
||||||
|
### 2. 端口管理(4 个)
|
||||||
|
|
||||||
|
| # | 测试名 | 描述 | 步骤 | 预期 |
|
||||||
|
|---|--------|------|------|------|
|
||||||
|
| 2 | `port_create_basic` | 基本创建 | `dr_port_create()` | 返回 ≥ 0 |
|
||||||
|
| 3 | `port_create_max` | 满容量 64 | 循环到满 | 第 65 个 INVALID |
|
||||||
|
| 4 | `port_delete_invalid` | 删除无效 ID | `delete(-1)` + `delete(999)` | 不崩溃 |
|
||||||
|
| 5 | `port_default_state` | 默认状态 | 查 send_type / recv_type / count | 均为 -1 / 0 |
|
||||||
|
|
||||||
|
### 3. send_type / recv_type / handler(4 个)
|
||||||
|
|
||||||
|
| # | 测试名 | 描述 | 步骤 | 预期 |
|
||||||
|
|---|--------|------|------|------|
|
||||||
|
| 6 | `send_type_set_clear` | 设置并清除 send_type | set(sensor) → get → set(-1) → get | sensor → -1 |
|
||||||
|
| 7 | `recv_type_set_clear` | 设置并清除 recv_type | set(rtcm) → get → set(-1) → get | rtcm → -1 |
|
||||||
|
| 8 | `types_independent` | 收发类型独立设置 | 同时 set_send(sensor) + set_recv(command) | 各自返回正确值 |
|
||||||
|
| 9 | `handler_add_remove` | 添加后移除 handler | add(h) → count=1 → remove(h) → count=0 | 正确 |
|
||||||
|
|
||||||
|
### 4. 发送 — 自动广播(7 个)
|
||||||
|
|
||||||
|
| # | 测试名 | 描述 | 步骤 | 预期 |
|
||||||
|
|---|--------|------|------|------|
|
||||||
|
| 10 | `send_no_match_port` | 无匹配端口 | 不创建端口直接 send | 返回 -2 |
|
||||||
|
| 11 | `send_one_port_one_handler` | 单端口单 handler | send_type + add → send | 0,handler 1 次 |
|
||||||
|
| 12 | `send_multi_ports` | 两端口同类型 | p1(sensor) + p2(sensor) → send | handler 2 次 |
|
||||||
|
| 13 | `send_type_filter` | 类型过滤 | p1(sensor) + p2(status) → send_sensor | 只触发 p1 |
|
||||||
|
| 14 | `send_after_delete` | 删除端口后 send | 创建→设好→删除→send | 返回 -2 |
|
||||||
|
| 15 | `send_zero_length` | 零长度数据 | send("x", 0) | 0,handler 被调 |
|
||||||
|
| 16 | `send_null_data` | NULL 数据 | send(NULL, 0) | 0,handler 被调 |
|
||||||
|
|
||||||
|
### 5. 接收回调 + dispatch(6 个)
|
||||||
|
|
||||||
|
| # | 测试名 | 描述 | 步骤 | 预期 |
|
||||||
|
|---|--------|------|------|------|
|
||||||
|
| 17 | `recv_callback_direct` | 直接调用回调 | `dr_on_recv_rtcm()` + `dr_on_recv_command()` | 各自触发 |
|
||||||
|
| 18 | `dispatch_valid` | dispatch 自动路由 rtcm | set_recv(rtcm) → dispatch(port, data) | dr_on_recv_rtcm 触发 |
|
||||||
|
| 19 | `dispatch_command` | dispatch 自动路由 command | set_recv(command) → dispatch(port, data) | dr_on_recv_command 触发 |
|
||||||
|
| 20 | `dispatch_unset` | recv_type 未设置 | recv_type=-1 → dispatch | 无回调触发 |
|
||||||
|
| 21 | `dispatch_invalid_port` | 无效端口 dispatch | dispatch(999/-1, ...) | 无回调触发 |
|
||||||
|
| 22 | `dispatch_deleted_port` | 已删端口 dispatch | 创建→设置→删除→dispatch | 无回调触发 |
|
||||||
|
|
||||||
|
### 6. 能力元数据(2 个)
|
||||||
|
|
||||||
|
| # | 测试名 | 描述 | 步骤 | 预期 |
|
||||||
|
|---|--------|------|------|------|
|
||||||
|
| 23 | `send_cap_meta` | 发送能力元数据 | count / name / 边界 | 正确 |
|
||||||
|
| 24 | `recv_cap_meta` | 接收能力元数据 | count / name / 边界 | 正确 |
|
||||||
|
|
||||||
|
## 覆盖矩阵
|
||||||
|
|
||||||
|
| 功能模块 | 用例数 | 主要验证点 |
|
||||||
|
|----------|:------:|------------|
|
||||||
|
| 未初始化 | 1 | send → -1 |
|
||||||
|
| 端口管理 | 4 | 创建/满容量/删除/默认状态 |
|
||||||
|
| 收发类型 & handler | 4 | send_type/recv_type 独立设置、handler 增删 |
|
||||||
|
| 发送自动广播 | 7 | 单播/多播/过滤/删除后/零长/NULL |
|
||||||
|
| 接收 dispatch | 6 | 直接回调/有效路由/无效路由/未设置/无效端口/已删除 |
|
||||||
|
| 能力元数据 | 2 | 两组独立查询 |
|
||||||
|
|
||||||
|
**总计:24 个测试用例**
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
|
||||||
|
####### Any changes to this file will be overwritten by the next CMake run ####
|
||||||
|
####### The input file was DataRouterConfig.cmake.in ########
|
||||||
|
|
||||||
|
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
|
||||||
|
|
||||||
|
macro(set_and_check _var _file)
|
||||||
|
set(${_var} "${_file}")
|
||||||
|
if(NOT EXISTS "${_file}")
|
||||||
|
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(check_required_components _NAME)
|
||||||
|
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||||
|
if(NOT ${_NAME}_${comp}_FOUND)
|
||||||
|
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||||
|
set(${_NAME}_FOUND FALSE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
####################################################################################
|
||||||
|
|
||||||
|
get_filename_component(DataRouter_INCLUDE_DIR
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/../../../include" ABSOLUTE)
|
||||||
|
get_filename_component(DataRouter_LIBRARY_DIR
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/../../../lib" ABSOLUTE)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/DataRouterTargets.cmake" OPTIONAL)
|
||||||
|
|
||||||
|
# 无论 targets 文件是否加载,都覆盖 include 路径为正确值
|
||||||
|
# (targets 文件中的 _IMPORT_PREFIX 在某些平台/工具链下可能计算异常)
|
||||||
|
if(TARGET DataRouter)
|
||||||
|
set_target_properties(DataRouter PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${DataRouter_INCLUDE_DIR}"
|
||||||
|
)
|
||||||
|
if(NOT TARGET DataRouter::DataRouter)
|
||||||
|
add_library(DataRouter::DataRouter ALIAS DataRouter)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_library(DataRouter::DataRouter STATIC IMPORTED)
|
||||||
|
set_target_properties(DataRouter::DataRouter PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${DataRouter_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}DataRouter${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${DataRouter_INCLUDE_DIR}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
check_required_components(DataRouter)
|
||||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,27 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
get_filename_component(DataRouter_INCLUDE_DIR
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/../../../include" ABSOLUTE)
|
||||||
|
get_filename_component(DataRouter_LIBRARY_DIR
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/../../../lib" ABSOLUTE)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/DataRouterTargets.cmake" OPTIONAL)
|
||||||
|
|
||||||
|
# 无论 targets 文件是否加载,都覆盖 include 路径为正确值
|
||||||
|
# (targets 文件中的 _IMPORT_PREFIX 在某些平台/工具链下可能计算异常)
|
||||||
|
if(TARGET DataRouter)
|
||||||
|
set_target_properties(DataRouter PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${DataRouter_INCLUDE_DIR}"
|
||||||
|
)
|
||||||
|
if(NOT TARGET DataRouter::DataRouter)
|
||||||
|
add_library(DataRouter::DataRouter ALIAS DataRouter)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_library(DataRouter::DataRouter STATIC IMPORTED)
|
||||||
|
set_target_properties(DataRouter::DataRouter PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${DataRouter_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}DataRouter${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${DataRouter_INCLUDE_DIR}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
check_required_components(DataRouter)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
set(CMAKE_SYSTEM_NAME Generic)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||||
|
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
set(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||||
|
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
set(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||||
|
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
set(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR amd64)
|
||||||
|
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
+212
@@ -0,0 +1,212 @@
|
|||||||
|
/**
|
||||||
|
* @file datarouter.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "datarouter.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define DR_WEAK __attribute__((weak))
|
||||||
|
#else
|
||||||
|
#define DR_WEAK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DR_MAX_PORTS
|
||||||
|
#define DR_MAX_PORTS 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int send_type;
|
||||||
|
int recv_type;
|
||||||
|
dr_send_handler_t handlers[DR_MAX_HANDLERS_PER_PORT];
|
||||||
|
int count;
|
||||||
|
uint8_t in_use;
|
||||||
|
} port_entry_t;
|
||||||
|
|
||||||
|
static port_entry_t ports[DR_MAX_PORTS];
|
||||||
|
static uint8_t initialized;
|
||||||
|
|
||||||
|
/* ---- 元数据 ---- */
|
||||||
|
|
||||||
|
static const char *send_names[] = {
|
||||||
|
#define DR_SEND(id, desc) #id,
|
||||||
|
DR_SEND_CAPABILITIES
|
||||||
|
#undef DR_SEND
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *send_descs[] = {
|
||||||
|
#define DR_SEND(id, desc) desc,
|
||||||
|
DR_SEND_CAPABILITIES
|
||||||
|
#undef DR_SEND
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *recv_names[] = {
|
||||||
|
#define DR_RECV(id, desc) #id,
|
||||||
|
DR_RECV_CAPABILITIES
|
||||||
|
#undef DR_RECV
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *recv_descs[] = {
|
||||||
|
#define DR_RECV(id, desc) desc,
|
||||||
|
DR_RECV_CAPABILITIES
|
||||||
|
#undef DR_RECV
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---- 接收回调函数指针表(dispatch 查表用) ---- */
|
||||||
|
|
||||||
|
static void (*const recv_table[DR_RECV_CAP_COUNT])(uint32_t, const void*, size_t) = {
|
||||||
|
#define DR_RECV(id, desc) dr_on_recv_##id,
|
||||||
|
DR_RECV_CAPABILITIES
|
||||||
|
#undef DR_RECV
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---- 弱符号接收回调 ---- */
|
||||||
|
|
||||||
|
#define DR_RECV(id, desc) \
|
||||||
|
DR_WEAK void dr_on_recv_##id( \
|
||||||
|
uint32_t port_id, const void *data, size_t len) \
|
||||||
|
{ (void)port_id; (void)data; (void)len; }
|
||||||
|
DR_RECV_CAPABILITIES
|
||||||
|
#undef DR_RECV
|
||||||
|
|
||||||
|
/* ---- 发送触发函数 ---- */
|
||||||
|
|
||||||
|
#define DR_SEND(id, desc) \
|
||||||
|
int dr_send_##id(const void *data, size_t len) \
|
||||||
|
{ \
|
||||||
|
if (!initialized) return -1; \
|
||||||
|
int called = 0; \
|
||||||
|
for (uint32_t _p = 0; _p < DR_MAX_PORTS; _p++) { \
|
||||||
|
if (!ports[_p].in_use) continue; \
|
||||||
|
if (ports[_p].send_type != DR_SEND_##id) continue; \
|
||||||
|
for (int _h = 0; _h < ports[_p].count; _h++) { \
|
||||||
|
ports[_p].handlers[_h](_p, data, len); \
|
||||||
|
called = 1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return called ? 0 : -2; \
|
||||||
|
}
|
||||||
|
DR_SEND_CAPABILITIES
|
||||||
|
#undef DR_SEND
|
||||||
|
|
||||||
|
/* ---- 端口管理 ---- */
|
||||||
|
|
||||||
|
void dr_init(void)
|
||||||
|
{
|
||||||
|
if (initialized) return;
|
||||||
|
memset(ports, 0, sizeof(ports));
|
||||||
|
initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_reset(void)
|
||||||
|
{
|
||||||
|
initialized = 0;
|
||||||
|
memset(ports, 0, sizeof(ports));
|
||||||
|
}
|
||||||
|
|
||||||
|
dr_port_t dr_port_create(void)
|
||||||
|
{
|
||||||
|
if (!initialized) return DR_INVALID_PORT;
|
||||||
|
for (int i = 0; i < DR_MAX_PORTS; i++) {
|
||||||
|
if (!ports[i].in_use) {
|
||||||
|
ports[i].in_use = 1;
|
||||||
|
ports[i].send_type = -1;
|
||||||
|
ports[i].recv_type = -1;
|
||||||
|
ports[i].count = 0;
|
||||||
|
return (dr_port_t)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DR_INVALID_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_port_delete(dr_port_t port)
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS) return;
|
||||||
|
ports[port].in_use = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_port_set_send_type(dr_port_t port, int cap_id)
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return;
|
||||||
|
ports[port].send_type = cap_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dr_port_get_send_type(dr_port_t port)
|
||||||
|
{
|
||||||
|
if (!initialized) return -1;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return -1;
|
||||||
|
return ports[port].send_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_port_set_recv_type(dr_port_t port, int cap_id)
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return;
|
||||||
|
ports[port].recv_type = cap_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dr_port_get_recv_type(dr_port_t port)
|
||||||
|
{
|
||||||
|
if (!initialized) return -1;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return -1;
|
||||||
|
return ports[port].recv_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_port_dispatch(dr_port_t port, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return;
|
||||||
|
int rid = ports[port].recv_type;
|
||||||
|
if (rid < 0 || rid >= DR_RECV_CAP_COUNT) return;
|
||||||
|
recv_table[rid]((uint32_t)port, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dr_port_add_handler(dr_port_t port, dr_send_handler_t handler)
|
||||||
|
{
|
||||||
|
if (!initialized) return -1;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return -1;
|
||||||
|
if (ports[port].count >= DR_MAX_HANDLERS_PER_PORT) return -2;
|
||||||
|
for (int i = 0; i < ports[port].count; i++)
|
||||||
|
if (ports[port].handlers[i] == handler) return -3;
|
||||||
|
ports[port].handlers[ports[port].count++] = handler;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dr_port_remove_handler(dr_port_t port, dr_send_handler_t handler)
|
||||||
|
{
|
||||||
|
if (!initialized) return -1;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return -1;
|
||||||
|
for (int i = 0; i < ports[port].count; i++) {
|
||||||
|
if (ports[port].handlers[i] == handler) {
|
||||||
|
ports[port].handlers[i] = ports[port].handlers[--ports[port].count];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_port_clear_handlers(dr_port_t port)
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return;
|
||||||
|
ports[port].count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dr_port_handler_count(dr_port_t port)
|
||||||
|
{
|
||||||
|
if (!initialized) return -1;
|
||||||
|
if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return -1;
|
||||||
|
return ports[port].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- 元数据查询 ---- */
|
||||||
|
|
||||||
|
int dr_send_cap_count(void) { return DR_SEND_CAP_COUNT; }
|
||||||
|
const char *dr_send_cap_name(int c) { return (c<0||c>=DR_SEND_CAP_COUNT)?NULL:send_names[c]; }
|
||||||
|
const char *dr_send_cap_desc(int c) { return (c<0||c>=DR_SEND_CAP_COUNT)?NULL:send_descs[c]; }
|
||||||
|
|
||||||
|
int dr_recv_cap_count(void) { return DR_RECV_CAP_COUNT; }
|
||||||
|
const char *dr_recv_cap_name(int c) { return (c<0||c>=DR_RECV_CAP_COUNT)?NULL:recv_names[c]; }
|
||||||
|
const char *dr_recv_cap_desc(int c) { return (c<0||c>=DR_RECV_CAP_COUNT)?NULL:recv_descs[c]; }
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* @file datarouter.h
|
||||||
|
* @brief 数据路由库 —— 公共接口
|
||||||
|
*
|
||||||
|
* ## 概念
|
||||||
|
*
|
||||||
|
* - **发送能力**:编译期声明的可发送报文类型,生成 dr_send_<id>(data, len)
|
||||||
|
* - **接收能力**:编译期声明的可接收报文类型,生成 dr_on_recv_<id>(port, data, len)
|
||||||
|
* - **端口**:运行期连接点,包含 send_type + recv_type + handler 列表
|
||||||
|
*
|
||||||
|
* ## 发送路由
|
||||||
|
*
|
||||||
|
* dr_send_<id>(data, len) 遍历所有端口,找到 send_type 匹配的端口,
|
||||||
|
* 逐一调用其全部 handler,无需指定从哪个端口发送。
|
||||||
|
*
|
||||||
|
* ## 接收路由
|
||||||
|
*
|
||||||
|
* 外设(UART / SPI / CAN)收到数据后,调用 dr_port_dispatch(port, data, len),
|
||||||
|
* 库根据端口的 recv_type 自动查表调用对应的 dr_on_recv_<id>(),无需手动 if/else。
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DR_H
|
||||||
|
#define DR_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if defined(__has_include)
|
||||||
|
# if __has_include(<datarouter_config.h>)
|
||||||
|
# include <datarouter_config.h>
|
||||||
|
# else
|
||||||
|
# include "datarouter_config.h"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include "datarouter_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========== 发送能力枚举 ========== */
|
||||||
|
|
||||||
|
enum dr_send_cap {
|
||||||
|
#define DR_SEND(id, desc) DR_SEND_##id,
|
||||||
|
DR_SEND_CAPABILITIES
|
||||||
|
#undef DR_SEND
|
||||||
|
DR_SEND_CAP_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ========== 接收能力枚举 ========== */
|
||||||
|
|
||||||
|
enum dr_recv_cap {
|
||||||
|
#define DR_RECV(id, desc) DR_RECV_##id,
|
||||||
|
DR_RECV_CAPABILITIES
|
||||||
|
#undef DR_RECV
|
||||||
|
DR_RECV_CAP_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ========== 外设发送 handler ========== */
|
||||||
|
|
||||||
|
typedef void (*dr_send_handler_t)(uint32_t port_id, const void *data, size_t len);
|
||||||
|
|
||||||
|
#ifndef DR_MAX_HANDLERS_PER_PORT
|
||||||
|
#define DR_MAX_HANDLERS_PER_PORT 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========== 发送触发函数 ========== */
|
||||||
|
|
||||||
|
#define DR_SEND(id, desc) \
|
||||||
|
int dr_send_##id(const void *data, size_t len);
|
||||||
|
DR_SEND_CAPABILITIES
|
||||||
|
#undef DR_SEND
|
||||||
|
|
||||||
|
/* ========== 接收回调声明 ========== */
|
||||||
|
|
||||||
|
#define DR_RECV(id, desc) \
|
||||||
|
void dr_on_recv_##id(uint32_t port_id, const void *data, size_t len);
|
||||||
|
DR_RECV_CAPABILITIES
|
||||||
|
#undef DR_RECV
|
||||||
|
|
||||||
|
/* ========== 端口管理 API ========== */
|
||||||
|
|
||||||
|
typedef int32_t dr_port_t;
|
||||||
|
#define DR_INVALID_PORT ((dr_port_t)-1)
|
||||||
|
|
||||||
|
void dr_init(void);
|
||||||
|
void dr_reset(void);
|
||||||
|
|
||||||
|
dr_port_t dr_port_create(void);
|
||||||
|
void dr_port_delete(dr_port_t port);
|
||||||
|
|
||||||
|
void dr_port_set_send_type(dr_port_t port, int cap_id);
|
||||||
|
int dr_port_get_send_type(dr_port_t port);
|
||||||
|
void dr_port_set_recv_type(dr_port_t port, int cap_id);
|
||||||
|
int dr_port_get_recv_type(dr_port_t port);
|
||||||
|
|
||||||
|
int dr_port_add_handler(dr_port_t port, dr_send_handler_t handler);
|
||||||
|
int dr_port_remove_handler(dr_port_t port, dr_send_handler_t handler);
|
||||||
|
void dr_port_clear_handlers(dr_port_t port);
|
||||||
|
int dr_port_handler_count(dr_port_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按端口绑定的 recv_type 自动路由到对应的 dr_on_recv_<id>() 回调
|
||||||
|
*
|
||||||
|
* 外设中断中收到数据后调用此函数,无需自己写 if/else 判断报文类型。
|
||||||
|
* 库通过 X-macro 生成函数指针表,直接查表调用,零分支预测开销。
|
||||||
|
*
|
||||||
|
* @param[in] port 接收端口 ID
|
||||||
|
* @param[in] data 数据缓冲区
|
||||||
|
* @param[in] len 数据长度
|
||||||
|
*/
|
||||||
|
void dr_port_dispatch(dr_port_t port, const void *data, size_t len);
|
||||||
|
|
||||||
|
/* ========== 能力元数据查询 ========== */
|
||||||
|
|
||||||
|
int dr_send_cap_count(void);
|
||||||
|
const char *dr_send_cap_name(int cap_id);
|
||||||
|
const char *dr_send_cap_desc(int cap_id);
|
||||||
|
|
||||||
|
int dr_recv_cap_count(void);
|
||||||
|
const char *dr_recv_cap_name(int cap_id);
|
||||||
|
const char *dr_recv_cap_desc(int cap_id);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* DR_H */
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* @file datarouter_config.h
|
||||||
|
* @brief 数据路由默认配置
|
||||||
|
*
|
||||||
|
* 这是库内置的默认配置,提供示例能力声明。
|
||||||
|
* 用户可自定义此文件以实现自己的报文类型:
|
||||||
|
*
|
||||||
|
* 1. 复制当前文件到你的项目目录
|
||||||
|
* 2. 按需修改 DR_SEND_CAPABILITIES / DR_RECV_CAPABILITIES
|
||||||
|
* 3. 编译时添加 -I /path/to/your/config 覆盖库的默认配置
|
||||||
|
*
|
||||||
|
* 覆盖后库将使用你的版本,无需修改库源代码。
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DR_CONFIG_H
|
||||||
|
#define DR_CONFIG_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def DR_SEND_CAPABILITIES
|
||||||
|
* @brief 发送能力列表
|
||||||
|
*
|
||||||
|
* 每行格式:DR_SEND(标识符, "描述")
|
||||||
|
* 每项生成:发送触发函数 dr_send_<id>(port, data, len)
|
||||||
|
*/
|
||||||
|
#define DR_SEND_CAPABILITIES \
|
||||||
|
DR_SEND(sensor, "Sensor data report") \
|
||||||
|
DR_SEND(status, "Device status report")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def DR_RECV_CAPABILITIES
|
||||||
|
* @brief 接收能力列表
|
||||||
|
*
|
||||||
|
* 每行格式:DR_RECV(标识符, "描述")
|
||||||
|
* 每项生成:接收回调声明 dr_on_recv_<id>(port, data, len)
|
||||||
|
*/
|
||||||
|
#define DR_RECV_CAPABILITIES \
|
||||||
|
DR_RECV(rtcm, "RTCM correction data") \
|
||||||
|
DR_RECV(command, "Remote control command")
|
||||||
|
|
||||||
|
#endif /* DR_CONFIG_H */
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* @file datarouter_config_template.h
|
||||||
|
* @brief 数据路由配置模板 —— 复制此文件到项目目录并修改
|
||||||
|
*
|
||||||
|
* 使用方法:
|
||||||
|
* 1. 将此文件复制到你的项目目录,重命名为 datarouter_config.h
|
||||||
|
* 2. 修改下面的 DR_SEND_CAPABILITIES 和 DR_RECV_CAPABILITIES
|
||||||
|
* 3. 编译时添加 -I /path/to/your/project
|
||||||
|
* 4. 库将自动使用你的配置,无需修改库源代码
|
||||||
|
*
|
||||||
|
* 格式说明:
|
||||||
|
* 发送能力:DR_SEND(标识符, "描述")
|
||||||
|
* 接收能力:DR_RECV(标识符, "描述")
|
||||||
|
*
|
||||||
|
* 标识符只能包含字母、数字、下划线。
|
||||||
|
* 描述为字符串字面量。
|
||||||
|
*
|
||||||
|
* 示例配置:
|
||||||
|
* // 传感器设备:只需发送
|
||||||
|
* #define DR_SEND_CAPABILITIES \
|
||||||
|
* DR_SEND(sensor, "Sensor data report")
|
||||||
|
* #define DR_RECV_CAPABILITIES
|
||||||
|
*
|
||||||
|
* // 遥控设备:只需接收
|
||||||
|
* #define DR_SEND_CAPABILITIES
|
||||||
|
* #define DR_RECV_CAPABILITIES \
|
||||||
|
* DR_RECV(command, "Remote command")
|
||||||
|
*
|
||||||
|
* // 网关设备:同时收发
|
||||||
|
* #define DR_SEND_CAPABILITIES \
|
||||||
|
* DR_SEND(status, "Status report")
|
||||||
|
* #define DR_RECV_CAPABILITIES \
|
||||||
|
* DR_RECV(config, "Configuration update")
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DR_CONFIG_H
|
||||||
|
#define DR_CONFIG_H
|
||||||
|
|
||||||
|
/* ========== 在此声明你的发送能力 ========== */
|
||||||
|
|
||||||
|
#define DR_SEND_CAPABILITIES \
|
||||||
|
DR_SEND(sensor, "Sensor data report") \
|
||||||
|
DR_SEND(status, "Device status report")
|
||||||
|
|
||||||
|
/* ========== 在此声明你的接收能力 ========== */
|
||||||
|
|
||||||
|
#define DR_RECV_CAPABILITIES \
|
||||||
|
DR_RECV(rtcm, "RTCM correction data") \
|
||||||
|
DR_RECV(command, "Remote control command")
|
||||||
|
|
||||||
|
#endif /* DR_CONFIG_H */
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* @file example.c
|
||||||
|
*
|
||||||
|
* 展示:
|
||||||
|
* 1. send_type + 多 handler 发送广播
|
||||||
|
* 2. recv_type + dr_port_dispatch 自动路由接收
|
||||||
|
* 3. 外设中断中只需一行 dr_port_dispatch()
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "datarouter.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* ---- 发送 handler ---- */
|
||||||
|
|
||||||
|
static void uart_write(uint32_t port_id, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
printf("[UART port %u] %.*s\n", port_id, (int)len, (const char *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_write(uint32_t port_id, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
printf("[TCP port %u] %.*s\n", port_id, (int)len, (const char *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- 接收回调 ---- */
|
||||||
|
|
||||||
|
void dr_on_recv_rtcm(uint32_t port_id, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
printf("[RX:rtcm port %u] %.*s\n", port_id, (int)len, (const char *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dr_on_recv_command(uint32_t port_id, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
printf("[RX:cmd port %u] %.*s\n", port_id, (int)len, (const char *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- main ---- */
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
dr_init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 创建端口,配置发送和接收能力。
|
||||||
|
* 一个端口可以同时有 send_type 和 recv_type。
|
||||||
|
*/
|
||||||
|
dr_port_t uart1 = dr_port_create();
|
||||||
|
dr_port_set_send_type(uart1, DR_SEND_sensor);
|
||||||
|
dr_port_set_recv_type(uart1, DR_RECV_rtcm);
|
||||||
|
dr_port_add_handler(uart1, uart_write);
|
||||||
|
dr_port_add_handler(uart1, tcp_write);
|
||||||
|
|
||||||
|
dr_port_t uart2 = dr_port_create();
|
||||||
|
dr_port_set_send_type(uart2, DR_SEND_status);
|
||||||
|
dr_port_set_recv_type(uart2, DR_RECV_command);
|
||||||
|
dr_port_add_handler(uart2, uart_write);
|
||||||
|
|
||||||
|
/* ---- 发送 ---- */
|
||||||
|
printf("--- send sensor (auto-route to uart1) ---\n");
|
||||||
|
dr_send_sensor("temperature:25.3", 16);
|
||||||
|
|
||||||
|
printf("\n--- send status (auto-route to uart2) ---\n");
|
||||||
|
dr_send_status("status:OK", 9);
|
||||||
|
|
||||||
|
/* ---- 接收(模拟外设中断) ---- */
|
||||||
|
printf("\n--- UART1 received data → dispatch to rtcm ---\n");
|
||||||
|
dr_port_dispatch(uart1, "rtcm_data_v3.2", 14);
|
||||||
|
|
||||||
|
printf("\n--- UART2 received data → dispatch to command ---\n");
|
||||||
|
dr_port_dispatch(uart2, "reboot", 6);
|
||||||
|
|
||||||
|
/* 清理 */
|
||||||
|
dr_port_delete(uart1);
|
||||||
|
dr_port_delete(uart2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#include "library.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void hello(void) {
|
|
||||||
printf("Hello, World!\n");
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#ifndef DATAROUTER_LIBRARY_H
|
|
||||||
#define DATAROUTER_LIBRARY_H
|
|
||||||
|
|
||||||
void hello(void);
|
|
||||||
|
|
||||||
#endif // DATAROUTER_LIBRARY_H
|
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
/**
|
||||||
|
* @file test_datarouter.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "datarouter.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 框架
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
static int _total_run, _total_pass, _total_fail;
|
||||||
|
static int _err;
|
||||||
|
static const char *_cur_name;
|
||||||
|
|
||||||
|
#define FIXTURE_MAX 16
|
||||||
|
typedef struct {
|
||||||
|
dr_port_t ports[FIXTURE_MAX];
|
||||||
|
int count;
|
||||||
|
} fixture_t;
|
||||||
|
|
||||||
|
#define FIXTURE_INIT(f) memset((f), 0, sizeof(*(f)))
|
||||||
|
#define FIXTURE_PUSH(f, p) do { if ((f)->count < FIXTURE_MAX) (f)->ports[(f)->count++] = (p); } while (0)
|
||||||
|
#define FIXTURE_CLEAN(f) do { for (int _i = 0; _i < (f)->count; _i++) dr_port_delete((f)->ports[_i]); } while (0)
|
||||||
|
#define FIXTURE_CREATE(f) ({ dr_port_t _p = dr_port_create(); FIXTURE_PUSH(f, _p); _p; })
|
||||||
|
|
||||||
|
#define TEST_START(name) \
|
||||||
|
static void test_##name(void) \
|
||||||
|
{ \
|
||||||
|
fixture_t _fix; \
|
||||||
|
FIXTURE_INIT(&_fix); \
|
||||||
|
_cur_name = #name; \
|
||||||
|
_err = 0;
|
||||||
|
|
||||||
|
#define TEST_END() \
|
||||||
|
cleanup: \
|
||||||
|
FIXTURE_CLEAN(&_fix); \
|
||||||
|
if (_err) { _total_fail++; printf(" FAIL %s\n", _cur_name); } \
|
||||||
|
else { _total_pass++; printf(" PASS %s\n", _cur_name); } \
|
||||||
|
_total_run++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK(cond, ...) do { \
|
||||||
|
if (!(cond)) { \
|
||||||
|
printf(" %s [line %d]: ", _cur_name, __LINE__); \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
printf("\n"); \
|
||||||
|
_err = 1; \
|
||||||
|
goto cleanup; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 测试用 handler / 回调
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
static int _h_cnt;
|
||||||
|
static void _h(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; }
|
||||||
|
static void reset_h(void) { _h_cnt = 0; }
|
||||||
|
|
||||||
|
static int _rx_rtcm;
|
||||||
|
static int _rx_cmd;
|
||||||
|
void dr_on_recv_rtcm(uint32_t p, const void *d, size_t l)
|
||||||
|
{ (void)p; (void)d; (void)l; _rx_rtcm++; }
|
||||||
|
void dr_on_recv_command(uint32_t p, const void *d, size_t l)
|
||||||
|
{ (void)p; (void)d; (void)l; _rx_cmd++; }
|
||||||
|
static void reset_rx(void) { _rx_rtcm = _rx_cmd = 0; }
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 1. 未初始化
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
TEST_START(error_uninit)
|
||||||
|
CHECK(dr_send_sensor("d", 1) == -1, "expected -1");
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 2. 端口管理
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
TEST_START(port_create_basic)
|
||||||
|
CHECK(FIXTURE_CREATE(&_fix) >= 0, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(port_create_max)
|
||||||
|
int c = 0;
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
dr_port_t p = dr_port_create();
|
||||||
|
if (p == DR_INVALID_PORT) break;
|
||||||
|
FIXTURE_PUSH(&_fix, p); c++;
|
||||||
|
}
|
||||||
|
CHECK(c >= 64, "got %d", c);
|
||||||
|
CHECK(dr_port_create() == DR_INVALID_PORT, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(port_delete_invalid)
|
||||||
|
dr_port_delete(-1); dr_port_delete(999);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(port_default_state)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
CHECK(dr_port_get_send_type(p) == -1, NULL);
|
||||||
|
CHECK(dr_port_get_recv_type(p) == -1, NULL);
|
||||||
|
CHECK(dr_port_handler_count(p) == 0, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 3. send_type / recv_type 与 handler
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
TEST_START(send_type_set_clear)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p, DR_SEND_sensor);
|
||||||
|
CHECK(dr_port_get_send_type(p) == DR_SEND_sensor, NULL);
|
||||||
|
dr_port_set_send_type(p, -1);
|
||||||
|
CHECK(dr_port_get_send_type(p) == -1, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(recv_type_set_clear)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_recv_type(p, DR_RECV_rtcm);
|
||||||
|
CHECK(dr_port_get_recv_type(p) == DR_RECV_rtcm, NULL);
|
||||||
|
dr_port_set_recv_type(p, -1);
|
||||||
|
CHECK(dr_port_get_recv_type(p) == -1, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(types_independent)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p, DR_SEND_sensor);
|
||||||
|
dr_port_set_recv_type(p, DR_RECV_command);
|
||||||
|
CHECK(dr_port_get_send_type(p) == DR_SEND_sensor, NULL);
|
||||||
|
CHECK(dr_port_get_recv_type(p) == DR_RECV_command, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(handler_add_remove)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
CHECK(dr_port_add_handler(p, _h) == 0, NULL);
|
||||||
|
CHECK(dr_port_handler_count(p) == 1, NULL);
|
||||||
|
CHECK(dr_port_remove_handler(p, _h) == 0, NULL);
|
||||||
|
CHECK(dr_port_handler_count(p) == 0, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 4. 发送 — 自动广播
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
TEST_START(send_no_match_port)
|
||||||
|
CHECK(dr_send_sensor("d", 1) == -2, "expected -2");
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(send_one_port_one_handler)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p, DR_SEND_sensor);
|
||||||
|
dr_port_add_handler(p, _h);
|
||||||
|
reset_h();
|
||||||
|
CHECK(dr_send_sensor("d", 1) == 0, NULL);
|
||||||
|
CHECK(_h_cnt == 1, "cnt=%d", _h_cnt);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(send_multi_ports)
|
||||||
|
dr_port_t p1 = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_t p2 = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p1, DR_SEND_sensor);
|
||||||
|
dr_port_set_send_type(p2, DR_SEND_sensor);
|
||||||
|
dr_port_add_handler(p1, _h);
|
||||||
|
dr_port_add_handler(p2, _h);
|
||||||
|
reset_h();
|
||||||
|
CHECK(dr_send_sensor("d", 1) == 0, NULL);
|
||||||
|
CHECK(_h_cnt == 2, "cnt=%d", _h_cnt);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(send_type_filter)
|
||||||
|
dr_port_t p1 = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_t p2 = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p1, DR_SEND_sensor);
|
||||||
|
dr_port_set_send_type(p2, DR_SEND_status);
|
||||||
|
dr_port_add_handler(p1, _h);
|
||||||
|
dr_port_add_handler(p2, _h);
|
||||||
|
reset_h();
|
||||||
|
CHECK(dr_send_sensor("d", 1) == 0, NULL);
|
||||||
|
CHECK(_h_cnt == 1, "cnt=%d", _h_cnt);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(send_after_delete)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p, DR_SEND_sensor);
|
||||||
|
dr_port_add_handler(p, _h);
|
||||||
|
dr_port_delete(p);
|
||||||
|
CHECK(dr_send_sensor("d", 1) == -2, "expected -2");
|
||||||
|
_fix.count--;
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(send_zero_length)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p, DR_SEND_sensor);
|
||||||
|
dr_port_add_handler(p, _h);
|
||||||
|
reset_h();
|
||||||
|
CHECK(dr_send_sensor("x", 0) == 0, NULL);
|
||||||
|
CHECK(_h_cnt == 1, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(send_null_data)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_send_type(p, DR_SEND_sensor);
|
||||||
|
dr_port_add_handler(p, _h);
|
||||||
|
reset_h();
|
||||||
|
CHECK(dr_send_sensor(NULL, 0) == 0, NULL);
|
||||||
|
CHECK(_h_cnt == 1, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 5. 接收回调 + dispatch
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
TEST_START(recv_callback_direct)
|
||||||
|
/* 直接调用回调(旧方式) */
|
||||||
|
reset_rx();
|
||||||
|
dr_on_recv_rtcm(0, "d", 1);
|
||||||
|
CHECK(_rx_rtcm == 1, "rtcm=%d", _rx_rtcm);
|
||||||
|
dr_on_recv_command(1, "d", 1);
|
||||||
|
CHECK(_rx_cmd == 1, "cmd=%d", _rx_cmd);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(dispatch_valid)
|
||||||
|
/* dr_port_dispatch 自动路由到对应回调 */
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_recv_type(p, DR_RECV_rtcm);
|
||||||
|
|
||||||
|
reset_rx();
|
||||||
|
dr_port_dispatch(p, "data", 4);
|
||||||
|
CHECK(_rx_rtcm == 1, "rtcm should fire: %d", _rx_rtcm);
|
||||||
|
CHECK(_rx_cmd == 0, "cmd should not fire: %d", _rx_cmd);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(dispatch_command)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_recv_type(p, DR_RECV_command);
|
||||||
|
|
||||||
|
reset_rx();
|
||||||
|
dr_port_dispatch(p, "data", 4);
|
||||||
|
CHECK(_rx_cmd == 1, "cmd should fire: %d", _rx_cmd);
|
||||||
|
CHECK(_rx_rtcm == 0, "rtcm should not fire: %d", _rx_rtcm);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(dispatch_unset)
|
||||||
|
/* recv_type 为 -1 时 dispatch 不应调用任何回调 */
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
reset_rx();
|
||||||
|
dr_port_dispatch(p, "data", 4);
|
||||||
|
CHECK(_rx_rtcm == 0, NULL);
|
||||||
|
CHECK(_rx_cmd == 0, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(dispatch_invalid_port)
|
||||||
|
reset_rx();
|
||||||
|
dr_port_dispatch(999, "data", 4);
|
||||||
|
dr_port_dispatch(-1, "data", 4);
|
||||||
|
CHECK(_rx_rtcm == 0, NULL);
|
||||||
|
CHECK(_rx_cmd == 0, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(dispatch_deleted_port)
|
||||||
|
dr_port_t p = FIXTURE_CREATE(&_fix);
|
||||||
|
dr_port_set_recv_type(p, DR_RECV_rtcm);
|
||||||
|
dr_port_delete(p);
|
||||||
|
reset_rx();
|
||||||
|
dr_port_dispatch(p, "data", 4);
|
||||||
|
CHECK(_rx_rtcm == 0, "deleted should not fire");
|
||||||
|
_fix.count--;
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 6. 能力元数据
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
TEST_START(send_cap_meta)
|
||||||
|
CHECK(dr_send_cap_count() == 2, NULL);
|
||||||
|
CHECK(strcmp(dr_send_cap_name(0), "sensor") == 0, NULL);
|
||||||
|
CHECK(dr_send_cap_name(-1) == NULL, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
TEST_START(recv_cap_meta)
|
||||||
|
CHECK(dr_recv_cap_count() == 2, NULL);
|
||||||
|
CHECK(strcmp(dr_recv_cap_name(0), "rtcm") == 0, NULL);
|
||||||
|
CHECK(dr_recv_cap_name(-1) == NULL, NULL);
|
||||||
|
TEST_END()
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* 主函数
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
#define RUN(name) do { reset_h(); reset_rx(); test_##name(); } while (0)
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("==== DataRouter Unit Tests ====\n\n");
|
||||||
|
|
||||||
|
printf("[uninitialized]\n");
|
||||||
|
RUN(error_uninit);
|
||||||
|
|
||||||
|
dr_init();
|
||||||
|
|
||||||
|
printf("\n[port management]\n");
|
||||||
|
RUN(port_create_basic);
|
||||||
|
RUN(port_create_max);
|
||||||
|
RUN(port_delete_invalid);
|
||||||
|
RUN(port_default_state);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
dr_reset(); dr_init();
|
||||||
|
printf("[send_type / recv_type / handler]\n");
|
||||||
|
RUN(send_type_set_clear);
|
||||||
|
RUN(recv_type_set_clear);
|
||||||
|
RUN(types_independent);
|
||||||
|
RUN(handler_add_remove);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("[send — auto broadcast]\n");
|
||||||
|
RUN(send_no_match_port);
|
||||||
|
RUN(send_one_port_one_handler);
|
||||||
|
RUN(send_multi_ports);
|
||||||
|
RUN(send_type_filter);
|
||||||
|
RUN(send_after_delete);
|
||||||
|
RUN(send_zero_length);
|
||||||
|
RUN(send_null_data);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("[receive — dispatch]\n");
|
||||||
|
RUN(recv_callback_direct);
|
||||||
|
RUN(dispatch_valid);
|
||||||
|
RUN(dispatch_command);
|
||||||
|
RUN(dispatch_unset);
|
||||||
|
RUN(dispatch_invalid_port);
|
||||||
|
RUN(dispatch_deleted_port);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("[capability metadata]\n");
|
||||||
|
RUN(send_cap_meta);
|
||||||
|
RUN(recv_cap_meta);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("==============================\n");
|
||||||
|
printf(" total: %d | pass: %d | fail: %d\n\n",
|
||||||
|
_total_run, _total_pass, _total_fail);
|
||||||
|
return _total_fail > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user