mirror of
https://github.com/linux-can/can-utils.git
synced 2026-09-23 08:31:09 +02:00
Compare commits
159
Commits
277048eba6
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbbad5eede | ||
|
|
95aae6bf83 | ||
|
|
bf5fe736c3 | ||
|
|
14245b7c79 | ||
|
|
90383a0cca | ||
|
|
d5cb91c8ea | ||
|
|
9743a2ffcf | ||
|
|
d5ed23583c | ||
|
|
60301896d1 | ||
|
|
99ab67143a | ||
|
|
a0aeaed234 | ||
|
|
3cae8a449b | ||
|
|
44e6eb45e3 | ||
|
|
9e444073b1 | ||
|
|
9d4f3c82a2 | ||
|
|
7e8e247b2f | ||
|
|
3fe1c42bbf | ||
|
|
1520ab5b98 | ||
|
|
aa902ae2af | ||
|
|
a0b592178e | ||
|
|
4f2fdecfba | ||
|
|
cbbe4b41ea | ||
|
|
2da0c7e95e | ||
|
|
1f038b3cd8 | ||
|
|
392ccc970b | ||
|
|
7939678070 | ||
|
|
88a0417a6b | ||
|
|
65e715d56d | ||
|
|
374fecde09 | ||
|
|
bfbf0c851f | ||
|
|
ed7822c9a2 | ||
|
|
e9ea9d1168 | ||
|
|
2d793d38d2 | ||
|
|
340a3b8c92 | ||
|
|
8838ce80fc | ||
|
|
d6c57240ed | ||
|
|
3e0e6ae3a4 | ||
|
|
8bf5f8873f | ||
|
|
0094905376 | ||
|
|
987bc8aac2 | ||
|
|
6b46063eee | ||
|
|
93a7b2dfd3 | ||
|
|
af09afb734 | ||
|
|
69efecc428 | ||
|
|
3698814740 | ||
|
|
6ed0f0ea7f | ||
|
|
287469245c | ||
|
|
7a318636e7 | ||
|
|
7fb81e6779 | ||
|
|
a904183b4e | ||
|
|
e2172546aa | ||
|
|
705b3202a9 | ||
|
|
31a59be02f | ||
|
|
4d908bd7cf | ||
|
|
837e2bb343 | ||
|
|
ec16ef97ff | ||
|
|
651c8818dd | ||
|
|
130e0dced2 | ||
|
|
ff90f4ec21 | ||
|
|
e3ee283443 | ||
|
|
e8130a3575 | ||
|
|
1250c12a30 | ||
|
|
9b5b030877 | ||
|
|
da3914c491 | ||
|
|
18b1e7970a | ||
|
|
491cabea07 | ||
|
|
f1cea504a4 | ||
|
|
900c7e9f6e | ||
|
|
b208876e65 | ||
|
|
72a9fd8ccd | ||
|
|
e448d542e8 | ||
|
|
71b2aec834 | ||
|
|
a24bff8b08 | ||
|
|
fe9ea67814 | ||
|
|
e8559479fb | ||
|
|
6050aa155d | ||
|
|
302184f383 | ||
|
|
c542c9ada7 | ||
|
|
2b8c7c5f4b | ||
|
|
4577316bd6 | ||
|
|
4364d655b8 | ||
|
|
2e71e396c5 | ||
|
|
01083a64eb | ||
|
|
008f9f8e22 | ||
|
|
66e7c08beb | ||
|
|
4b66e8c56f | ||
|
|
e6e3253972 | ||
|
|
6d69bef837 | ||
|
|
4d8b247258 | ||
|
|
0e9c53f6d3 | ||
|
|
99c5c14790 | ||
|
|
df8e08fa70 | ||
|
|
cb5ab07f34 | ||
|
|
0e692bf42e | ||
|
|
0984817438 | ||
|
|
b3da2f62b9 | ||
|
|
b85418d75c | ||
|
|
6eb97b57c5 | ||
|
|
fc1f6979c0 | ||
|
|
24e0c520b6 | ||
|
|
06561ac3dc | ||
|
|
7093a73185 | ||
|
|
72f236e3ac | ||
|
|
3bbc8075eb | ||
|
|
6526683a10 | ||
|
|
dced0a6ec7 | ||
|
|
6c36d44c83 | ||
|
|
7260844b73 | ||
|
|
be1fc77311 | ||
|
|
fc2473424e | ||
|
|
724e6f7c11 | ||
|
|
7665e1e236 | ||
|
|
b592ec5b1f | ||
|
|
30b6b04053 | ||
|
|
367e0df4aa | ||
|
|
8a156fee19 | ||
|
|
a63bf468c2 | ||
|
|
d337863d91 | ||
|
|
95fe6522c6 | ||
|
|
fe514eedf8 | ||
|
|
4eb72fd39a | ||
|
|
51b1f67851 | ||
|
|
847486083a | ||
|
|
f6db81da68 | ||
|
|
15dbb474c7 | ||
|
|
4b86049167 | ||
|
|
cf0091c90c | ||
|
|
d0b04bd456 | ||
|
|
af95ee0c6d | ||
|
|
69c1e8289d | ||
|
|
72d097b2f9 | ||
|
|
97bfb2960a | ||
|
|
8fdd8f9a5a | ||
|
|
4597b054e2 | ||
|
|
bc88e89caf | ||
|
|
db2fe6a605 | ||
|
|
bfcf548f97 | ||
|
|
1405a90e8b | ||
|
|
e0bb44c908 | ||
|
|
c468568f1e | ||
|
|
8012b3b23d | ||
|
|
a7ff280c62 | ||
|
|
c98e25334b | ||
|
|
c2e40edd24 | ||
|
|
f12a59d780 | ||
|
|
fbd097edf6 | ||
|
|
465ee7c203 | ||
|
|
800c48fb1e | ||
|
|
e865e54490 | ||
|
|
4d16dc867d | ||
|
|
6c893e5c4f | ||
|
|
7b6daa3aca | ||
|
|
0e4c2d35f2 | ||
|
|
3b5593f499 | ||
|
|
2a93b10057 | ||
|
|
b76bb3f66c | ||
|
|
06ab86226a | ||
|
|
fc742c574e | ||
|
|
1e8bc8fd34 |
@@ -0,0 +1,16 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[{CMakeLists.txt,*.cmake}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
|
||||
[{*.c,*.h}]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
tab_width = 8
|
||||
@@ -1,19 +0,0 @@
|
||||
name: C with autotools
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: autogen
|
||||
run: ./autogen.sh
|
||||
- name: configure
|
||||
run: ./configure
|
||||
- name: make
|
||||
run: make
|
||||
- name: make distcheck
|
||||
run: make distcheck
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -67,4 +67,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
name: native and cross
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
release:
|
||||
- "ubuntu:20.04"
|
||||
- "ubuntu:22.04"
|
||||
- "ubuntu:24.04"
|
||||
- "ubuntu:rolling"
|
||||
- "debian:oldstable-slim"
|
||||
- "debian:stable-slim"
|
||||
- "debian:testing-slim"
|
||||
- "debian:unstable-slim"
|
||||
- "debian:experimental"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare ${{ matrix.release }} container
|
||||
env:
|
||||
release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }}
|
||||
run: |
|
||||
podman version
|
||||
podman run --name stable -di --userns=keep-id:uid=1000,gid=1000 -v "$PWD":/home -w /home ${{ matrix.release }} bash
|
||||
podman exec -i stable uname -a
|
||||
podman exec -i stable id
|
||||
|
||||
- name: Update APT Sources List (Ubuntu Only)
|
||||
if:
|
||||
startsWith(matrix.release, 'ubuntu:') && matrix.release != 'ubuntu:20.04'
|
||||
run: |
|
||||
podman exec -i -u root stable apt update
|
||||
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy \
|
||||
lsb-release
|
||||
|
||||
podman exec -i -u root stable \
|
||||
test -e /etc/apt/sources.list &&
|
||||
podman exec -i -u root stable \
|
||||
sed -i -e 's|\(http.*:\)|[arch=amd64] \1|g' /etc/apt/sources.list
|
||||
|
||||
podman exec -i -u root stable \
|
||||
test -e /etc/apt/sources.list.d/ubuntu.sources &&
|
||||
podman exec -i -u root stable \
|
||||
sed -i -e '/^Components:/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
|
||||
|
||||
echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs) main restricted universe multiverse" | \
|
||||
podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list
|
||||
echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs)-updates main restricted universe multiverse" | \
|
||||
podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list
|
||||
echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs)-backports main restricted universe multiverse" | \
|
||||
podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list
|
||||
|
||||
- name: Add Architecture
|
||||
if:
|
||||
matrix.release != 'ubuntu:20.04'
|
||||
run: |
|
||||
podman exec -i -u root stable dpkg --add-architecture arm64
|
||||
podman exec -i -u root stable dpkg --add-architecture armhf
|
||||
|
||||
- name: Install Development Packages
|
||||
env:
|
||||
release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }}
|
||||
run: |
|
||||
podman exec -i -u root stable apt update
|
||||
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt upgrade -o APT::Install-Suggests=false -qy
|
||||
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \
|
||||
clang \
|
||||
cmake \
|
||||
gcc \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
libgps-dev \
|
||||
make
|
||||
|
||||
- name: Install Cross Libs
|
||||
env:
|
||||
release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }}
|
||||
if:
|
||||
matrix.release != 'ubuntu:20.04'
|
||||
run: |
|
||||
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \
|
||||
libgps-dev:arm64 \
|
||||
libgps-dev:armhf
|
||||
|
||||
- name: Configure & Build with gcc
|
||||
env:
|
||||
cc: gcc
|
||||
run: |
|
||||
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -DENABLE_GPS=ON -B build-${cc}
|
||||
podman exec -i stable cmake --build build-${cc}
|
||||
|
||||
- name: Configure & Build with clang
|
||||
env:
|
||||
cc: clang
|
||||
run: |
|
||||
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -DENABLE_GPS=ON -B build-${cc}
|
||||
podman exec -i stable cmake --build build-${cc}
|
||||
|
||||
- name: Configure & Build with arm-linux-gnueabihf-gcc
|
||||
env:
|
||||
toolchain: arm-linux-gnueabihf-gcc
|
||||
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
|
||||
run: |
|
||||
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain}
|
||||
podman exec -i stable cmake --build build-${toolchain}
|
||||
|
||||
- name: Configure & Build with arm-linux-gnueabihf-clang
|
||||
if:
|
||||
matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim'
|
||||
env:
|
||||
toolchain: arm-linux-gnueabihf-clang
|
||||
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
|
||||
run: |
|
||||
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain}
|
||||
podman exec -i stable cmake --build build-${toolchain}
|
||||
|
||||
- name: Configure & Build with aarch64-linux-gnu-gcc
|
||||
env:
|
||||
toolchain: aarch64-linux-gnu-gcc
|
||||
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
|
||||
run: |
|
||||
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain}
|
||||
podman exec -i stable cmake --build build-${toolchain}
|
||||
|
||||
- name: Configure & Build with aarch64-linux-gnu-clang
|
||||
if:
|
||||
matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim'
|
||||
env:
|
||||
toolchain: aarch64-linux-gnu-clang
|
||||
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
|
||||
run: |
|
||||
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -DENABLE_GPS=${gps} -B build-${toolchain}
|
||||
podman exec -i stable cmake --build build-${toolchain}
|
||||
|
||||
- name: Configure & Build with gcc (Makefile)
|
||||
env:
|
||||
cc: gcc
|
||||
run: |
|
||||
podman exec -i stable make CC=${cc}
|
||||
podman exec -i stable make clean
|
||||
|
||||
- name: Configure & Build with clang (Makefile)
|
||||
env:
|
||||
cc: clang
|
||||
run: |
|
||||
podman exec -i stable make CC=${cc}
|
||||
podman exec -i stable make clean
|
||||
|
||||
- name: Show logs
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
for log in build-*/CMakeFiles/{CMakeOutput.log,CMakeConfigureLog.yaml}; do \
|
||||
if [ -e ${log} ]; then \
|
||||
echo "---------------- ${log} ----------------"; \
|
||||
cat ${log}; \
|
||||
fi; \
|
||||
done
|
||||
@@ -0,0 +1,15 @@
|
||||
name: NDK
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: CMake and NDK
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_WERROR=ON -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -B build
|
||||
cmake --build build
|
||||
+12
-26
@@ -1,36 +1,22 @@
|
||||
*~
|
||||
*.a
|
||||
*.so
|
||||
*.so.*
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
.ccls-cache
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
compile_commands.json
|
||||
|
||||
configure
|
||||
libtool
|
||||
GNUmakefile
|
||||
GNUmakefile.in
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/calc-bit-timing/.dirstamp
|
||||
/config.log
|
||||
/config.status
|
||||
/config/autoconf/
|
||||
/config/m4/libtool.m4
|
||||
/config/m4/ltoptions.m4
|
||||
/config/m4/ltsugar.m4
|
||||
/config/m4/ltversion.m4
|
||||
/config/m4/lt~obsolete.m4
|
||||
/isobusfs/.dirstamp
|
||||
/mcp251xfd/.dirstamp
|
||||
tags
|
||||
/build
|
||||
|
||||
/asc2log
|
||||
/bcmserver
|
||||
/can-calc-bit-timing
|
||||
/canbusload
|
||||
/candump
|
||||
/canerrsim
|
||||
/canfdtest
|
||||
/cangen
|
||||
/cangw
|
||||
@@ -52,6 +38,9 @@ GNUmakefile.in
|
||||
/j1939cat
|
||||
/j1939spy
|
||||
/j1939sr
|
||||
/j1939-timedate-cli
|
||||
/j1939-timedate-srv
|
||||
/j1939-vehicle-position-srv
|
||||
/log2asc
|
||||
/log2long
|
||||
/mcp251xfd-dump
|
||||
@@ -59,6 +48,3 @@ GNUmakefile.in
|
||||
/slcand
|
||||
/slcanpty
|
||||
/testj1939
|
||||
|
||||
/can-utils-*.tar.bz2
|
||||
/can-utils-*.tar.gz
|
||||
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
language: c
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# native
|
||||
|
||||
- env: test="x64 4.8.4 (make)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: make
|
||||
|
||||
- env: test="x64 4.8.4 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
|
||||
- env: test="x64 5.0 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
|
||||
- env: test="x64 4.8.4 (CMake gcc)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
before_script:
|
||||
- mkdir gcc_rel && cd gcc_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
|
||||
- env: test="x64 5.0 (CMake clang)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_rel && cd clang_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
|
||||
- env: test="x64 5.0 (CMake clang - Ninja) Debug"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
|
||||
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
|
||||
script: ninja
|
||||
|
||||
# ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (make)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (CMake gcc)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
before_script:
|
||||
- mkdir gcc_rel && cd gcc_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (CMake clang)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_rel && cd clang_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (CMake clang - Ninja) Debug"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
|
||||
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
|
||||
script: ninja
|
||||
arch: ppc64le
|
||||
|
||||
# Android
|
||||
|
||||
- env: test="Android NDK (CMake)"
|
||||
os: linux
|
||||
language: android
|
||||
android:
|
||||
components:
|
||||
- build-tools-25.0.2
|
||||
install:
|
||||
- echo y | sdkmanager "ndk-bundle"
|
||||
- echo y | sdkmanager "cmake;3.6.4111459"
|
||||
before_script:
|
||||
- export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
|
||||
- export ANDROID_CMAKE=$ANDROID_HOME/cmake/3.6.4111459/bin/cmake
|
||||
- export ANDROID_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake
|
||||
script:
|
||||
- pushd . && mkdir android15_armeabiv7a_rel && cd android15_armeabiv7a_rel
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android15_x86_rel && cd android15_x86_rel
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android21_arm64-v8a_rel && cd android21_arm64-v8a_rel
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android21_x86_64_rel && cd android21_x86_64_rel
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android15_armeabiv7a_dbg && cd android15_armeabiv7a_dbg
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android15_x86_dbg && cd android15_x86_dbg
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=x86 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android21_arm64-v8a_dbg && cd android21_arm64-v8a_dbg
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
- pushd . && mkdir android21_x86_64_dbg && cd android21_x86_64_dbg
|
||||
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
|
||||
- make && popd
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- autoconf
|
||||
- automake
|
||||
- libtool
|
||||
- m4
|
||||
- cmake
|
||||
- ninja-build
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
-498
@@ -1,498 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
PRIVATE_LOCAL_CFLAGS := -O2 -g -W -Wall \
|
||||
-Wno-error=unused-parameter \
|
||||
-DSO_RXQ_OVFL=40 \
|
||||
-DPF_CAN=29 \
|
||||
-DAF_CAN=PF_CAN
|
||||
|
||||
#
|
||||
# canlib
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := lib.c canframelen.c
|
||||
LOCAL_MODULE := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# j1939lib
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := libj1939.c
|
||||
LOCAL_MODULE := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# j1939acd
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939acd.c
|
||||
LOCAL_MODULE := j1939acd
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939cat
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939cat.c
|
||||
LOCAL_MODULE := j1939cat
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939spy
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939spy.c
|
||||
LOCAL_MODULE := j1939spy
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939sr
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939sr.c
|
||||
LOCAL_MODULE := j1939sr
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# testj1939
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := testj1939.c
|
||||
LOCAL_MODULE := testj1939
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# candump
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := candump.c
|
||||
LOCAL_MODULE := candump
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cansend
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cansend.c
|
||||
LOCAL_MODULE := cansend
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cansequence
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cansequence.c
|
||||
LOCAL_MODULE := cansequence
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# bcmserver
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := bcmserver.c
|
||||
LOCAL_MODULE := bcmserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# can-calc-bit-timing
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := calc-bit-timing/can-calc-bit-timing.c
|
||||
LOCAL_MODULE := can-calc-bit-timing
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# canbusload
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := canbusload.c
|
||||
LOCAL_MODULE := canbusload
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# canfdtest
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := canfdtest.c
|
||||
LOCAL_MODULE := canfdtest
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cangen
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cangen.c
|
||||
LOCAL_MODULE := cangen
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cangw
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cangw.c
|
||||
LOCAL_MODULE := cangw
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# canlogserver
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := canlogserver.c
|
||||
LOCAL_MODULE := canlogserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# canplayer
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := canplayer.c
|
||||
LOCAL_MODULE := canplayer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cansniffer
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cansniffer.c
|
||||
LOCAL_MODULE := cansniffer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotpdump
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpdump.c
|
||||
LOCAL_MODULE := isotpdump
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotprecv
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotprecv.c
|
||||
LOCAL_MODULE := isotprecv
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotpsend
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpsend.c
|
||||
LOCAL_MODULE := isotpsend
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotpserver
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpserver.c
|
||||
LOCAL_MODULE := isotpserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotpsniffer
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpsniffer.c
|
||||
LOCAL_MODULE := isotpsniffer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotptun
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotptun.c
|
||||
LOCAL_MODULE := isotptun
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# isotpperf
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpperf.c
|
||||
LOCAL_MODULE := isotpperf
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# log2asc
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := log2asc.c
|
||||
LOCAL_MODULE := log2asc
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# asc2log
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := asc2log.c
|
||||
LOCAL_MODULE := asc2log
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# log2long
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := log2long.c
|
||||
LOCAL_MODULE := log2long
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# slcan_attach
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := slcan_attach.c
|
||||
LOCAL_MODULE := slcan_attach
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# slcand
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := slcand.c
|
||||
LOCAL_MODULE := slcand
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# slcanpty
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := lib.c slcanpty.c
|
||||
LOCAL_MODULE := slcanpty
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
+175
-81
@@ -1,18 +1,57 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
cmake_minimum_required(VERSION 3.5...3.10)
|
||||
|
||||
project(can-utils LANGUAGES C)
|
||||
|
||||
include (CheckFunctionExists)
|
||||
include (CheckSymbolExists)
|
||||
include (GNUInstallDirs)
|
||||
message(STATUS "CMake version: ${CMAKE_VERSION}")
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
if(CMAKE_EXPORT_COMPILE_COMMANDS STREQUAL "")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "project default" FORCE)
|
||||
endif()
|
||||
|
||||
# Add an option to enable treating warnings as errors
|
||||
option(ENABLE_WERROR "Treat all compiler warnings as errors" OFF)
|
||||
option(ENABLE_GPS "Enable GPS support" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
|
||||
# Options for controlling targets. These groups correspond to the README.
|
||||
option(ENABLE_BASIC_TOOLS "Build basic tools" ON)
|
||||
option(ENABLE_IP_SERVER "Build tools providing CAN access via IP sockets" ON)
|
||||
option(ENABLE_GATEWAY "Build in-kernel gateway configuration tools" ON)
|
||||
option(ENABLE_MEASUREMENT "Build measurement tools" ON)
|
||||
option(ENABLE_ISOTP "Build isotp tools" ON)
|
||||
option(ENABLE_LOG_FILE "Build log file converter tools" ON)
|
||||
option(ENABLE_SLCAN "Build slcan tools" ON)
|
||||
option(ENABLE_MCP251XFD "Build MCP251XFD tools" ON)
|
||||
|
||||
# cmake_dependent_option is only available in CMake 3.22 and later.
|
||||
if(ANDROID)
|
||||
set(ENABLE_J1939 OFF)
|
||||
set(ENABLE_ISOBUSFS OFF)
|
||||
else()
|
||||
option(ENABLE_J1939 "Build J1939 tools" ON)
|
||||
option(ENABLE_ISOBUSFS "Build ISOBUS tools" ON)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
if(ENABLE_GPS)
|
||||
pkg_check_modules(GPS REQUIRED libgps)
|
||||
endif()
|
||||
|
||||
if(ENABLE_WERROR)
|
||||
add_compile_options(-Werror)
|
||||
endif()
|
||||
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses -Wsign-compare")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_RXQ_OVFL=40")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29")
|
||||
@@ -23,93 +62,116 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCLOCK_TAI=11")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_TXTIME=61")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TXTIME=SO_TXTIME")
|
||||
|
||||
include_directories (.)
|
||||
include_directories (./include)
|
||||
include_directories(.)
|
||||
include_directories(./include)
|
||||
|
||||
check_function_exists(fork HAVE_FORK)
|
||||
|
||||
set(PROGRAMS_CANLIB
|
||||
asc2log
|
||||
canbusload
|
||||
# List of all programs to be built.
|
||||
# Each program is expected to have a corresponding source file with the same name.
|
||||
set(PROGRAMS)
|
||||
# List of programs to link against can.
|
||||
set(PROGRAMS_CANLIB)
|
||||
# List of programs to link against j1939 and can.
|
||||
set(PROGRAMS_J1939)
|
||||
|
||||
if(ENABLE_BASIC_TOOLS)
|
||||
list(APPEND PROGRAMS cansniffer)
|
||||
list(APPEND PROGRAMS_CANLIB
|
||||
candump
|
||||
cangen
|
||||
canplayer
|
||||
cansend
|
||||
cangen
|
||||
cansequence
|
||||
log2asc
|
||||
log2long
|
||||
slcanpty
|
||||
)
|
||||
|
||||
if(HAVE_FORK)
|
||||
list(APPEND PROGRAMS_CANLIB canlogserver)
|
||||
)
|
||||
endif()
|
||||
|
||||
set(PROGRAMS_J1939
|
||||
j1939acd
|
||||
j1939cat
|
||||
j1939spy
|
||||
j1939sr
|
||||
testj1939
|
||||
)
|
||||
if(ENABLE_IP_SERVER AND HAVE_FORK)
|
||||
list(APPEND PROGRAMS bcmserver)
|
||||
list(APPEND PROGRAMS_CANLIB canlogserver)
|
||||
endif()
|
||||
|
||||
set(PROGRAMS_ISOBUSFS
|
||||
isobusfs-srv
|
||||
isobusfs-cli
|
||||
)
|
||||
if(ENABLE_GATEWAY)
|
||||
list(APPEND PROGRAMS cangw)
|
||||
endif()
|
||||
|
||||
set(PROGRAMS
|
||||
${PROGRAMS_CANLIB}
|
||||
if(ENABLE_MEASUREMENT)
|
||||
list(APPEND PROGRAMS
|
||||
canfdtest
|
||||
cangw
|
||||
cansniffer
|
||||
canerrsim
|
||||
)
|
||||
list(APPEND PROGRAMS_CANLIB canbusload)
|
||||
|
||||
add_executable(can-calc-bit-timing
|
||||
calc-bit-timing/can-calc-bit-timing.c
|
||||
)
|
||||
install(TARGETS can-calc-bit-timing DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
if(ENABLE_ISOTP)
|
||||
list(APPEND PROGRAMS
|
||||
isotpdump
|
||||
isotpperf
|
||||
isotprecv
|
||||
isotpsend
|
||||
isotpsniffer
|
||||
isotptun
|
||||
slcan_attach
|
||||
slcand
|
||||
)
|
||||
|
||||
if(HAVE_FORK)
|
||||
list(APPEND PROGRAMS bcmserver)
|
||||
list(APPEND PROGRAMS isotpserver)
|
||||
endif()
|
||||
|
||||
add_executable(can-calc-bit-timing
|
||||
calc-bit-timing/can-calc-bit-timing.c
|
||||
)
|
||||
|
||||
add_executable(mcp251xfd-dump
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c
|
||||
mcp251xfd/mcp251xfd-dump.c
|
||||
mcp251xfd/mcp251xfd-main.c
|
||||
mcp251xfd/mcp251xfd-regmap.c
|
||||
)
|
||||
|
||||
if(NOT ANDROID)
|
||||
list(APPEND PROGRAMS ${PROGRAMS_J1939})
|
||||
|
||||
add_library(j1939 STATIC
|
||||
libj1939.c
|
||||
)
|
||||
|
||||
add_library(isobusfs SHARED
|
||||
if(HAVE_FORK)
|
||||
list(APPEND PROGRAMS isotpserver)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_J1939)
|
||||
list(APPEND PROGRAMS_J1939
|
||||
j1939acd
|
||||
j1939cat
|
||||
j1939spy
|
||||
j1939sr
|
||||
testj1939
|
||||
)
|
||||
|
||||
add_executable(j1939-timedate-cli
|
||||
j1939_timedate/j1939_timedate_cli.c
|
||||
)
|
||||
target_link_libraries(j1939-timedate-cli
|
||||
PRIVATE can j1939
|
||||
)
|
||||
install(TARGETS j1939-timedate-cli DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
add_executable(j1939-timedate-srv
|
||||
j1939_timedate/j1939_timedate_srv.c
|
||||
)
|
||||
target_link_libraries(j1939-timedate-srv
|
||||
PRIVATE can j1939
|
||||
)
|
||||
install(TARGETS j1939-timedate-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
if(ENABLE_J1939 AND ENABLE_GPS)
|
||||
add_executable(j1939-vehicle-position-srv
|
||||
j1939_vehicle_position/j1939_vehicle_position_srv.c
|
||||
)
|
||||
target_link_libraries(j1939-vehicle-position-srv
|
||||
PRIVATE can j1939 ${GPS_LIBRARIES}
|
||||
)
|
||||
install(TARGETS j1939-vehicle-position-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
if(ENABLE_ISOBUSFS)
|
||||
add_library(isobusfs EXCLUDE_FROM_ALL
|
||||
isobusfs/isobusfs_cmn.c
|
||||
isobusfs/isobusfs_cmn_dh.c
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADER_ISOBUSFS
|
||||
isobusfs/isobusfs_cmn.h
|
||||
isobusfs/isobusfs_cmn_cm.h
|
||||
)
|
||||
|
||||
set_target_properties(isobusfs PROPERTIES
|
||||
PUBLIC_HEADER "${PUBLIC_HEADER_ISOBUSFS}"
|
||||
SOVERSION 0
|
||||
)
|
||||
|
||||
install(TARGETS isobusfs
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
@@ -123,11 +185,10 @@ if(NOT ANDROID)
|
||||
isobusfs/isobusfs_cli_selftests.c
|
||||
isobusfs/isobusfs_cli_int.c
|
||||
)
|
||||
|
||||
target_link_libraries(isobusfs-cli
|
||||
PRIVATE isobusfs
|
||||
PRIVATE can
|
||||
PRIVATE isobusfs can j1939
|
||||
)
|
||||
install(TARGETS isobusfs-cli DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
add_executable(isobusfs-srv
|
||||
isobusfs/isobusfs_srv.c
|
||||
@@ -138,21 +199,53 @@ if(NOT ANDROID)
|
||||
isobusfs/isobusfs_srv_fh.c
|
||||
isobusfs/isobusfs_srv_vh.c
|
||||
)
|
||||
|
||||
target_link_libraries(isobusfs-srv
|
||||
PRIVATE isobusfs
|
||||
PRIVATE can
|
||||
PRIVATE isobusfs can j1939
|
||||
)
|
||||
|
||||
install(TARGETS
|
||||
isobusfs-cli
|
||||
isobusfs-srv
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS isobusfs-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
add_library(can STATIC
|
||||
lib.c
|
||||
canframelen.c
|
||||
if(ENABLE_LOG_FILE)
|
||||
list(APPEND PROGRAMS_CANLIB
|
||||
asc2log
|
||||
log2asc
|
||||
log2long
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SLCAN)
|
||||
list(APPEND PROGRAMS
|
||||
slcan_attach
|
||||
slcand
|
||||
)
|
||||
list(APPEND PROGRAMS_CANLIB slcanpty)
|
||||
endif()
|
||||
|
||||
if(ENABLE_MCP251XFD)
|
||||
add_executable(mcp251xfd-dump
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c
|
||||
mcp251xfd/mcp251xfd-dump.c
|
||||
mcp251xfd/mcp251xfd-main.c
|
||||
mcp251xfd/mcp251xfd-regmap.c
|
||||
)
|
||||
install(TARGETS mcp251xfd-dump DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
list(APPEND PROGRAMS
|
||||
${PROGRAMS_CANLIB}
|
||||
${PROGRAMS_J1939}
|
||||
)
|
||||
|
||||
add_library(can STATIC EXCLUDE_FROM_ALL
|
||||
lib.c
|
||||
canframelen.c
|
||||
)
|
||||
|
||||
add_library(j1939 STATIC EXCLUDE_FROM_ALL
|
||||
libj1939.c
|
||||
)
|
||||
target_link_libraries(j1939
|
||||
PRIVATE can
|
||||
)
|
||||
|
||||
foreach(name ${PROGRAMS})
|
||||
@@ -160,17 +253,18 @@ foreach(name ${PROGRAMS})
|
||||
|
||||
if("${name}" IN_LIST PROGRAMS_J1939)
|
||||
target_link_libraries(${name}
|
||||
PRIVATE j1939
|
||||
PRIVATE j1939 can
|
||||
)
|
||||
elseif("${name}" IN_LIST PROGRAMS_CANLIB)
|
||||
target_link_libraries(${name}
|
||||
PRIVATE can
|
||||
PRIVATE can
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endforeach()
|
||||
|
||||
install(TARGETS can-calc-bit-timing mcp251xfd-dump DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake")
|
||||
add_custom_target(uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake"
|
||||
COMMENT "Add uninstall target"
|
||||
)
|
||||
|
||||
-198
@@ -1,198 +0,0 @@
|
||||
ACLOCAL_AMFLAGS = -I config/m4
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir)/include \
|
||||
$(linux_CFLAGS)
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
# link every app against libcan, it's static so it wouldn't hurt
|
||||
LDADD = \
|
||||
libcan.la
|
||||
|
||||
noinst_HEADERS = \
|
||||
canframelen.h \
|
||||
isobusfs/isobusfs_cli.h \
|
||||
isobusfs/isobusfs_cmn.h \
|
||||
isobusfs/isobusfs_cmn_cm.h \
|
||||
isobusfs/isobusfs_cmn_dh.h \
|
||||
isobusfs/isobusfs_cmn_fa.h \
|
||||
isobusfs/isobusfs_cmn_fh.h \
|
||||
isobusfs/isobusfs_cmn_va.h \
|
||||
isobusfs/isobusfs_srv.h \
|
||||
lib.h \
|
||||
libj1939.h \
|
||||
terminal.h \
|
||||
include/linux/can.h \
|
||||
include/linux/can/bcm.h \
|
||||
include/linux/can/error.h \
|
||||
include/linux/can/gw.h \
|
||||
include/linux/can/isotp.h \
|
||||
include/linux/can/j1939.h \
|
||||
include/linux/can/netlink.h \
|
||||
include/linux/can/raw.h \
|
||||
include/linux/can/vxcan.h \
|
||||
include/linux/errqueue.h \
|
||||
include/linux/kernel.h \
|
||||
include/linux/net_tstamp.h \
|
||||
include/linux/netlink.h
|
||||
|
||||
noinst_LTLIBRARIES = \
|
||||
libcan.la \
|
||||
libj1939.la
|
||||
|
||||
libcan_la_SOURCES = \
|
||||
lib.c \
|
||||
canframelen.c
|
||||
|
||||
libj1939_la_SOURCES = \
|
||||
libj1939.c
|
||||
|
||||
can_calc_bit_timing_SOURCES = \
|
||||
calc-bit-timing/can-calc-bit-timing.c \
|
||||
calc-bit-timing/compat.h
|
||||
|
||||
EXTRA_DIST += \
|
||||
calc-bit-timing/can-calc-bit-timing-v2_6_31.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v3_18.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v4_8.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v5_16.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v5_19.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v6_3.c
|
||||
|
||||
mcp251xfd_dump_SOURCES = \
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c \
|
||||
mcp251xfd/mcp251xfd-dump-userspace.h \
|
||||
mcp251xfd/mcp251xfd-dump.c \
|
||||
mcp251xfd/mcp251xfd-dump.h \
|
||||
mcp251xfd/mcp251xfd-main.c \
|
||||
mcp251xfd/mcp251xfd-regmap.c \
|
||||
mcp251xfd/mcp251xfd.h
|
||||
|
||||
EXTRA_DIST += \
|
||||
mcp251xfd/99-devcoredump.rules \
|
||||
mcp251xfd/data/devcoredump-canfd-v5.15.dump \
|
||||
mcp251xfd/data/devcoredump-canfd.dump \
|
||||
mcp251xfd/data/devcoredump-classic-can-v5.15.dump \
|
||||
mcp251xfd/data/devcoredump-classic-can.dump \
|
||||
mcp251xfd/data/registers-canfd-v5.15.dump \
|
||||
mcp251xfd/data/registers-canfd.dump \
|
||||
mcp251xfd/data/registers-classic-can-v5.15.dump \
|
||||
mcp251xfd/data/registers-classic-can.dump \
|
||||
mcp251xfd/devcoredump \
|
||||
mcp251xfd/mcp251xfd-gen-testdata.sh
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libisobusfs.la
|
||||
|
||||
libisobusfs_la_SOURCES = \
|
||||
isobusfs/isobusfs_cmn.c \
|
||||
isobusfs/isobusfs_cmn_dh.c
|
||||
|
||||
bin_PROGRAMS = \
|
||||
asc2log \
|
||||
can-calc-bit-timing \
|
||||
canbusload \
|
||||
candump \
|
||||
canfdtest \
|
||||
cangen \
|
||||
cangw \
|
||||
canplayer \
|
||||
cansend \
|
||||
cansequence \
|
||||
cansniffer \
|
||||
isobusfs-cli \
|
||||
isobusfs-srv \
|
||||
isotpdump \
|
||||
isotpperf \
|
||||
isotprecv \
|
||||
isotpsend \
|
||||
isotpsniffer \
|
||||
isotptun \
|
||||
j1939acd \
|
||||
j1939cat \
|
||||
j1939spy \
|
||||
j1939sr \
|
||||
log2asc \
|
||||
log2long \
|
||||
mcp251xfd-dump \
|
||||
slcan_attach \
|
||||
slcand \
|
||||
slcanpty \
|
||||
testj1939
|
||||
|
||||
if HAVE_FORK
|
||||
bin_PROGRAMS += \
|
||||
bcmserver \
|
||||
canlogserver \
|
||||
isotpserver
|
||||
endif
|
||||
|
||||
isobusfs_cli_SOURCES = \
|
||||
isobusfs/isobusfs_cli.c \
|
||||
isobusfs/isobusfs_cli_cm.c \
|
||||
isobusfs/isobusfs_cli_dh.c \
|
||||
isobusfs/isobusfs_cli_fa.c \
|
||||
isobusfs/isobusfs_cli_selftests.c \
|
||||
isobusfs/isobusfs_cli_int.c
|
||||
|
||||
isobusfs_cli_LDADD = \
|
||||
libisobusfs.la \
|
||||
libcan.la
|
||||
|
||||
isobusfs_srv_SOURCES = \
|
||||
isobusfs/isobusfs_srv.c \
|
||||
isobusfs/isobusfs_srv_cm.c \
|
||||
isobusfs/isobusfs_srv_cm_fss.c \
|
||||
isobusfs/isobusfs_srv_dh.c \
|
||||
isobusfs/isobusfs_srv_fa.c \
|
||||
isobusfs/isobusfs_srv_fh.c \
|
||||
isobusfs/isobusfs_srv_vh.c
|
||||
|
||||
isobusfs_srv_LDADD = \
|
||||
libisobusfs.la \
|
||||
libcan.la
|
||||
|
||||
EXTRA_DIST += \
|
||||
isobusfs/isobusfs_create_test_dirs.sh \
|
||||
isobusfs/isobusfs_create_test_file.sh
|
||||
|
||||
j1939acd_LDADD = libj1939.la
|
||||
j1939cat_LDADD = libj1939.la
|
||||
j1939spy_LDADD = libj1939.la
|
||||
j1939sr_LDADD = libj1939.la
|
||||
testj1939_LDADD = libj1939.la
|
||||
|
||||
EXTRA_DIST += \
|
||||
.travis.yml \
|
||||
Android.mk \
|
||||
README.md \
|
||||
autogen.sh \
|
||||
can-j1939-kickstart.md \
|
||||
can-j1939.md \
|
||||
can-tc-init-etf.sh
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
configure \
|
||||
GNUmakefile.in \
|
||||
aclocal.m4 \
|
||||
config/autoconf/compile \
|
||||
config/autoconf/config.guess \
|
||||
config/autoconf/config.sub \
|
||||
config/autoconf/depcomp \
|
||||
config/autoconf/install-sh \
|
||||
config/autoconf/ltmain.sh \
|
||||
config/autoconf/mdate-sh \
|
||||
config/autoconf/missing \
|
||||
config/autoconf/texinfo.tex \
|
||||
config/m4/libtool.m4 \
|
||||
config/m4/ltoptions.m4 \
|
||||
config/m4/ltsugar.m4 \
|
||||
config/m4/ltversion.m4 \
|
||||
config/m4/lt~obsolete.m4 \
|
||||
$(DIST_ARCHIVES)
|
||||
|
||||
maintainer-clean-local:
|
||||
-chmod -R a+rw $(distdir)
|
||||
-rm -fr $(distdir)
|
||||
@@ -46,6 +46,7 @@ MAKEFLAGS := -k
|
||||
CFLAGS := -O2 -Wall -Wno-parentheses -Wsign-compare
|
||||
|
||||
HAVE_FORK := $(shell ./check_cc.sh "$(CC)" fork_test.c)
|
||||
HAVE_LIBGPS := $(shell test -x "`which pkg-config`" && pkg-config --exists libgps && echo 1 || echo 0)
|
||||
|
||||
CPPFLAGS += \
|
||||
-I. \
|
||||
@@ -63,6 +64,15 @@ CPPFLAGS += \
|
||||
PROGRAMS_CANGW := \
|
||||
cangw
|
||||
|
||||
PROGRAMS_J1939_TIMEDATE := \
|
||||
j1939-timedate-srv \
|
||||
j1939-timedate-cli
|
||||
|
||||
ifeq ($(HAVE_LIBGPS),1)
|
||||
PROGRAMS_J1939_VEHICLE_POSITION := \
|
||||
j1939-vehicle-position-srv
|
||||
endif
|
||||
|
||||
PROGRAMS_ISOBUSFS := \
|
||||
isobusfs-srv \
|
||||
isobusfs-cli
|
||||
@@ -93,6 +103,8 @@ PROGRAMS_SLCAN := \
|
||||
|
||||
PROGRAMS := \
|
||||
$(PROGRAMS_CANGW) \
|
||||
$(PROGRAMS_J1939_TIMEDATE) \
|
||||
$(PROGRAMS_J1939_VEHICLE_POSITION) \
|
||||
$(PROGRAMS_ISOBUSFS) \
|
||||
$(PROGRAMS_ISOTP) \
|
||||
$(PROGRAMS_J1939) \
|
||||
@@ -101,6 +113,7 @@ PROGRAMS := \
|
||||
can-calc-bit-timing \
|
||||
canbusload \
|
||||
candump \
|
||||
canerrsim \
|
||||
canfdtest \
|
||||
cangen \
|
||||
cansequence \
|
||||
@@ -121,7 +134,8 @@ endif
|
||||
all: $(PROGRAMS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o
|
||||
rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o j1939_timedate/*.o \
|
||||
j1939_vehicle_position/*.o
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
@@ -139,13 +153,17 @@ cansend.o: lib.h
|
||||
log2asc.o: lib.h
|
||||
log2long.o: lib.h
|
||||
slcanpty.o: lib.h
|
||||
j1939acd.o: libj1939.h
|
||||
j1939cat.o: libj1939.h
|
||||
j1939spy.o: libj1939.h
|
||||
j1939sr.o: libj1939.h
|
||||
testj1939.o: libj1939.h
|
||||
isobusfs_srv.o: lib.h
|
||||
isobusfs_c.o: lib.h
|
||||
j1939acd.o: lib.h libj1939.h
|
||||
j1939cat.o: lib.h libj1939.h
|
||||
j1939spy.o: lib.h libj1939.h
|
||||
j1939sr.o: lib.h libj1939.h
|
||||
testj1939.o: lib.h libj1939.h
|
||||
isobusfs_srv.o: lib.h libj1939.h
|
||||
isobusfs_c.o: lib.h libj1939.h
|
||||
j1939_timedate_srv.o: lib.h libj1939.h
|
||||
j1939_timedate_cli.o: lib.h libj1939.h
|
||||
j1939_vehicle_position_srv.o: lib.h libj1939.h
|
||||
|
||||
canframelen.o: canframelen.h
|
||||
|
||||
asc2log: asc2log.o lib.o
|
||||
@@ -159,13 +177,30 @@ cansequence: cansequence.o lib.o
|
||||
log2asc: log2asc.o lib.o
|
||||
log2long: log2long.o lib.o
|
||||
slcanpty: slcanpty.o lib.o
|
||||
j1939acd: j1939acd.o libj1939.o
|
||||
j1939cat: j1939cat.o libj1939.o
|
||||
j1939spy: j1939spy.o libj1939.o
|
||||
j1939sr: j1939sr.o libj1939.o
|
||||
testj1939: testj1939.o libj1939.o
|
||||
j1939acd: j1939acd.o lib.o libj1939.o
|
||||
j1939cat: j1939cat.o lib.o libj1939.o
|
||||
j1939spy: j1939spy.o lib.o libj1939.o
|
||||
j1939sr: j1939sr.o lib.o libj1939.o
|
||||
testj1939: testj1939.o lib.o libj1939.o
|
||||
|
||||
j1939-timedate-srv: lib.o \
|
||||
libj1939.o \
|
||||
j1939_timedate/j1939_timedate_srv.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
j1939-timedate-cli: lib.o \
|
||||
libj1939.o \
|
||||
j1939_timedate/j1939_timedate_cli.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
j1939-vehicle-position-srv: \
|
||||
lib.o \
|
||||
libj1939.o \
|
||||
j1939_vehicle_position/j1939_vehicle_position_srv.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) $(shell pkg-config --libs libgps) -o $@
|
||||
|
||||
isobusfs-srv: lib.o \
|
||||
libj1939.o \
|
||||
isobusfs/isobusfs_cmn.o \
|
||||
isobusfs/isobusfs_srv.o \
|
||||
isobusfs/isobusfs_srv_cm.o \
|
||||
@@ -178,6 +213,7 @@ isobusfs-srv: lib.o \
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
isobusfs-cli: lib.o \
|
||||
libj1939.o \
|
||||
isobusfs/isobusfs_cmn.o \
|
||||
isobusfs/isobusfs_cli.o \
|
||||
isobusfs/isobusfs_cli_cm.o \
|
||||
|
||||
@@ -29,6 +29,7 @@ subsystem (aka SocketCAN):
|
||||
* canbusload : calculate and display the CAN busload
|
||||
* can-calc-bit-timing : userspace version of in-kernel bitrate calculation
|
||||
* canfdtest : Full-duplex test program (DUT and host part)
|
||||
* canerrsim : CAN error message simulator
|
||||
|
||||
#### ISO-TP tools [ISO15765-2:2016 for Linux](https://github.com/hartkopp/can-isotp)
|
||||
* isotpsend : send a single ISO-TP PDU
|
||||
@@ -49,6 +50,10 @@ subsystem (aka SocketCAN):
|
||||
Follow the link to see examples on how this tools can be used:
|
||||
[Kickstart guide to can-j1939 on linux](https://github.com/linux-can/can-utils/blob/master/can-j1939-kickstart.md)
|
||||
|
||||
#### ISOBus File server tools
|
||||
* isobusfs-cli : ISOBus file client
|
||||
* isobusfs-srv : ISOBus file server
|
||||
|
||||
#### Log file converters
|
||||
* asc2log : convert ASC logfile to compact CAN frame logfile
|
||||
* log2asc : convert compact CAN frame logfile to ASC logfile
|
||||
@@ -72,7 +77,7 @@ Follow the link to see examples on how this tools can be used:
|
||||
|
||||
### Additional Information:
|
||||
|
||||
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/Documentation/networking/can.txt)
|
||||
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/html/latest/networking/can.html)
|
||||
* [Elinux.org CAN Bus Page](http://elinux.org/CAN_Bus)
|
||||
* [Debian Package Description](https://packages.debian.org/sid/can-utils)
|
||||
|
||||
* [J1939 kernel module installation on Debian](can-j1939-install-kernel-module.md)
|
||||
|
||||
@@ -58,7 +58,17 @@
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define BUFLEN 400 /* CAN FD mode lines can be pretty long */
|
||||
#define BUFLEN 6500 /* CAN XL mode lines can be pretty long */
|
||||
#define NO_DIR '.'
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
#define ASC_F_XLF 0x00400000
|
||||
#define ASC_F_RES 0x00800000
|
||||
#define ASC_F_SEC 0x01000000
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
@@ -69,10 +79,12 @@ static void print_usage(char *prg)
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "\t-I <infile>\t(default stdin)\n");
|
||||
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
|
||||
fprintf(stderr, "\t-d (disable direction information R/T)\n");
|
||||
fprintf(stderr, "\t-v (verbose)\n");
|
||||
}
|
||||
|
||||
static void prframe(FILE *file, struct timeval *tv, int dev,
|
||||
struct canfd_frame *cf, char *extra_info)
|
||||
union cfu *cf, char dir)
|
||||
{
|
||||
static char abuf[BUFLEN];
|
||||
|
||||
@@ -83,19 +95,23 @@ static void prframe(FILE *file, struct timeval *tv, int dev,
|
||||
else
|
||||
fprintf(file, "canX ");
|
||||
|
||||
snprintf_canframe(abuf, sizeof(abuf), (cu_t *)cf, 0);
|
||||
fprintf(file, "%s%s", abuf, extra_info);
|
||||
snprintf_canframe(abuf, sizeof(abuf), cf, 0);
|
||||
|
||||
if (dir == NO_DIR)
|
||||
fprintf(file, "%s\n", abuf);
|
||||
else
|
||||
fprintf(file, "%s %c\n", abuf, dir);
|
||||
}
|
||||
|
||||
static void get_can_id(struct canfd_frame *cf, char *idstring, int base)
|
||||
static void get_can_id(canid_t *can_id, char *idstring, int base)
|
||||
{
|
||||
if (idstring[strlen(idstring)-1] == 'x') {
|
||||
cf->can_id = CAN_EFF_FLAG;
|
||||
*can_id = CAN_EFF_FLAG;
|
||||
idstring[strlen(idstring)-1] = 0;
|
||||
} else
|
||||
cf->can_id = 0;
|
||||
*can_id = 0;
|
||||
|
||||
cf->can_id |= strtoul(idstring, NULL, base);
|
||||
*can_id |= strtoul(idstring, NULL, base);
|
||||
}
|
||||
|
||||
static void calc_tv(struct timeval *tv, struct timeval *read_tv,
|
||||
@@ -131,7 +147,7 @@ static void calc_tv(struct timeval *tv, struct timeval *read_tv,
|
||||
}
|
||||
|
||||
static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
char base, int dplace, FILE *outfile)
|
||||
char base, int dplace, int disable_dir, FILE *outfile)
|
||||
{
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
@@ -142,27 +158,26 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
int dlc = 0;
|
||||
int len = 0;
|
||||
int data[8];
|
||||
char tmp1[BUFLEN];
|
||||
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
|
||||
char *extra_info;
|
||||
char idstr[21];
|
||||
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
|
||||
int i, items;
|
||||
unsigned long long sec, usec;
|
||||
|
||||
/* check for ErrorFrames */
|
||||
if (sscanf(buf, "%llu.%llu %d %s",
|
||||
if (sscanf(buf, "%llu.%llu %d %20s",
|
||||
&sec, &usec,
|
||||
&interface, tmp1) == 4) {
|
||||
&interface, idstr) == 4) {
|
||||
read_tv.tv_sec = sec;
|
||||
read_tv.tv_usec = usec;
|
||||
|
||||
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||
if (!strncmp(idstr, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||
|
||||
/* do not know more than 'Error' */
|
||||
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
||||
cf.len = CAN_ERR_DLC;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, "\n");
|
||||
prframe(outfile, &tv, interface, (union cfu *)&cf, NO_DIR);
|
||||
fflush(outfile);
|
||||
return;
|
||||
}
|
||||
@@ -172,15 +187,15 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
|
||||
/* check for CAN frames with (hexa)decimal values */
|
||||
if (base == 'h')
|
||||
items = sscanf(buf, "%llu.%llu %d %s %2s %c %x %x %x %x %x %x %x %x %x",
|
||||
items = sscanf(buf, "%llu.%llu %d %20s %4s %c %x %x %x %x %x %x %x %x %x",
|
||||
&sec, &usec, &interface,
|
||||
tmp1, dir, &rtr, &dlc,
|
||||
idstr, dir, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]);
|
||||
else
|
||||
items = sscanf(buf, "%llu.%llu %d %s %2s %c %x %d %d %d %d %d %d %d %d",
|
||||
items = sscanf(buf, "%llu.%llu %d %20s %4s %c %x %d %d %d %d %d %d %d %d",
|
||||
&sec, &usec, &interface,
|
||||
tmp1, dir, &rtr, &dlc,
|
||||
idstr, dir, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]);
|
||||
|
||||
@@ -205,9 +220,9 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
|
||||
/* check for CAN ID with (hexa)decimal value */
|
||||
if (base == 'h')
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
get_can_id(&cf.can_id, idstr, 16);
|
||||
else
|
||||
get_can_id(&cf, tmp1, 10);
|
||||
get_can_id(&cf.can_id, idstr, 10);
|
||||
|
||||
/* dlc > 8 => len == CAN_MAX_DLEN => fill len8_dlc value */
|
||||
if (dlc > CAN_MAX_DLC)
|
||||
@@ -216,6 +231,9 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (disable_dir)
|
||||
dir[0] = NO_DIR;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
@@ -223,11 +241,6 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
cf.len = len;
|
||||
if (rtr == 'r')
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
@@ -236,13 +249,13 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
cf.data[i] = data[i] & 0xFFU;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, extra_info);
|
||||
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
|
||||
fflush(outfile);
|
||||
}
|
||||
}
|
||||
|
||||
static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
int dplace, FILE *outfile)
|
||||
int dplace, int disable_dir, FILE *outfile)
|
||||
{
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
@@ -251,29 +264,33 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
unsigned char brs, esi, ctmp;
|
||||
unsigned int flags;
|
||||
int dlc, dlen = 0;
|
||||
char tmp1[BUFLEN];
|
||||
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
|
||||
char *extra_info;
|
||||
char idstr[21];
|
||||
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
|
||||
char *ptr;
|
||||
int i;
|
||||
int n = 0; /* sscanf consumed characters */
|
||||
unsigned long long sec, usec;
|
||||
|
||||
/* The CANFD format is mainly in hex representation but <DataLength>
|
||||
and probably some content we skip anyway. Don't trust the docs! */
|
||||
/*
|
||||
* The CANFD format is mainly in hex representation but <DataLength>
|
||||
* and probably some content we skip anyway. Don't trust the docs!
|
||||
*/
|
||||
|
||||
/* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \
|
||||
100000 214 223040 80000000 46500250 460a0250 20011736 20010205 */
|
||||
/*
|
||||
* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \
|
||||
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \
|
||||
* 100000 214 223040 80000000 46500250 460a0250 20011736 20010205
|
||||
*/
|
||||
|
||||
/* check for valid line without symbolic name */
|
||||
if (sscanf(buf, "%llu.%llu %*s %d %2s %s %hhx %hhx %x %d ",
|
||||
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %hhx %hhx %x %d %n",
|
||||
&sec, &usec, &interface,
|
||||
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
|
||||
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) {
|
||||
|
||||
/* check for valid line with a symbolic name */
|
||||
if (sscanf(buf, "%llu.%llu %*s %d %2s %s %*s %hhx %hhx %x %d ",
|
||||
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %*s %hhx %hhx %x %d %n",
|
||||
&sec, &usec, &interface,
|
||||
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
|
||||
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) {
|
||||
|
||||
/* no valid CANFD format pattern */
|
||||
return;
|
||||
@@ -290,6 +307,9 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (disable_dir)
|
||||
dir[0] = NO_DIR;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
@@ -298,26 +318,13 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
/* don't trust ASCII content - sanitize data length */
|
||||
if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen)))
|
||||
return;
|
||||
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
get_can_id(&cf.can_id, idstr, 16);
|
||||
|
||||
/* now search for the beginning of the data[] content */
|
||||
sprintf(tmp1, " %x %x %x %2d ", brs, esi, dlc, dlen);
|
||||
|
||||
/* search for the pattern generated by real data */
|
||||
ptr = strcasestr(buf, tmp1);
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
ptr += strlen(tmp1); /* start of ASCII hex frame data */
|
||||
ptr = buf + n; /* start of ASCII hex frame data */
|
||||
|
||||
cf.len = dlen;
|
||||
|
||||
@@ -341,12 +348,6 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
if (sscanf(ptr, " %*x %*x %x ", &flags) != 1)
|
||||
return;
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
|
||||
if (flags & ASC_F_FDF) {
|
||||
cf.flags = CANFD_FDF;
|
||||
if (flags & ASC_F_BRS)
|
||||
@@ -373,18 +374,414 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
}
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, extra_info);
|
||||
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
|
||||
fflush(outfile);
|
||||
|
||||
/* No support for really strange CANFD ErrorFrames format m( */
|
||||
}
|
||||
|
||||
static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
int dplace, int disable_dir, FILE *outfile)
|
||||
{
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
struct can_frame cf = { 0 };
|
||||
unsigned char ctmp;
|
||||
unsigned int flags;
|
||||
int dlc, dlen = 0;
|
||||
char idstr[21];
|
||||
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
|
||||
char *ptr;
|
||||
int i;
|
||||
int n = 0; /* sscanf consumed characters */
|
||||
unsigned long long sec, usec;
|
||||
|
||||
/*
|
||||
* 59.171614 CANXL 2 Rx CBFF 243215 176 432 msgCanCCTest1 \
|
||||
* f 8 e1 89 e8 c2 b9 6d 5a f1 174 00000000 00000000 \
|
||||
* 000000050005000e 0000000000a00010 0000000a000a001d \
|
||||
* 0000000000a00002 000000100010000f 000000000a00001
|
||||
*/
|
||||
|
||||
/* check for valid line without symbolic name */
|
||||
if (sscanf(buf,
|
||||
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
|
||||
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
|
||||
"%x %d %n", /* DLC, Datalen */
|
||||
&sec, &usec, &interface, dir,
|
||||
idstr,
|
||||
&dlc, &dlen, &n) != 7) {
|
||||
/* check for valid line with a symbolic name */
|
||||
if (sscanf(buf,
|
||||
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
|
||||
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
|
||||
"%*s %x %d %n", /* sym name, DLC, Datalen */
|
||||
&sec, &usec, &interface, dir,
|
||||
idstr,
|
||||
&dlc, &dlen, &n) != 7) {
|
||||
/* no valid CAN CC format pattern */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
read_tv.tv_sec = sec;
|
||||
read_tv.tv_usec = usec;
|
||||
|
||||
/* check for allowed (unsigned) value ranges */
|
||||
if ((dlen > CAN_MAX_DLEN) || (dlc > CAN_MAX_RAW_DLC))
|
||||
return;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (disable_dir)
|
||||
dir[0] = NO_DIR;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
get_can_id(&cf.can_id, idstr, 16);
|
||||
|
||||
ptr = buf + n; /* start of ASCII hex frame data */
|
||||
|
||||
cf.len = dlen;
|
||||
|
||||
for (i = 0; i < dlen; i++) {
|
||||
ctmp = asc2nibble(ptr[0]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] = (ctmp << 4);
|
||||
|
||||
ctmp = asc2nibble(ptr[1]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] |= ctmp;
|
||||
|
||||
ptr += 3; /* start of next ASCII hex byte */
|
||||
}
|
||||
|
||||
/* skip FCRC to get Flags value */
|
||||
if (sscanf(ptr, "%*x %x ", &flags) != 1)
|
||||
return;
|
||||
|
||||
if (flags & ASC_F_RTR) {
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
/* dlen is always 0 for classic CAN RTR frames
|
||||
but the DLC value is valid in RTR cases */
|
||||
cf.len = dlc;
|
||||
/* sanitize payload length value */
|
||||
if (dlc > CAN_MAX_DLEN)
|
||||
cf.len = CAN_MAX_DLEN;
|
||||
}
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((cf.len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC))
|
||||
cf.len8_dlc = dlc;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
|
||||
fflush(outfile);
|
||||
}
|
||||
|
||||
static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
int dplace, int disable_dir, FILE *outfile)
|
||||
{
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
struct canfd_frame cf = { 0 };
|
||||
unsigned char ctmp;
|
||||
unsigned int flags;
|
||||
int dlc, dlen = 0;
|
||||
char idstr[21];
|
||||
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
|
||||
char *ptr;
|
||||
int i;
|
||||
int n = 0; /* sscanf consumed characters */
|
||||
unsigned long long sec, usec;
|
||||
|
||||
/*
|
||||
* 59.171614 CANXL 2 Rx FBFF 243215 176 432 msgCanFDTest2 \
|
||||
* 9 12 e1 89 e8 c2 b9 6d 5a f1 11 22 33 44 a 12345 00001240 00000000 \
|
||||
* 000000050005000e 0000000000a00010 0000000a000a001d \
|
||||
* 0000000000a00002 000000100010000f 000000000a00001
|
||||
*/
|
||||
|
||||
/* check for valid line without symbolic name */
|
||||
if (sscanf(buf,
|
||||
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
|
||||
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
|
||||
"%x %d %n", /* DLC, Datalen */
|
||||
&sec, &usec, &interface, dir,
|
||||
idstr,
|
||||
&dlc, &dlen, &n) != 7) {
|
||||
/* check for valid line with a symbolic name */
|
||||
if (sscanf(buf,
|
||||
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
|
||||
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
|
||||
"%*s %x %d %n", /* sym name, DLC, Datalen */
|
||||
&sec, &usec, &interface, dir,
|
||||
idstr,
|
||||
&dlc, &dlen, &n) != 7) {
|
||||
/* no valid CAN CC format pattern */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
read_tv.tv_sec = sec;
|
||||
read_tv.tv_usec = usec;
|
||||
|
||||
/* check for allowed (unsigned) value ranges */
|
||||
if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC))
|
||||
return;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (disable_dir)
|
||||
dir[0] = NO_DIR;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
get_can_id(&cf.can_id, idstr, 16);
|
||||
|
||||
ptr = buf + n; /* start of ASCII hex frame data */
|
||||
|
||||
cf.len = dlen;
|
||||
|
||||
for (i = 0; i < dlen; i++) {
|
||||
ctmp = asc2nibble(ptr[0]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] = (ctmp << 4);
|
||||
|
||||
ctmp = asc2nibble(ptr[1]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] |= ctmp;
|
||||
|
||||
ptr += 3; /* start of next ASCII hex byte */
|
||||
}
|
||||
|
||||
/* skip stuff field and FCRC to get Flags value */
|
||||
if (sscanf(ptr, "%*s %*s %x ", &flags) != 1)
|
||||
return;
|
||||
|
||||
if (!(flags & ASC_F_FDF))
|
||||
return;
|
||||
|
||||
cf.flags = CANFD_FDF;
|
||||
|
||||
if (flags & ASC_F_BRS)
|
||||
cf.flags |= CANFD_BRS;
|
||||
if (flags & ASC_F_ESI)
|
||||
cf.flags |= CANFD_ESI;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
|
||||
fflush(outfile);
|
||||
}
|
||||
|
||||
static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
int dplace, int disable_dir, FILE *outfile)
|
||||
{
|
||||
int interface;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
struct canxl_frame cf = { 0 };
|
||||
unsigned char sdt, vcid, secbit, ctmp;
|
||||
unsigned int af, flags;
|
||||
int dlc, dlen = 0;
|
||||
char idstr[21];
|
||||
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
|
||||
char *ptr;
|
||||
int i;
|
||||
int n = 0; /* sscanf consumed characters */
|
||||
unsigned long long sec, usec;
|
||||
|
||||
/*
|
||||
* 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \
|
||||
* e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \
|
||||
* ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \
|
||||
* 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \
|
||||
* 000000000a00001
|
||||
*/
|
||||
|
||||
/* check for valid line without symbolic name */
|
||||
if (sscanf(buf,
|
||||
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
|
||||
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
|
||||
"%hhx %hhx %x %d " /* SDT, SEC, DLC, Datalen */
|
||||
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
|
||||
&sec, &usec, &interface, dir,
|
||||
idstr,
|
||||
&sdt, &secbit, &dlc, &dlen,
|
||||
&vcid, &af, &n) != 11) {
|
||||
/* check for valid line with a symbolic name */
|
||||
if (sscanf(buf,
|
||||
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
|
||||
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
|
||||
"%*s %hhx %hhx %x %d " /* sym name, SDT, SEC, DLC, Datalen */
|
||||
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
|
||||
&sec, &usec, &interface, dir,
|
||||
idstr,
|
||||
&sdt, &secbit, &dlc, &dlen,
|
||||
&vcid, &af, &n) != 11) {
|
||||
|
||||
/* no valid CANXL format pattern */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
read_tv.tv_sec = sec;
|
||||
read_tv.tv_usec = usec;
|
||||
|
||||
/* check for allowed (unsigned) value ranges */
|
||||
if ((dlen > CANXL_MAX_DLEN) || (dlc > CANXL_MAX_DLC) || (secbit > 1))
|
||||
return;
|
||||
|
||||
cf.sdt = sdt;
|
||||
cf.af = af;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (disable_dir)
|
||||
dir[0] = NO_DIR;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
/* don't trust ASCII content - sanitize data length */
|
||||
if (dlen != dlc + 1)
|
||||
return;
|
||||
|
||||
get_can_id(&cf.prio, idstr, 16);
|
||||
|
||||
if ((cf.prio & CANXL_PRIO_MASK) != cf.prio)
|
||||
return;
|
||||
|
||||
if (vcid)
|
||||
cf.prio |= (vcid << CANXL_VCID_OFFSET);
|
||||
|
||||
ptr = buf + n; /* start of ASCII hex frame data */
|
||||
|
||||
cf.len = dlen;
|
||||
|
||||
for (i = 0; i < dlen; i++) {
|
||||
ctmp = asc2nibble(ptr[0]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] = (ctmp << 4);
|
||||
|
||||
ctmp = asc2nibble(ptr[1]);
|
||||
if (ctmp > 0x0F)
|
||||
return;
|
||||
|
||||
cf.data[i] |= ctmp;
|
||||
|
||||
ptr += 3; /* start of next ASCII hex byte */
|
||||
}
|
||||
|
||||
/* skip FCRC to get Flags value */
|
||||
if (sscanf(ptr, "%*x %x ", &flags) != 1)
|
||||
return;
|
||||
|
||||
/* mandatory for CAN XL frames */
|
||||
if (!(flags & ASC_F_XLF))
|
||||
return;
|
||||
|
||||
/* mark as CAN XL */
|
||||
cf.flags = CANXL_XLF;
|
||||
|
||||
if (flags & ASC_F_SEC)
|
||||
cf.flags |= CANXL_SEC;
|
||||
|
||||
if (flags & ASC_F_RES)
|
||||
cf.flags |= CANXL_RRS;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
|
||||
fflush(outfile);
|
||||
|
||||
/* No support for CAN XL ErrorFrames */
|
||||
}
|
||||
|
||||
static void eval_canxl(char* buf, struct timeval *date_tvp, char timestamps,
|
||||
int dplace, int disable_dir, FILE *outfile)
|
||||
{
|
||||
int interface;
|
||||
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
|
||||
char frfo[5]; /* frame format 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' plus terminating zero */
|
||||
unsigned long long sec, usec;
|
||||
|
||||
/*
|
||||
* The CANXL format is mainly in hex representation but <DataLength>
|
||||
* and probably some content we skip anyway. Check out the new spec:
|
||||
* CAN, Log & Trigger ASC Logging Format Spec V 1.4.17 of 2024-05-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a CAN XL ("XLFF") example for the CANXL Message Event:
|
||||
*
|
||||
* 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \
|
||||
* e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \
|
||||
* ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \
|
||||
* 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \
|
||||
* 000000000a00001
|
||||
*/
|
||||
|
||||
/* check for valid line until frame format tag */
|
||||
if (sscanf(buf, "%llu.%llu %*s %d %4s %4s ",
|
||||
&sec, &usec, &interface, dir, frfo) != 5)
|
||||
return; /* no valid CANXL format pattern */
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (strlen(frfo) != 4) /* 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' */
|
||||
return;
|
||||
|
||||
if (!strncmp(frfo, "XLFF", 4))
|
||||
eval_canxl_xl(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
|
||||
else if (!strncmp(frfo, "FBFF", 4))
|
||||
eval_canxl_fd(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
|
||||
else if (!strncmp(frfo, "FEFF", 4))
|
||||
eval_canxl_fd(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
|
||||
else if (!strncmp(frfo, "CBFF", 4))
|
||||
eval_canxl_cc(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
|
||||
else if (!strncmp(frfo, "CEFF", 4))
|
||||
eval_canxl_cc(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
|
||||
}
|
||||
|
||||
static int get_date(struct timeval *tv, char *date)
|
||||
{
|
||||
struct tm tms;
|
||||
unsigned int msecs = 0;
|
||||
|
||||
if (strcasestr(date, " pm ") != NULL) {
|
||||
if ((strcasestr(date, " am ") != NULL) || (strcasestr(date, " pm ") != NULL)) {
|
||||
/* assume EN/US date due to existing am/pm field */
|
||||
|
||||
if (!setlocale(LC_TIME, "en_US")) {
|
||||
@@ -393,9 +790,11 @@ static int get_date(struct timeval *tv, char *date)
|
||||
}
|
||||
|
||||
if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) {
|
||||
/* The string might contain a milliseconds value which strptime()
|
||||
does not support. So we read the ms value into the year variable
|
||||
before parsing the real year value (hack) */
|
||||
/*
|
||||
* The string might contain a milliseconds value which strptime()
|
||||
* does not support. So we read the ms value into the year variable
|
||||
* before parsing the real year value (hack)
|
||||
*/
|
||||
if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms))
|
||||
return 1;
|
||||
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
|
||||
@@ -410,9 +809,11 @@ static int get_date(struct timeval *tv, char *date)
|
||||
}
|
||||
|
||||
if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) {
|
||||
/* The string might contain a milliseconds value which strptime()
|
||||
does not support. So we read the ms value into the year variable
|
||||
before parsing the real year value (hack) */
|
||||
/*
|
||||
* The string might contain a milliseconds value which strptime()
|
||||
* does not support. So we read the ms value into the year variable
|
||||
* before parsing the real year value (hack)
|
||||
*/
|
||||
if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms))
|
||||
return 1;
|
||||
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
|
||||
@@ -434,11 +835,11 @@ static int get_date(struct timeval *tv, char *date)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[BUFLEN], tmp1[BUFLEN], tmp2[BUFLEN];
|
||||
char buf[BUFLEN], tmp1[10], tmp2[10];
|
||||
|
||||
FILE *infile = stdin;
|
||||
FILE *outfile = stdout;
|
||||
static int verbose;
|
||||
static int verbose, disable_dir;
|
||||
static struct timeval date_tv; /* date of the ASC file */
|
||||
static int dplace; /* decimal place 4, 5 or 6 or uninitialized */
|
||||
static char base; /* 'd'ec or 'h'ex */
|
||||
@@ -446,7 +847,7 @@ int main(int argc, char **argv)
|
||||
int opt;
|
||||
unsigned long long sec, usec;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:O:v?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:O:dv?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -464,6 +865,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
disable_dir = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
@@ -488,7 +893,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check for base and timestamp entries in the header */
|
||||
if ((!base) &&
|
||||
(sscanf(buf, "base %s timestamps %s", tmp1, tmp2) == 2)) {
|
||||
(sscanf(buf, "base %9s timestamps %9s", tmp1, tmp2) == 2)) {
|
||||
base = tmp1[0];
|
||||
timestamps = tmp2[0];
|
||||
if (verbose)
|
||||
@@ -522,7 +927,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* check for decimal places length in valid CAN frames */
|
||||
if (sscanf(buf, "%llu.%s %s ", &sec, tmp2,
|
||||
if (sscanf(buf, "%llu.%9s %9s ", &sec, tmp2,
|
||||
tmp1) != 3)
|
||||
continue; /* dplace remains zero until first found CAN frame */
|
||||
|
||||
@@ -537,15 +942,19 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/* the representation of a valid CAN frame is known here */
|
||||
/* so try to get CAN frames and ErrorFrames and convert them */
|
||||
/*
|
||||
* The representation of a valid CAN frame is known here.
|
||||
* So try to get CAN frames and ErrorFrames and convert them.
|
||||
*/
|
||||
|
||||
/* check classic CAN format or the CANFD tag which can take both types */
|
||||
if (sscanf(buf, "%llu.%llu %s ", &sec, &usec, tmp1) == 3){
|
||||
if (!strncmp(tmp1, "CANFD", 5))
|
||||
eval_canfd(buf, &date_tv, timestamps, dplace, outfile);
|
||||
/* check classic CAN format or the CANFD/CANXL tag which can take different types */
|
||||
if (sscanf(buf, "%llu.%llu %9s ", &sec, &usec, tmp1) == 3) {
|
||||
if (!strncmp(tmp1, "CANXL", 5))
|
||||
eval_canxl(buf, &date_tv, timestamps, dplace, disable_dir, outfile);
|
||||
else if (!strncmp(tmp1, "CANFD", 5))
|
||||
eval_canfd(buf, &date_tv, timestamps, dplace, disable_dir, outfile);
|
||||
else
|
||||
eval_can(buf, &date_tv, timestamps, base, dplace, outfile);
|
||||
eval_can(buf, &date_tv, timestamps, base, dplace, disable_dir, outfile);
|
||||
}
|
||||
}
|
||||
fclose(outfile);
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# banner <target name>
|
||||
#
|
||||
banner() {
|
||||
echo
|
||||
TG=`echo $1 | sed -e "s,/.*/,,g"`
|
||||
LINE=`echo $TG |sed -e "s/./-/g"`
|
||||
echo $LINE
|
||||
echo $TG
|
||||
echo $LINE
|
||||
echo
|
||||
}
|
||||
|
||||
banner "autoreconf"
|
||||
|
||||
autoreconf --force --install -Wall || exit $?
|
||||
|
||||
banner "Finished"
|
||||
+35
-11
@@ -153,12 +153,16 @@ int main(void)
|
||||
|
||||
char buf[MAXLEN];
|
||||
char format[FORMATSZ];
|
||||
char rxmsg[50];
|
||||
char rxmsg[64];
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
|
||||
struct {
|
||||
struct bcm_msg_head msg_head;
|
||||
struct can_frame frame;
|
||||
} msg;
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
if (snprintf(format, FORMATSZ, "< %%%ds %%c %%lu %%lu %%x %%hhu "
|
||||
"%%hhx %%hhx %%hhx %%hhx %%hhx %%hhx "
|
||||
@@ -194,7 +198,7 @@ int main(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (1) {
|
||||
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
|
||||
if (sa > 0 ){
|
||||
if (!fork())
|
||||
@@ -230,7 +234,7 @@ int main(void)
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
again:
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(sc, &readfds);
|
||||
FD_SET(sa, &readfds);
|
||||
@@ -238,6 +242,8 @@ int main(void)
|
||||
select((sc > sa)?sc+1:sa+1, &readfds, NULL, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(sc, &readfds)) {
|
||||
size_t size = sizeof(rxmsg);
|
||||
int len = 0, res;
|
||||
|
||||
recvfrom(sc, &msg, sizeof(msg), 0,
|
||||
(struct sockaddr*)&caddr, &caddrlen);
|
||||
@@ -245,17 +251,35 @@ int main(void)
|
||||
ifr.ifr_ifindex = caddr.can_ifindex;
|
||||
ioctl(sc, SIOCGIFNAME, &ifr);
|
||||
|
||||
sprintf(rxmsg, "< %s %03X %d ", ifr.ifr_name,
|
||||
msg.msg_head.can_id, msg.frame.can_dlc);
|
||||
res = snprintf(rxmsg, size, "< %s %03X %d ", ifr.ifr_name,
|
||||
msg.msg_head.can_id, msg.frame.can_dlc);
|
||||
if (res < 0 || (size_t)res >= size) {
|
||||
printf("Error: rxmsg buffer (size %zu) too small for data.\n", size);
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( i = 0; i < msg.frame.can_dlc; i++)
|
||||
sprintf(rxmsg + strlen(rxmsg), "%02X ",
|
||||
msg.frame.data[i]);
|
||||
len += res;
|
||||
|
||||
for (i = 0; i < msg.frame.can_dlc; i++) {
|
||||
res = snprintf(rxmsg + len, size - len, "%02X ", msg.frame.data[i]);
|
||||
if (res < 0 || (size_t)res >= (size - len)) {
|
||||
printf("Error: rxmsg buffer (size %zu) too small for data.\n", size);
|
||||
goto again;
|
||||
}
|
||||
|
||||
len += res;
|
||||
}
|
||||
|
||||
/* delimiter '\0' for Adobe(TM) Flash(TM) XML sockets */
|
||||
strcat(rxmsg, ">\0");
|
||||
res = snprintf(rxmsg + len, size - len, ">");
|
||||
if (res < 0 || (size_t)res >= (size - len)) {
|
||||
printf("Error: rxmsg buffer (size %zu) too small for data.\n", size);
|
||||
continue;
|
||||
}
|
||||
|
||||
send(sa, rxmsg, strlen(rxmsg) + 1, 0);
|
||||
len += res;
|
||||
|
||||
send(sa, rxmsg, len + 1, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +319,7 @@ int main(void)
|
||||
|
||||
items = sscanf(buf, format,
|
||||
ifr.ifr_name,
|
||||
&cmd,
|
||||
&cmd,
|
||||
&msg.msg_head.ival2.tv_sec,
|
||||
&msg.msg_head.ival2.tv_usec,
|
||||
&msg.msg_head.can_id,
|
||||
|
||||
@@ -1121,6 +1121,11 @@ static const unsigned int common_data_bitrates[] = {
|
||||
4000000,
|
||||
2000000,
|
||||
1000000,
|
||||
800000,
|
||||
500000,
|
||||
250000,
|
||||
125000,
|
||||
100000,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
+180
-180
@@ -1,180 +1,180 @@
|
||||
# can-j1939 kernel module installation #
|
||||
|
||||
|
||||
|
||||
### Problem
|
||||
|
||||
You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939
|
||||
modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64
|
||||
```
|
||||
|
||||
and also this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ testj1939
|
||||
testj1939: socket(j1939): Protocol not supported
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Solution
|
||||
|
||||
Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine.
|
||||
|
||||
|
||||
|
||||
#### 1. Download kernel source ####
|
||||
|
||||
We will download Debian patched kernel 5.8. First update your sources
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ sudo apt update
|
||||
```
|
||||
|
||||
and then look at available Debian patched kernel source packages
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ apt-cache search linux-source
|
||||
linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches
|
||||
linux-source - Linux kernel source (meta-package)
|
||||
linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches
|
||||
linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches
|
||||
linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches
|
||||
linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches
|
||||
linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches
|
||||
```
|
||||
|
||||
If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this
|
||||
|
||||
```
|
||||
echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list
|
||||
```
|
||||
|
||||
Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours)
|
||||
|
||||
```
|
||||
deb http://security.debian.org/debian-security buster/updates main contrib
|
||||
deb-src http://security.debian.org/debian-security buster/updates main contrib
|
||||
|
||||
deb http://deb.debian.org/debian/ buster main contrib non-free
|
||||
deb-src http://deb.debian.org/debian/ buster main contrib non-free
|
||||
|
||||
deb http://deb.debian.org/debian buster-backports main contrib
|
||||
```
|
||||
|
||||
After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package
|
||||
|
||||
```
|
||||
sudo apt install linux-source-5.8
|
||||
```
|
||||
|
||||
and unpack it
|
||||
```
|
||||
avra@vm-debian:~$ cd /usr/src
|
||||
avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz
|
||||
avra@vm-debian:/usr/src$ cd linux-source-5.8
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2. Add can-j1939 module to kernel ####
|
||||
|
||||
First we need some packages for **menuconfig**
|
||||
|
||||
```
|
||||
sudo apt-get install libncurses5 libncurses5-dev
|
||||
```
|
||||
|
||||
copy and use our old configuration to run **menuconfig**
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig
|
||||
```
|
||||
|
||||
where we enable SAE J1939 kernel module as shown
|
||||
|
||||
```
|
||||
- Networking Support
|
||||
- Can bus subsystem support
|
||||
- <M> SAE J1939
|
||||
```
|
||||
|
||||
Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following
|
||||
```
|
||||
CONFIG_SYSTEM_TRUSTED_KEYS=""
|
||||
```
|
||||
|
||||
and save the file.
|
||||
|
||||
|
||||
|
||||
#### 3. Compile and install kernel and modules
|
||||
|
||||
We will have to download necessary packages
|
||||
|
||||
```
|
||||
sudo apt install build-essential libssl-dev libelf-dev bison flex
|
||||
```
|
||||
|
||||
compile kernel (using threads to make it faster)
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc)
|
||||
```
|
||||
|
||||
install
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install
|
||||
```
|
||||
|
||||
and update grub
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot
|
||||
```
|
||||
|
||||
Check if installation is correct with
|
||||
|
||||
```
|
||||
sudo modprobe can-j1939
|
||||
```
|
||||
|
||||
and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works:
|
||||
|
||||
```
|
||||
sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko
|
||||
```
|
||||
|
||||
If it does then all you need to do is
|
||||
|
||||
```
|
||||
sudo depmod -av
|
||||
```
|
||||
|
||||
reboot once, and **modprobe** command from the above should finally work.
|
||||
|
||||
|
||||
|
||||
#### 4. Install headers if needed
|
||||
|
||||
You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with
|
||||
|
||||
```
|
||||
nano /usr/include/linux/can.h
|
||||
```
|
||||
|
||||
If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually
|
||||
|
||||
```
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/
|
||||
```
|
||||
|
||||
That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy!
|
||||
# can-j1939 kernel module installation #
|
||||
|
||||
|
||||
|
||||
### Problem
|
||||
|
||||
You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939
|
||||
modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64
|
||||
```
|
||||
|
||||
and also this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ testj1939
|
||||
testj1939: socket(j1939): Protocol not supported
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Solution
|
||||
|
||||
Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine.
|
||||
|
||||
|
||||
|
||||
#### 1. Download kernel source ####
|
||||
|
||||
We will download Debian patched kernel 5.8. First update your sources
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ sudo apt update
|
||||
```
|
||||
|
||||
and then look at available Debian patched kernel source packages
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ apt-cache search linux-source
|
||||
linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches
|
||||
linux-source - Linux kernel source (meta-package)
|
||||
linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches
|
||||
linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches
|
||||
linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches
|
||||
linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches
|
||||
linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches
|
||||
```
|
||||
|
||||
If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this
|
||||
|
||||
```
|
||||
echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list
|
||||
```
|
||||
|
||||
Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours)
|
||||
|
||||
```
|
||||
deb http://security.debian.org/debian-security buster/updates main contrib
|
||||
deb-src http://security.debian.org/debian-security buster/updates main contrib
|
||||
|
||||
deb http://deb.debian.org/debian/ buster main contrib non-free
|
||||
deb-src http://deb.debian.org/debian/ buster main contrib non-free
|
||||
|
||||
deb http://deb.debian.org/debian buster-backports main contrib
|
||||
```
|
||||
|
||||
After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package
|
||||
|
||||
```
|
||||
sudo apt install linux-source-5.8
|
||||
```
|
||||
|
||||
and unpack it
|
||||
```
|
||||
avra@vm-debian:~$ cd /usr/src
|
||||
avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz
|
||||
avra@vm-debian:/usr/src$ cd linux-source-5.8
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2. Add can-j1939 module to kernel ####
|
||||
|
||||
First we need some packages for **menuconfig**
|
||||
|
||||
```
|
||||
sudo apt-get install libncurses5 libncurses5-dev
|
||||
```
|
||||
|
||||
copy and use our old configuration to run **menuconfig**
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig
|
||||
```
|
||||
|
||||
where we enable SAE J1939 kernel module as shown
|
||||
|
||||
```
|
||||
- Networking Support
|
||||
- Can bus subsystem support
|
||||
- <M> SAE J1939
|
||||
```
|
||||
|
||||
Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following
|
||||
```
|
||||
CONFIG_SYSTEM_TRUSTED_KEYS=""
|
||||
```
|
||||
|
||||
and save the file.
|
||||
|
||||
|
||||
|
||||
#### 3. Compile and install kernel and modules
|
||||
|
||||
We will have to download necessary packages
|
||||
|
||||
```
|
||||
sudo apt install build-essential libssl-dev libelf-dev bison flex
|
||||
```
|
||||
|
||||
compile kernel (using threads to make it faster)
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc)
|
||||
```
|
||||
|
||||
install
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install
|
||||
```
|
||||
|
||||
and update grub
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot
|
||||
```
|
||||
|
||||
Check if installation is correct with
|
||||
|
||||
```
|
||||
sudo modprobe can-j1939
|
||||
```
|
||||
|
||||
and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works:
|
||||
|
||||
```
|
||||
sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko
|
||||
```
|
||||
|
||||
If it does then all you need to do is
|
||||
|
||||
```
|
||||
sudo depmod -av
|
||||
```
|
||||
|
||||
reboot once, and **modprobe** command from the above should finally work.
|
||||
|
||||
|
||||
|
||||
#### 4. Install headers if needed
|
||||
|
||||
You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with
|
||||
|
||||
```
|
||||
nano /usr/include/linux/can.h
|
||||
```
|
||||
|
||||
If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually
|
||||
|
||||
```
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/
|
||||
```
|
||||
|
||||
That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy!
|
||||
|
||||
+306
-81
@@ -45,14 +45,17 @@
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
@@ -65,34 +68,69 @@
|
||||
#include "terminal.h"
|
||||
#include "canframelen.h"
|
||||
|
||||
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
|
||||
#define ANYDEV "any" /* name of interface to receive from any CAN interface */
|
||||
#define MAXDEVS 20 /* max. number of CAN interfaces given on the cmdline */
|
||||
|
||||
#define PERCENTRES 5 /* resolution in percent for bargraph */
|
||||
#define NUMBAR (100 / PERCENTRES) /* number of bargraph elements */
|
||||
#define BRSTRLEN 20
|
||||
#define VISUAL_WINDOW 90 /* window width for visualization */
|
||||
|
||||
/*
|
||||
* Inspired from
|
||||
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/
|
||||
* include/linux/sched/loadavg.h
|
||||
*
|
||||
* Following are the fixed-point math constants and the exponential-damping
|
||||
* factors for:
|
||||
* - 1 samples/s in 1 minute
|
||||
* - 1 samples/s in 5 minutes
|
||||
* - 1 samples/s in 15 minutes
|
||||
* in fixed-point representation.
|
||||
*/
|
||||
#define FP_SHIFT 12 /* bits of precision */
|
||||
#define FP_ONE (1 << FP_SHIFT) /* 1.0 fixed-point representation */
|
||||
#define EXP_1 4028 /* (1 / e ^ (1 / 60)) * FP_ONE */
|
||||
#define EXP_5 4082 /* (1 / e ^ (1 / 300)) * FP_ONE */
|
||||
#define EXP_15 4091 /* (1 / e ^ (1 / 900)) * FP_ONE */
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static struct {
|
||||
char devname[IFNAMSIZ + 1];
|
||||
char bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */
|
||||
char recv_direction;
|
||||
int ifindex;
|
||||
unsigned int bitrate;
|
||||
unsigned int dbitrate;
|
||||
unsigned int recv_frames;
|
||||
unsigned int recv_bits_total;
|
||||
unsigned int recv_bits_payload;
|
||||
unsigned int recv_bits_dbitrate;
|
||||
} stat[MAXSOCK + 1];
|
||||
unsigned int load_min;
|
||||
unsigned int load_max;
|
||||
unsigned int load_1m;
|
||||
unsigned int load_5m;
|
||||
unsigned int load_15m;
|
||||
unsigned int loads[VISUAL_WINDOW];
|
||||
unsigned int index;
|
||||
} stat[MAXDEVS + 1];
|
||||
|
||||
static volatile int running = 1;
|
||||
static volatile sig_atomic_t signal_num;
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
static int max_bitrate_len;
|
||||
static int currmax;
|
||||
static int max_bitratestr_len;
|
||||
static unsigned int currmax;
|
||||
static unsigned char redraw;
|
||||
static unsigned char timestamp;
|
||||
static unsigned char color;
|
||||
static unsigned char bargraph;
|
||||
static bool statistic;
|
||||
static bool reset;
|
||||
static bool visualize;
|
||||
static enum cfl_mode mode = CFL_WORSTCASE;
|
||||
static char *prg;
|
||||
static struct termios old;
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
@@ -106,21 +144,23 @@ static void print_usage(char *prg)
|
||||
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
|
||||
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
|
||||
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
|
||||
fprintf(stderr, " -s (show statistics, press 'r' to reset)\n");
|
||||
fprintf(stderr, " -v (show busload visualization)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXSOCK);
|
||||
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>[,<dbitrate>]\n\n");
|
||||
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXDEVS);
|
||||
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>[,<dbitrate>]\n");
|
||||
fprintf(stderr, "The interface name 'any' enables an auto detection with the given bitrate[s]\n\n");
|
||||
fprintf(stderr, "The bitrate is mandatory as it is needed to know the CAN bus bitrate to\n");
|
||||
fprintf(stderr, "calculate the bus load percentage based on the received CAN frames.\n");
|
||||
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
|
||||
fprintf(stderr, "For each given interface the data is presented in one line which contains:\n\n");
|
||||
fprintf(stderr, "(interface) (received CAN frames) (used bits total) (used bits for payload)\n");
|
||||
fprintf(stderr, "(interface) (received CAN frames) (bits total) (bits payload) (bits payload brs)\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000 can2@500000 can3@500000 -r -t -b -c\n\n");
|
||||
fprintf(stderr, "%s 2014-02-01 21:13:16 (worst case bitstuffing)\n", prg);
|
||||
fprintf(stderr, " can0@100000 805 74491 36656 74%% |XXXXXXXXXXXXXX......|\n");
|
||||
fprintf(stderr, " can1@500000 796 75140 37728 15%% |XXX.................|\n");
|
||||
fprintf(stderr, " can2@500000 0 0 0 0%% |....................|\n");
|
||||
fprintf(stderr, " can3@500000 47 4633 2424 0%% |....................|\n");
|
||||
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000,2000000 can2@500000 -r -t -b -c\n\n");
|
||||
fprintf(stderr, "%s 2024-08-08 16:30:05 (worst case bitstuffing)\n", prg);
|
||||
fprintf(stderr, " can0@100k 192 21980 9136 0 21%% |TTTT................|\n");
|
||||
fprintf(stderr, " can1@500k/2M 2651 475500 234448 131825 74%% |XXXXXXXXXXXXXX......|\n");
|
||||
fprintf(stderr, " can2@500k 855 136777 62968 35219 27%% |RRRRR...............|\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -130,9 +170,45 @@ static void sigterm(int signo)
|
||||
signal_num = signo;
|
||||
}
|
||||
|
||||
static int add_bitrate(char *brstr, unsigned int bitrate)
|
||||
{
|
||||
if (bitrate % 1000000 == 0)
|
||||
return sprintf(brstr, "%dM", bitrate / 1000000);
|
||||
|
||||
if (bitrate % 1000 == 0)
|
||||
return sprintf(brstr, "%dk", bitrate / 1000);
|
||||
|
||||
return sprintf(brstr, "%d", bitrate);
|
||||
}
|
||||
|
||||
static void create_bitrate_string(int stat_idx, int *max_bitratestr_len)
|
||||
{
|
||||
int ptr;
|
||||
|
||||
ptr = add_bitrate(&stat[stat_idx].bitratestr[0], stat[stat_idx].bitrate);
|
||||
|
||||
if (stat[stat_idx].bitrate != stat[stat_idx].dbitrate) {
|
||||
ptr += sprintf(&stat[stat_idx].bitratestr[ptr], "/");
|
||||
ptr += add_bitrate(&stat[stat_idx].bitratestr[ptr], stat[stat_idx].dbitrate);
|
||||
}
|
||||
|
||||
if (ptr > *max_bitratestr_len)
|
||||
*max_bitratestr_len = ptr;
|
||||
}
|
||||
|
||||
static unsigned int calc_load(unsigned int load_fp,
|
||||
unsigned int exp_fp,
|
||||
unsigned int sample)
|
||||
{
|
||||
unsigned int sample_fp = sample << FP_SHIFT;
|
||||
unsigned int damped_sum = (load_fp * exp_fp) +
|
||||
(sample_fp * (FP_ONE - exp_fp));
|
||||
return damped_sum >> FP_SHIFT;
|
||||
}
|
||||
|
||||
static void printstats(int signo)
|
||||
{
|
||||
int i, j, percent;
|
||||
unsigned int i, j, k, percent, index;
|
||||
|
||||
if (redraw)
|
||||
printf("%s", CSR_HOME);
|
||||
@@ -194,15 +270,39 @@ static void printstats(int signo)
|
||||
else
|
||||
percent = 0;
|
||||
|
||||
printf(" %*s@%-*d %5d %7d %6d %6d %3d%%",
|
||||
printf(" %*s@%-*s %5d %7d %7d %7d %3d%%",
|
||||
max_devname_len, stat[i].devname,
|
||||
max_bitrate_len, stat[i].bitrate,
|
||||
max_bitratestr_len, stat[i].bitratestr,
|
||||
stat[i].recv_frames,
|
||||
stat[i].recv_bits_total,
|
||||
stat[i].recv_bits_payload,
|
||||
stat[i].recv_bits_dbitrate,
|
||||
percent);
|
||||
|
||||
if (statistic) {
|
||||
if (reset) {
|
||||
stat[i].load_min = UINT_MAX;
|
||||
stat[i].load_max = 0;
|
||||
stat[i].load_1m = 0;
|
||||
stat[i].load_5m = 0;
|
||||
stat[i].load_15m = 0;
|
||||
}
|
||||
|
||||
stat[i].load_min = MIN(stat[i].load_min, percent);
|
||||
stat[i].load_max = MAX(stat[i].load_max, percent);
|
||||
|
||||
stat[i].load_1m = calc_load(stat[i].load_1m, EXP_1, percent);
|
||||
stat[i].load_5m = calc_load(stat[i].load_5m, EXP_5, percent);
|
||||
stat[i].load_15m = calc_load(stat[i].load_15m, EXP_15, percent);
|
||||
|
||||
printf(" min:%3d%%, max:%3d%%, load:%3d%% %3d%% %3d%%",
|
||||
stat[i].load_min,
|
||||
stat[i].load_max,
|
||||
(stat[i].load_1m + (FP_ONE >> 1)) >> FP_SHIFT,
|
||||
(stat[i].load_5m + (FP_ONE >> 1)) >> FP_SHIFT,
|
||||
(stat[i].load_15m + (FP_ONE >> 1)) >> FP_SHIFT);
|
||||
}
|
||||
|
||||
if (bargraph) {
|
||||
|
||||
printf(" |");
|
||||
@@ -212,7 +312,7 @@ static void printstats(int signo)
|
||||
|
||||
for (j = 0; j < NUMBAR; j++) {
|
||||
if (j < percent / PERCENTRES)
|
||||
printf("X");
|
||||
printf("%c", stat[i].recv_direction);
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
@@ -220,6 +320,28 @@ static void printstats(int signo)
|
||||
printf("|");
|
||||
}
|
||||
|
||||
if (visualize) {
|
||||
stat[i].loads[stat[i].index] = percent;
|
||||
stat[i].index = (stat[i].index + 1) % VISUAL_WINDOW;
|
||||
|
||||
printf("\n");
|
||||
for (j = 0; j < NUMBAR; j++) {
|
||||
printf("%3d%%|", (NUMBAR - j) * PERCENTRES);
|
||||
index = stat[i].index;
|
||||
for (k = 0; k < VISUAL_WINDOW; k++) {
|
||||
percent = stat[i].loads[index];
|
||||
|
||||
if ((percent / PERCENTRES) >= (NUMBAR - j))
|
||||
printf("X");
|
||||
else
|
||||
printf(".");
|
||||
|
||||
index = (index + 1) % VISUAL_WINDOW;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (color)
|
||||
printf("%s", ATTRESET);
|
||||
|
||||
@@ -230,8 +352,11 @@ static void printstats(int signo)
|
||||
stat[i].recv_bits_total = 0;
|
||||
stat[i].recv_bits_dbitrate = 0;
|
||||
stat[i].recv_bits_payload = 0;
|
||||
stat[i].recv_direction = '.';
|
||||
}
|
||||
|
||||
reset = false;
|
||||
|
||||
if (!redraw)
|
||||
printf("\n");
|
||||
|
||||
@@ -240,17 +365,35 @@ static void printstats(int signo)
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &old);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fd_set rdfs;
|
||||
int s[MAXSOCK];
|
||||
|
||||
int s;
|
||||
int opt;
|
||||
char *ptr, *nptr;
|
||||
struct sockaddr_can addr;
|
||||
struct canfd_frame frame;
|
||||
int nbytes, i;
|
||||
struct ifreq ifr;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
unsigned int i;
|
||||
int nbytes;
|
||||
|
||||
int have_anydev = 0;
|
||||
unsigned int anydev_bitrate = 0;
|
||||
unsigned int anydev_dbitrate = 0;
|
||||
char anydev_bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */
|
||||
struct termios temp;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &old);
|
||||
atexit(cleanup);
|
||||
temp = old;
|
||||
temp.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &temp);
|
||||
|
||||
signal(SIGTERM, sigterm);
|
||||
signal(SIGHUP, sigterm);
|
||||
@@ -260,7 +403,7 @@ int main(int argc, char **argv)
|
||||
|
||||
prg = basename(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "rtbcieh?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "rtbciesvh?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'r':
|
||||
redraw = 1;
|
||||
@@ -286,6 +429,15 @@ int main(int argc, char **argv)
|
||||
mode = CFL_EXACT;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
statistic = true;
|
||||
reset = true;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
visualize = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(prg);
|
||||
exit(1);
|
||||
@@ -300,27 +452,22 @@ int main(int argc, char **argv)
|
||||
|
||||
currmax = argc - optind; /* find real number of CAN devices */
|
||||
|
||||
if (currmax > MAXSOCK) {
|
||||
printf("More than %d CAN devices given on commandline!\n", MAXSOCK);
|
||||
if (currmax > MAXDEVS) {
|
||||
printf("More than %d CAN devices given on commandline!\n", MAXDEVS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* prefill stat[] array with given interface assignments */
|
||||
for (i = 0; i < currmax; i++) {
|
||||
ptr = argv[optind + i];
|
||||
ptr = argv[optind + i + have_anydev];
|
||||
|
||||
nbytes = strlen(ptr);
|
||||
if (nbytes >= (int)(IFNAMSIZ + sizeof("@1000000") + 1)) {
|
||||
if (nbytes >= (int)(IFNAMSIZ + sizeof("@1000000,2000000") + 1)) {
|
||||
printf("name of CAN device '%s' is too long!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pr_debug("open %d '%s'.\n", i, ptr);
|
||||
|
||||
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (s[i] < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
pr_debug("handle %d '%s'.\n", i, ptr);
|
||||
|
||||
nptr = strchr(ptr, '@');
|
||||
|
||||
@@ -330,55 +477,76 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* interface name length */
|
||||
nbytes = nptr - ptr; /* interface name is up the first '@' */
|
||||
|
||||
if (nbytes >= (int)IFNAMSIZ) {
|
||||
printf("name of CAN device '%s' is too long!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* copy interface name to stat[] entry */
|
||||
strncpy(stat[i].devname, ptr, nbytes);
|
||||
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
|
||||
strncpy(ifr.ifr_name, ptr, nbytes);
|
||||
|
||||
if (nbytes > max_devname_len)
|
||||
max_devname_len = nbytes; /* for nice printing */
|
||||
|
||||
char *endp;
|
||||
stat[i].bitrate = strtol(nptr + 1, &endp, 0); /* bitrate is placed behind the '@' */
|
||||
/* bitrate is placed behind the '@' */
|
||||
stat[i].bitrate = strtol(nptr + 1, &endp, 0);
|
||||
|
||||
/* check for CAN FD additional data bitrate */
|
||||
if (*endp == ',')
|
||||
/* data bitrate is placed behind the ',' */
|
||||
stat[i].dbitrate = strtol(endp + 1, &endp, 0);
|
||||
else
|
||||
stat[i].dbitrate = stat[i].bitrate;
|
||||
|
||||
if (!stat[i].bitrate || stat[i].bitrate > 1000000) {
|
||||
if (!stat[i].bitrate || stat[i].bitrate > 1000000 ||
|
||||
!stat[i].dbitrate || stat[i].dbitrate > 8000000) {
|
||||
printf("invalid bitrate for CAN device '%s'!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
nbytes = strlen(nptr + 1);
|
||||
if (nbytes > max_bitrate_len)
|
||||
max_bitrate_len = nbytes; /* for nice printing */
|
||||
/* prepare bitrate string for hot path */
|
||||
create_bitrate_string(i, &max_bitratestr_len);
|
||||
|
||||
pr_debug("using interface name '%s'.\n", ifr.ifr_name);
|
||||
stat[i].recv_direction = '.';
|
||||
|
||||
/* try to switch the socket into CAN FD mode */
|
||||
const int canfd_on = 1;
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
|
||||
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
exit(1);
|
||||
/* handling for 'any' device */
|
||||
if (have_anydev == 0 && strcmp(ANYDEV, stat[i].devname) == 0) {
|
||||
anydev_bitrate = stat[i].bitrate;
|
||||
anydev_dbitrate = stat[i].dbitrate;
|
||||
memcpy(anydev_bitratestr, stat[i].bitratestr, BRSTRLEN);
|
||||
/* no real interface: remove this command line entry */
|
||||
have_anydev = 1;
|
||||
currmax--;
|
||||
i--;
|
||||
} else {
|
||||
stat[i].ifindex = if_nametoindex(stat[i].devname);
|
||||
if (!stat[i].ifindex) {
|
||||
printf("invalid CAN device '%s'!\n", stat[i].devname);
|
||||
return 1;
|
||||
}
|
||||
pr_debug("using interface name '%s'.\n", stat[i].devname);
|
||||
}
|
||||
}
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
/* try to switch the socket into CAN FD mode */
|
||||
const int canfd_on = 1;
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = 0; /* any CAN device */
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
|
||||
alarm(1);
|
||||
@@ -386,43 +554,100 @@ int main(int argc, char **argv)
|
||||
if (redraw)
|
||||
printf("%s", CLR_SCREEN);
|
||||
|
||||
/* these settings are static and can be held out of the hot path */
|
||||
iov.iov_base = &frame;
|
||||
msg.msg_name = &addr;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = NULL;
|
||||
|
||||
while (running) {
|
||||
FD_ZERO(&rdfs);
|
||||
for (i = 0; i < currmax; i++)
|
||||
FD_SET(s[i], &rdfs);
|
||||
FD_SET(s, &rdfs);
|
||||
FD_SET(STDIN_FILENO, &rdfs);
|
||||
|
||||
if (select(s[currmax - 1] + 1, &rdfs, NULL, NULL, NULL) < 0) {
|
||||
if (select(s + 1, &rdfs, NULL, NULL, NULL) < 0) {
|
||||
//perror("pselect");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < currmax; i++) { /* check all CAN RAW sockets */
|
||||
|
||||
if (FD_ISSET(s[i], &rdfs)) {
|
||||
nbytes = read(s[i], &frame, sizeof(frame));
|
||||
|
||||
if (nbytes < 0) {
|
||||
perror("read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nbytes < (int)sizeof(struct can_frame)) {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stat[i].recv_frames++;
|
||||
stat[i].recv_bits_payload += frame.len * 8;
|
||||
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
|
||||
&frame, mode, sizeof(frame));
|
||||
stat[i].recv_bits_total += can_frame_length(&frame,
|
||||
mode, nbytes);
|
||||
if (FD_ISSET(STDIN_FILENO, &rdfs)) {
|
||||
if (getchar() == 'r') {
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* these settings may be modified by recvmsg() */
|
||||
iov.iov_len = sizeof(frame);
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
nbytes = recvmsg(s, &msg, 0);
|
||||
|
||||
if (nbytes < 0) {
|
||||
perror("read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nbytes != (int)sizeof(struct can_frame) &&
|
||||
nbytes != (int)sizeof(struct canfd_frame)) {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find received ifindex in stat[] array */
|
||||
for (i = 0; i < currmax; i++) {
|
||||
if (stat[i].ifindex == addr.can_ifindex)
|
||||
break;
|
||||
}
|
||||
|
||||
/* not found? check for unknown interface */
|
||||
if (i >= currmax) {
|
||||
/* drop unwanted traffic */
|
||||
if (have_anydev == 0)
|
||||
continue;
|
||||
|
||||
/* can we add another interface? */
|
||||
if (currmax >= MAXDEVS)
|
||||
continue;
|
||||
|
||||
/* add an new entry */
|
||||
stat[i].ifindex = addr.can_ifindex;
|
||||
stat[i].bitrate = anydev_bitrate;
|
||||
stat[i].dbitrate = anydev_dbitrate;
|
||||
memcpy(stat[i].bitratestr, anydev_bitratestr, BRSTRLEN);
|
||||
stat[i].recv_direction = '.';
|
||||
if_indextoname(addr.can_ifindex, stat[i].devname);
|
||||
nbytes = strlen(stat[i].devname);
|
||||
if (nbytes > max_devname_len)
|
||||
max_devname_len = nbytes; /* for nice printing */
|
||||
currmax++;
|
||||
}
|
||||
|
||||
if (msg.msg_flags & MSG_DONTROUTE) {
|
||||
/* TX direction */
|
||||
if (stat[i].recv_direction == '.')
|
||||
stat[i].recv_direction = 'T';
|
||||
else if (stat[i].recv_direction == 'R')
|
||||
stat[i].recv_direction = 'X';
|
||||
} else {
|
||||
/* RX direction */
|
||||
if (stat[i].recv_direction == '.')
|
||||
stat[i].recv_direction = 'R';
|
||||
else if (stat[i].recv_direction == 'T')
|
||||
stat[i].recv_direction = 'X';
|
||||
}
|
||||
|
||||
stat[i].recv_frames++;
|
||||
stat[i].recv_bits_payload += frame.len * 8;
|
||||
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
|
||||
&frame, mode, sizeof(frame));
|
||||
stat[i].recv_bits_total += can_frame_length(&frame,
|
||||
mode, nbytes);
|
||||
}
|
||||
|
||||
for (i = 0; i < currmax; i++)
|
||||
close(s[i]);
|
||||
close(s);
|
||||
|
||||
if (signal_num)
|
||||
return 128 + signal_num;
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
#ifndef SO_TIMESTAMPING
|
||||
#define SO_TIMESTAMPING 37
|
||||
#endif
|
||||
#ifndef SCM_TIMESTAMPING
|
||||
#define SCM_TIMESTAMPING SO_TIMESTAMPING
|
||||
#endif
|
||||
|
||||
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
|
||||
|
||||
@@ -113,7 +116,8 @@ static const int canfx_on = 1;
|
||||
|
||||
#define MAXANI 4
|
||||
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
|
||||
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
|
||||
static const char extra_fd_info[4][4] = { "- -", "B -", "- E", "B E" };
|
||||
static const char extra_xl_info[4][4] = { "- -", "S -", "- R", "S R" };
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
@@ -128,6 +132,7 @@ static void print_usage(void)
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -H (read hardware timestamps instead of system timestamps)\n");
|
||||
fprintf(stderr, " -N (log nanosecond timestamps instead of microseconds)\n");
|
||||
fprintf(stderr, " -c (increment color mode level)\n");
|
||||
fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n");
|
||||
fprintf(stderr, " -a (enable additional ASCII output)\n");
|
||||
@@ -142,7 +147,7 @@ static void print_usage(void)
|
||||
fprintf(stderr, " -d (monitor dropped CAN frames)\n");
|
||||
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n");
|
||||
fprintf(stderr, " -8 (display raw DLC values in {} for Classical CAN)\n");
|
||||
fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n");
|
||||
fprintf(stderr, " -x (print extra message infos, rx/tx [brs esi|sec rrs])\n");
|
||||
fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
|
||||
@@ -220,16 +225,22 @@ static int idx2dindex(int ifidx, int socket)
|
||||
return i;
|
||||
}
|
||||
|
||||
static int sprint_timestamp(char *ts_buffer, const char timestamp,
|
||||
const struct timeval *tv, struct timeval *const last_tv)
|
||||
static int sprint_timestamp(char *ts_buffer, const char timestamp, const char use_ns,
|
||||
const struct timespec *ts, struct timespec *const last_ts)
|
||||
{
|
||||
int numchars = 0;
|
||||
|
||||
switch (timestamp) {
|
||||
case 'a': /* absolute with timestamp */
|
||||
numchars = sprintf(ts_buffer, "(%010llu.%06llu) ",
|
||||
(unsigned long long)tv->tv_sec,
|
||||
(unsigned long long)tv->tv_usec);
|
||||
if (use_ns) {
|
||||
numchars = sprintf(ts_buffer, "(%010llu.%09llu) ",
|
||||
(unsigned long long)ts->tv_sec,
|
||||
(unsigned long long)ts->tv_nsec);
|
||||
} else {
|
||||
numchars = sprintf(ts_buffer, "(%010llu.%06llu) ",
|
||||
(unsigned long long)ts->tv_sec,
|
||||
(unsigned long long)ts->tv_nsec / 1000);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
@@ -237,32 +248,43 @@ static int sprint_timestamp(char *ts_buffer, const char timestamp,
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv->tv_sec);
|
||||
tm = *localtime(&ts->tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
|
||||
(unsigned long long)tv->tv_usec);
|
||||
if (use_ns) {
|
||||
numchars = sprintf(ts_buffer, "(%s.%09llu) ", timestring,
|
||||
(unsigned long long)ts->tv_nsec);
|
||||
} else {
|
||||
numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
|
||||
(unsigned long long)ts->tv_nsec / 1000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
struct timespec diff;
|
||||
|
||||
if (last_tv->tv_sec == 0) /* first init */
|
||||
*last_tv = *tv;
|
||||
diff.tv_sec = tv->tv_sec - last_tv->tv_sec;
|
||||
diff.tv_usec = tv->tv_usec - last_tv->tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (last_ts->tv_sec == 0) /* first init */
|
||||
*last_ts = *ts;
|
||||
diff.tv_sec = ts->tv_sec - last_ts->tv_sec;
|
||||
diff.tv_nsec = ts->tv_nsec - last_ts->tv_nsec;
|
||||
if (diff.tv_nsec < 0)
|
||||
diff.tv_sec--, diff.tv_nsec += 1000000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
numchars = sprintf(ts_buffer, "(%03llu.%06llu) ",
|
||||
(unsigned long long)diff.tv_sec,
|
||||
(unsigned long long)diff.tv_usec);
|
||||
diff.tv_sec = diff.tv_nsec = 0;
|
||||
if (use_ns) {
|
||||
numchars = sprintf(ts_buffer, "(%03llu.%09llu) ",
|
||||
(unsigned long long)diff.tv_sec,
|
||||
(unsigned long long)diff.tv_nsec);
|
||||
} else {
|
||||
numchars = sprintf(ts_buffer, "(%03llu.%06llu) ",
|
||||
(unsigned long long)diff.tv_sec,
|
||||
(unsigned long long)diff.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
if (timestamp == 'd')
|
||||
*last_tv = *tv; /* update for delta calculation */
|
||||
*last_ts = *ts; /* update for delta calculation */
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -288,6 +310,7 @@ int main(int argc, char **argv)
|
||||
unsigned char timestamp = 0;
|
||||
unsigned char logtimestamp = 'a';
|
||||
unsigned char hwtimestamp = 0;
|
||||
unsigned char use_ns = 0;
|
||||
unsigned char down_causes_exit = 1;
|
||||
unsigned char dropmonitor = 0;
|
||||
unsigned char extra_msg_info = 0;
|
||||
@@ -319,10 +342,10 @@ int main(int argc, char **argv)
|
||||
struct cmsghdr *cmsg;
|
||||
struct can_filter *rfilter;
|
||||
can_err_mask_t err_mask;
|
||||
static cu_t cu; /* union for CAN CC/FD/XL frames */
|
||||
static union cfu cu; /* union for CAN CC/FD/XL frames */
|
||||
int nbytes, i;
|
||||
struct ifreq ifr;
|
||||
struct timeval tv, last_tv;
|
||||
struct timespec ts, last_ts;
|
||||
int timeout_ms = -1; /* default to no timeout */
|
||||
FILE *logfile = NULL;
|
||||
char fname[83]; /* suggested by -Wformat-overflow= */
|
||||
@@ -334,12 +357,12 @@ int main(int argc, char **argv)
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_usec = 0;
|
||||
last_ts.tv_sec = 0;
|
||||
last_ts.tv_nsec = 0;
|
||||
|
||||
progname = basename(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lf:Ln:r:Dde8xT:h?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "t:HNciaSs:lf:Ln:r:Dde8xT:h?")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
timestamp = optarg[0];
|
||||
@@ -359,6 +382,10 @@ int main(int argc, char **argv)
|
||||
hwtimestamp = 1;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
use_ns = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
color++;
|
||||
break;
|
||||
@@ -688,12 +715,12 @@ int main(int argc, char **argv)
|
||||
localtime_r(&currtime, &now);
|
||||
|
||||
snprintf(fname, sizeof(fname), "candump-%04d-%02d-%02d_%02d%02d%02d.log",
|
||||
now.tm_year + 1900,
|
||||
now.tm_mon + 1,
|
||||
now.tm_mday,
|
||||
now.tm_hour,
|
||||
now.tm_min,
|
||||
now.tm_sec);
|
||||
now.tm_year + 1900,
|
||||
now.tm_mon + 1,
|
||||
now.tm_mday,
|
||||
now.tm_hour,
|
||||
now.tm_min,
|
||||
now.tm_sec);
|
||||
|
||||
logname = fname;
|
||||
}
|
||||
@@ -783,9 +810,13 @@ int main(int argc, char **argv)
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_TIMESTAMP) {
|
||||
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
|
||||
struct timeval tv;
|
||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec;
|
||||
ts.tv_nsec *= 1000;
|
||||
} else if (cmsg->cmsg_type == SCM_TIMESTAMPING) {
|
||||
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
||||
|
||||
/*
|
||||
@@ -795,8 +826,7 @@ int main(int argc, char **argv)
|
||||
* See chapter 2.1.2 Receive timestamps in
|
||||
* linux/Documentation/networking/timestamping.txt
|
||||
*/
|
||||
tv.tv_sec = stamp[2].tv_sec;
|
||||
tv.tv_usec = stamp[2].tv_nsec / 1000;
|
||||
ts = stamp[2];
|
||||
} else if (cmsg->cmsg_type == SO_RXQ_OVFL) {
|
||||
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
|
||||
}
|
||||
@@ -831,11 +861,9 @@ int main(int argc, char **argv)
|
||||
/* build common log format output */
|
||||
if ((log) || ((logfrmt) && (silent == SILENT_OFF))) {
|
||||
|
||||
alen = sprint_timestamp(afrbuf, logtimestamp,
|
||||
&tv, &last_tv);
|
||||
alen = sprint_timestamp(afrbuf, logtimestamp, use_ns, &ts, &last_ts);
|
||||
|
||||
alen += sprintf(afrbuf + alen, "%*s ",
|
||||
max_devname_len, devname[idx]);
|
||||
alen += sprintf(afrbuf + alen, "%*s ", max_devname_len, devname[idx]);
|
||||
|
||||
alen += snprintf_canframe(afrbuf + alen, sizeof(afrbuf) - alen, &cu, 0);
|
||||
}
|
||||
@@ -861,18 +889,23 @@ int main(int argc, char **argv)
|
||||
|
||||
/* print (colored) long CAN frame style to stdout */
|
||||
alen = sprintf(afrbuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
||||
alen += sprint_timestamp(afrbuf + alen, timestamp, &tv, &last_tv);
|
||||
alen += sprint_timestamp(afrbuf + alen, timestamp, use_ns, &ts, &last_ts);
|
||||
alen += sprintf(afrbuf + alen, " %s%*s",
|
||||
(color && (color < 3)) ? col_on[idx % MAXCOL] : "",
|
||||
max_devname_len, devname[idx]);
|
||||
(color && (color < 3)) ? col_on[idx % MAXCOL] : "",
|
||||
max_devname_len, devname[idx]);
|
||||
|
||||
if (extra_msg_info) {
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
alen += sprintf(afrbuf + alen, " TX %s",
|
||||
extra_m_info[cu.fd.flags & 3]);
|
||||
alen += sprintf(afrbuf + alen, " TX");
|
||||
else
|
||||
alen += sprintf(afrbuf + alen, " RX %s",
|
||||
extra_m_info[cu.fd.flags & 3]);
|
||||
alen += sprintf(afrbuf + alen, " RX");
|
||||
|
||||
if (cu.xl.flags & CANXL_XLF)
|
||||
alen += sprintf(afrbuf + alen, " %s",
|
||||
extra_xl_info[cu.xl.flags & 3]);
|
||||
else
|
||||
alen += sprintf(afrbuf + alen, " %s",
|
||||
extra_fd_info[cu.fd.flags & 3]);
|
||||
}
|
||||
|
||||
alen += sprintf(afrbuf + alen, "%s ", (color == 1) ? col_off : "");
|
||||
|
||||
+563
@@ -0,0 +1,563 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// canerrsim - utility to simulate SocketCAN error messages, by Zeljko Avramovic (c) 2024 //
|
||||
// //
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause //
|
||||
// //
|
||||
// Virtual CAN adapter vcan0 is hard coded and you can bring it up like this: //
|
||||
// sudo modprobe vcan //
|
||||
// sudo ip link add dev vcan0 type vcan //
|
||||
// sudo ip link set vcan0 mtu 72 # needed for CAN FD //
|
||||
// sudo ip link set vcan0 up //
|
||||
// //
|
||||
// To simulate error messages use canerrsim utility like this: //
|
||||
// ./canerrsim vcan0 LostArBit=09 Data4=AA TX BusOff NoAck ShowBits //
|
||||
// //
|
||||
// That should show in canerrdump utility as: //
|
||||
// 0x06A [8] 09 00 80 00 AA 00 00 00 ERR=LostArBit09,NoAck,BusOff,Prot(Type(TX),Loc(Unspec)) //
|
||||
// //
|
||||
// Alternatively, you could use candump from can-utils to check only error messages like this: //
|
||||
// candump -tA -e -c -a any,0~0,#FFFFFFFF //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <net/if.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define STR_EQUAL 0
|
||||
|
||||
void show_help_and_exit()
|
||||
{
|
||||
printf("\n");
|
||||
printf("Usage: canerrsim <CAN interface> <options>\n");
|
||||
printf("\n");
|
||||
printf("CAN interface: ( CAN interface is case sensitive )\n");
|
||||
printf(" can0 ( or can1, can2 or virtual ones like vcan0, vcan1...\n");
|
||||
printf("\n");
|
||||
printf("Options: ( options are not case sensitive )\n");
|
||||
printf(" ( ERROR CLASS (MASK) IN CAN ID: )\n");
|
||||
printf(" TxTimeout ( TX timeout by netdevice driver )\n");
|
||||
printf(" NoAck ( received no ACK on transmission )\n");
|
||||
printf(" BusOff ( bus off )\n");
|
||||
printf(" BusError ( bus error, may flood! )\n");
|
||||
printf(" Restarted ( controller restarted )\n");
|
||||
printf(" TxCount=<00..FF> ( TX error counter )\n");
|
||||
printf(" RxCount=<00..FF> ( RX error counter )\n");
|
||||
printf(" ( ARBITRATIONLOST IN CAN ID + BIT NUMBER IN DATA[0]: )\n");
|
||||
printf(" LostArBit=<00..29> ( decimal lost arbitration bit number in bitstream )\n");
|
||||
printf(" ( CONTROLLER IN CAN ID + ERROR STATUS IN DATA[1]: )\n");
|
||||
printf(" OverflowRX ( RX buffer overflow )\n");
|
||||
printf(" OverflowTX ( TX buffer overflow )\n");
|
||||
printf(" WarningRX ( reached warning level for RX errors )\n");
|
||||
printf(" WarningTX ( reached warning level for TX errors )\n");
|
||||
printf(" PassiveRX ( reached error passive status RX, errors > 127 )\n");
|
||||
printf(" PassiveTX ( reached error passive status TX, errors > 127 )\n");
|
||||
printf(" Active ( recovered to error active state )\n");
|
||||
printf(" ( PROTOCOL ERROR IN CAN ID + TYPE IN DATA[2]: )\n");
|
||||
printf(" SingleBit ( single bit error )\n");
|
||||
printf(" FrameFormat ( frame format error )\n");
|
||||
printf(" BitStuffing ( bit stuffing error )\n");
|
||||
printf(" Bit0 ( unable to send dominant bit )\n");
|
||||
printf(" Bit1 ( unable to send recessive bit )\n");
|
||||
printf(" BusOverload ( bus overload )\n");
|
||||
printf(" ActiveAnnouncement ( active error announcement )\n");
|
||||
printf(" TX ( error occurred on transmission )\n");
|
||||
printf(" ( PROTOCOL ERROR IN CAN ID + LOCATION IN DATA[3]: )\n");
|
||||
printf(" SOF ( start of frame )\n");
|
||||
printf(" ID28_21 ( ID bits 21..28, SFF: 3..10 )\n");
|
||||
printf(" ID20_18 ( ID bits 18..20, SFF: 0..2 )\n");
|
||||
printf(" SRTR ( substitute RTR, SFF: RTR )\n");
|
||||
printf(" IDE ( identifier extension )\n");
|
||||
printf(" ID17_13 ( ID bits 13..17 )\n");
|
||||
printf(" ID12_05 ( ID bits 5..12 )\n");
|
||||
printf(" ID04_00 ( ID bits 0..4 )\n");
|
||||
printf(" RTR ( RTR )\n");
|
||||
printf(" RES1 ( reserved bit 1 )\n");
|
||||
printf(" RES0 ( reserved bit 0 )\n");
|
||||
printf(" DLC ( data length code )\n");
|
||||
printf(" DATA ( data section )\n");
|
||||
printf(" CRC_SEQ ( CRC sequence )\n");
|
||||
printf(" CRC_DEL ( CRC delimiter )\n");
|
||||
printf(" ACK ( ACK slot )\n");
|
||||
printf(" ACK_DEL ( ACK delimiter )\n");
|
||||
printf(" EOF ( end of frame )\n");
|
||||
printf(" INTERM ( intermission )\n");
|
||||
printf(" ( TRANSCEIVER ERROR IN CAN ID + STATUS IN DATA[4]: )\n");
|
||||
printf(" ( CANH CANL )\n");
|
||||
printf(" TransUnspec ( 0000 0000 )\n");
|
||||
printf(" CanHiNoWire ( 0000 0100 )\n");
|
||||
printf(" CanHiShortToBAT ( 0000 0101 )\n");
|
||||
printf(" CanHiShortToVCC ( 0000 0110 )\n");
|
||||
printf(" CanHiShortToGND ( 0000 0111 )\n");
|
||||
printf(" CanLoNoWire ( 0100 0000 )\n");
|
||||
printf(" CanLoShortToBAT ( 0101 0000 )\n");
|
||||
printf(" CanLoShortToVCC ( 0110 0000 )\n");
|
||||
printf(" CanLoShortToGND ( 0111 0000 )\n");
|
||||
printf(" CanLoShortToCanHi ( 1000 0000 )\n");
|
||||
printf(" ( CUSTOM BYTE TO DATA[0..7]: )\n");
|
||||
printf(" Data<0..7>=<00..FF> ( write hex number to one of 8 payload bytes )\n");
|
||||
printf(" ( DEBUG HELPERS: )\n");
|
||||
printf(" ShowBits ( display all frame bits )\n");
|
||||
printf("\n");
|
||||
printf("Examples:\n");
|
||||
printf("\n");
|
||||
printf(" ./canerrsim can1 LostArBit=09 Data3=AA Data4=BB ShowBits\n");
|
||||
printf(" ( can1: 9th arb. bit lost, custom bytes in Data[3] and Data[4], show debug frame bits )\n");
|
||||
printf("\n");
|
||||
printf(" ./canerrsim vcan0 NoAck TxTimeout Active\n");
|
||||
printf(" ( vcan0: received no ACK on transmission, driver timeout, protocol type active error announcement )\n");
|
||||
printf("\n");
|
||||
printf(" ./canerrsim vcan0 BusError CanHiNoWire Restarted INTERM\n");
|
||||
printf(" ( vcan0: bus error, lost CANH wiring, controller restarted, protocol location intermission )\n");
|
||||
printf("\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void __attribute__((format (printf, 1, 2))) err_exit(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void show_invalid_option(const char *option)
|
||||
{
|
||||
err_exit("Error: Invalid option %s\n", option);
|
||||
}
|
||||
|
||||
void show_err_and_exit(const char *err_type)
|
||||
{
|
||||
err_exit("Error: You can only have one %s parameter!\n", err_type);
|
||||
}
|
||||
|
||||
void show_loc_err_and_exit()
|
||||
{
|
||||
show_err_and_exit("protocol location");
|
||||
}
|
||||
|
||||
void show_arb_err_and_exit()
|
||||
{
|
||||
show_err_and_exit("arbitration bit");
|
||||
}
|
||||
|
||||
void show_transc_err_and_exit()
|
||||
{
|
||||
show_err_and_exit("transceiver");
|
||||
}
|
||||
|
||||
void print_binary(uint32_t number)
|
||||
{
|
||||
uint32_t mask = 0x80000000; // start with the most significant bit
|
||||
for (int i = 0; i < 32; i++) {
|
||||
putchar((number & mask) ? '1' : '0');
|
||||
mask >>= 1; // shift the mask to the right
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_can addr;
|
||||
struct ifreq ifr;
|
||||
struct can_frame frame;
|
||||
bool show_bits = false, location_processed = false, transceiver_processed = false, arbitration_processed = false;
|
||||
|
||||
printf("CAN Sockets Error Messages Simulator\n");
|
||||
if (argc < 3)
|
||||
show_help_and_exit();
|
||||
|
||||
// initialize CAN frame
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
frame.can_id = CAN_ERR_FLAG;
|
||||
frame.can_dlc = CAN_ERR_DLC;
|
||||
|
||||
// Parse command line parameters
|
||||
for (int i = 2; i < argc; i++) {
|
||||
//printf("strlen(argv[%d]) = %d\n", i, strlen(argv[i]));
|
||||
|
||||
// error class (mask) in can_id
|
||||
if (strcasecmp(argv[i], "TxTimeout") == STR_EQUAL)
|
||||
frame.can_id |= CAN_ERR_TX_TIMEOUT; // generate TxTimeout error
|
||||
else if (strcasecmp(argv[i], "NoAck") == STR_EQUAL)
|
||||
frame.can_id |= CAN_ERR_ACK; // generate NoAck error
|
||||
else if (strcasecmp(argv[i], "BusOff") == STR_EQUAL)
|
||||
frame.can_id |= CAN_ERR_BUSOFF; // generate BusOff error
|
||||
else if (strcasecmp(argv[i], "BusError") == STR_EQUAL)
|
||||
frame.can_id |= CAN_ERR_BUSERROR; // generate BusError error
|
||||
else if (strcasecmp(argv[i], "Restarted") == STR_EQUAL)
|
||||
frame.can_id |= CAN_ERR_RESTARTED; // generate Restarted error
|
||||
// error status of CAN controller / data[1]
|
||||
else if (strcasecmp(argv[i], "OverflowRX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; // generate RX Overflow suberror
|
||||
} else if (strcasecmp(argv[i], "OverflowTX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_TX_OVERFLOW; // generate TX Overflow suberror
|
||||
} else if (strcasecmp(argv[i], "WarningRX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_RX_WARNING; // generate RX Warning suberror
|
||||
} else if (strcasecmp(argv[i], "WarningTX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_TX_WARNING; // generate TX Warning suberror
|
||||
} else if (strcasecmp(argv[i], "PassiveRX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_RX_PASSIVE; // generate RX Passive suberror
|
||||
} else if (strcasecmp(argv[i], "PassiveTX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_TX_PASSIVE; // generate TX Passive suberror
|
||||
} else if (strcasecmp(argv[i], "Active") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] |= CAN_ERR_CRTL_ACTIVE; // generate Active suberror
|
||||
} else if (strcasecmp(argv[i], "CtrlUnspec") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CRTL; // generate Controller error
|
||||
frame.data[1] = CAN_ERR_CRTL_UNSPEC; // generate Unspec suberror
|
||||
}
|
||||
// error in CAN protocol (type) / data[2]
|
||||
else if (strcasecmp(argv[i], "SingleBit") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_BIT; // generate SingleBit suberror
|
||||
} else if (strcasecmp(argv[i], "FrameFormat") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_FORM; // generate FrameFormat suberror
|
||||
} else if (strcasecmp(argv[i], "BitStuffing") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_STUFF; // generate BitStuffing suberror
|
||||
} else if (strcasecmp(argv[i], "Bit0") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_BIT0; // generate Bit0 suberror
|
||||
} else if (strcasecmp(argv[i], "Bit1") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_BIT1; // generate Bit1 suberror
|
||||
} else if (strcasecmp(argv[i], "BusOverload") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_OVERLOAD; // generate BusOverload suberror
|
||||
} else if (strcasecmp(argv[i], "ActiveAnnouncement") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_ACTIVE; // generate ActiveAnnouncement suberror
|
||||
} else if (strcasecmp(argv[i], "TX") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_TX; // generate TX suberror
|
||||
} else if (strcasecmp(argv[i], "ProtUnspec") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Type error
|
||||
frame.data[2] = CAN_ERR_PROT_UNSPEC; // generate Unspec suberror
|
||||
}
|
||||
// error in CAN protocol (location) / data[3]
|
||||
else if (strcasecmp(argv[i], "LocUnspec") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_UNSPEC; // generate Unspec suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "SOF") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_SOF; // generate SOF suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "SOF") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_SOF; // generate SOF suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ID28_21") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ID28_21; // generate ID28_21 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ID20_18") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ID20_18; // generate ID20_18 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "SRTR") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_SRTR; // generate SRTR suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "IDE") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_IDE; // generate IDE suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ID17_13") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ID17_13; // generate ID17_13 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ID12_05") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ID12_05; // generate ID12_05 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ID04_00") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ID04_00; // generate ID04_00 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "RTR") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_RTR; // generate RTR suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "RES1") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_RES1; // generate RES1 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "RES0") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_RES0; // generate RES0 suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "DLC") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_DLC; // generate DLC suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "DATA") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_DATA; // generate DATA suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CRC_SEQ") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; // generate CRC_SEQ suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CRC_DEL") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_CRC_DEL; // generate CRC_DEL suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ACK") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ACK; // generate ACK suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "ACK_DEL") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_ACK_DEL; // generate ACK_DEL suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "EOF") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_EOF; // generate EOF suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "INTERM") == STR_EQUAL) {
|
||||
if (location_processed)
|
||||
show_loc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_PROT; // generate Protocol Location error
|
||||
frame.data[3] = CAN_ERR_PROT_LOC_INTERM; // generate INTERM suberror
|
||||
location_processed = true;
|
||||
}
|
||||
// error status of CAN transceiver / data[4]
|
||||
else if (strcasecmp(argv[i], "TransUnspec") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_UNSPEC; // generate EOF suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanHiNoWire") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANH_NO_WIRE; // generate CanHiNoWire suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanHiShortToBAT") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANH_SHORT_TO_BAT; // generate CanHiShortToBAT suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanHiShortToVCC") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANH_SHORT_TO_VCC; // generate CanHiShortToVCC suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanHiShortToGND") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANH_SHORT_TO_GND; // generate CanHiShortToGND suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanLoNoWire") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANL_NO_WIRE; // generate CanLoNoWire suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanLoShortToBAT") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANL_SHORT_TO_BAT; // generate CanLoShortToBAT suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanLoShortToVCC") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANL_SHORT_TO_VCC; // generate CanLoShortToVCC suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanLoShortToGND") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANL_SHORT_TO_GND; // generate CanLoShortToGND suberror
|
||||
location_processed = true;
|
||||
} else if (strcasecmp(argv[i], "CanLoShortToCanHi") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_TRX; // generate Transceiver error
|
||||
frame.data[4] = CAN_ERR_TRX_CANL_SHORT_TO_CANH; // generate CanLoShortToCanHi suberror
|
||||
location_processed = true;
|
||||
}
|
||||
// LostArBit=29 (Totallength=12)
|
||||
else if ((strlen(argv[i]) == 12) && // 'LostArBit=29'
|
||||
(argv[i][9] == '=') && // '='
|
||||
(argv[i][10] >= '0' && argv[i][10] <= '2') && // valid bits are from 00 to 29 (in decimal)
|
||||
(argv[i][11] >= '0' && argv[i][11] <= '9')) { // valid bits are from 00 to 29 (in decimal)
|
||||
unsigned char arb_bit_num = (argv[i][10] - '0') * 10 + argv[i][11] - '0'; // convert decimal bitnumber to byte
|
||||
argv[i][9] = 0; // terminate string for comparison
|
||||
if (strcasecmp(argv[i], "LostArBit") == STR_EQUAL) {
|
||||
if (arbitration_processed)
|
||||
show_arb_err_and_exit();
|
||||
frame.can_id |= CAN_ERR_LOSTARB; // generate LostArbitartionBit error
|
||||
frame.data[0] = arb_bit_num; // bitnumber
|
||||
arbitration_processed = true;
|
||||
} else {
|
||||
argv[i][9] = '='; // undo string termination
|
||||
show_invalid_option(argv[i]);
|
||||
}
|
||||
}
|
||||
// Data1=F4 (Totallength=8) // since this does not set any error bit, has to be combined with other errors
|
||||
else if ((strlen(argv[i]) == 8) && // 'Data1=F4'
|
||||
(argv[i][4] >= '0' && argv[i][4] <= '7') && // valid data bytes are from 0 to 7 (in decimal)
|
||||
(argv[i][5] == '=') && // '='
|
||||
((argv[i][6] >= '0' && argv[i][6] <= '9') || (argv[i][6] >= 'A' && argv[i][6] <= 'F')) && // first hexadecimal digit
|
||||
((argv[i][7] >= '0' && argv[i][7] <= '9') || (argv[i][6] >= 'A' && argv[i][6] <= 'F'))) { // second hexadecimal digit
|
||||
unsigned char data_byte_value, data_byte_no = 0;
|
||||
data_byte_no = argv[i][4] - '0'; // convert order number of data byte (Data1 to 1, Data2 to 2...)
|
||||
data_byte_value = 0;
|
||||
if (argv[i][6] >= 'A') // convert higher digit hexadecimal char to byte
|
||||
data_byte_value += (argv[i][6] - 'A' + 10) * 16;
|
||||
else
|
||||
data_byte_value += (argv[i][6] - '0') * 16;
|
||||
if (argv[i][7] >= 'A') // convert lower digit hexadecimal char to byte
|
||||
data_byte_value += (argv[i][7] - 'A' + 10);
|
||||
else
|
||||
data_byte_value += (argv[i][7] - '0');
|
||||
argv[i][4] = 0; // terminate string for comparison
|
||||
if (strcasecmp(argv[i], "Data") == STR_EQUAL) {
|
||||
if (transceiver_processed)
|
||||
show_transc_err_and_exit();
|
||||
frame.data[data_byte_no] = data_byte_value; // populate proper data byte
|
||||
arbitration_processed = true;
|
||||
} else {
|
||||
argv[i][4] = data_byte_no + '0'; // undo string termination
|
||||
show_invalid_option(argv[i]);
|
||||
}
|
||||
}
|
||||
// RxCount=F4 or TxCount=3A (Totallength=10)
|
||||
else if ((strlen(argv[i]) == 10) && // 'RxCounter=F4' or 'TxCounter=3A'
|
||||
(argv[i][7] == '=') && // '='
|
||||
((argv[i][8] >= '0' && argv[i][8] <= '9') || (argv[i][8] >= 'A' && argv[i][8] <= 'F')) && // first hexadecimal digit
|
||||
((argv[i][9] >= '0' && argv[i][9] <= '9') || (argv[i][9] >= 'A' && argv[i][9] <= 'F'))) { // second hexadecimal digit
|
||||
unsigned char counter_value = 0;
|
||||
if (argv[i][8] >= 'A') // convert higher digit hexadecimal char to byte
|
||||
counter_value += (argv[i][8] - 'A' + 10) * 16;
|
||||
else
|
||||
counter_value += (argv[i][8] - '0') * 16;
|
||||
if (argv[i][9] >= 'A') // convert lower digit hexadecimal char to byte
|
||||
counter_value += (argv[i][9] - 'A' + 10);
|
||||
else
|
||||
counter_value += (argv[i][9] - '0');
|
||||
argv[i][7] = 0; // terminate string for comparison
|
||||
if (strcasecmp(argv[i], "TxCount") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CNT; // generate TxCounter error
|
||||
frame.data[6] = counter_value; // populate proper data byte
|
||||
} else if (strcasecmp(argv[i], "RxCount") == STR_EQUAL) {
|
||||
frame.can_id |= CAN_ERR_CNT; // generate RxCounter error
|
||||
frame.data[7] = counter_value; // populate proper data byte
|
||||
} else {
|
||||
argv[i][7] = '='; // undo string termination
|
||||
show_invalid_option(argv[i]);
|
||||
}
|
||||
} else if (strcasecmp(argv[i], "ShowBits") == STR_EQUAL) // DEBUG helper
|
||||
show_bits = true; // Display frame as bits
|
||||
else
|
||||
show_invalid_option(argv[i]);
|
||||
}
|
||||
|
||||
if (show_bits == true) {
|
||||
printf("CAN ID = ");
|
||||
print_binary(frame.can_id);
|
||||
printf("\n");
|
||||
// printf("frame.can_dlc = %d\n", frame.can_dlc);
|
||||
printf("CAN Data = ");
|
||||
for (size_t i = 0; i < frame.can_dlc; i++)
|
||||
printf("%02X ", frame.data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// create socket
|
||||
if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
|
||||
err_exit("Error while opening socket\n");
|
||||
|
||||
// set interface name
|
||||
if (strlen(argv[1]) >= IFNAMSIZ)
|
||||
err_exit("Name of CAN device '%s' is too long!\n\n", argv[1]);
|
||||
|
||||
strcpy(ifr.ifr_name, argv[1]); // can0, vcan0...
|
||||
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
|
||||
err_exit("Error setting CAN interface name %s\n", argv[1]);
|
||||
|
||||
// bind socket to the CAN interface
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
err_exit("Error in socket bind\n");
|
||||
|
||||
// Send CAN error frame
|
||||
if (write(sock, &frame, sizeof(frame)) < 0)
|
||||
err_exit("Error writing to socket\n");
|
||||
else
|
||||
printf("CAN error frame sent\n");
|
||||
|
||||
close(sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+1
-1
@@ -157,7 +157,7 @@ static int compare_frame(const struct canfd_frame *exp, const struct canfd_frame
|
||||
} else {
|
||||
for (i = 0; i < rec->len; i++) {
|
||||
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
|
||||
printf("Databyte %x mismatch!\n", i);
|
||||
printf("Databyte 0x%x mismatch!\n", i);
|
||||
print_compare(expected_can_id, exp->data, exp->len,
|
||||
rec->can_id, rec->data, rec->len, inc);
|
||||
running = 0;
|
||||
|
||||
@@ -180,7 +180,7 @@ static void print_usage(char *prg)
|
||||
fprintf(stderr, " -X (generate CAN XL CAN frames)\n");
|
||||
fprintf(stderr, " -R (generate RTR frames)\n");
|
||||
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
|
||||
fprintf(stderr, " -m (mix -e -f -b -E -R -X frames)\n");
|
||||
fprintf(stderr, " -m (mix CC [-e -R] FD [-f -b -E] XL [-X] on capable devices)\n");
|
||||
fprintf(stderr, " -I <mode> (CAN ID generation mode - see below)\n");
|
||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
|
||||
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
||||
@@ -189,6 +189,7 @@ static void print_usage(char *prg)
|
||||
fprintf(stderr, " -A <mode> (CAN XL AF generation mode - see below, no e/o mode)\n");
|
||||
fprintf(stderr, " -V <mode> (CAN XL VCID generation mode - see below, no e/o mode)\n");
|
||||
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
|
||||
fprintf(stderr, " -P <priority> (set socket priority using SO_PRIORITY)\n");
|
||||
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
|
||||
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
|
||||
fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n");
|
||||
@@ -298,7 +299,7 @@ static int setsockopt_txtime(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_send_one(int fd, cu_t *cu, size_t len, int timeout)
|
||||
static int do_send_one(int fd, union cfu *cu, size_t len, int timeout)
|
||||
{
|
||||
uint8_t control[CMSG_SPACE(sizeof(uint64_t))] = { 0 };
|
||||
struct iovec iov = {
|
||||
@@ -338,10 +339,9 @@ resend:
|
||||
nbytes = sendmsg(fd, &msg, 0);
|
||||
if (nbytes < 0) {
|
||||
ret = -errno;
|
||||
if (ret != -ENOBUFS) {
|
||||
perror("write");
|
||||
if (ret != -ENOBUFS)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ignore_enobufs && !timeout) {
|
||||
perror("write");
|
||||
return ret;
|
||||
@@ -454,6 +454,9 @@ int main(int argc, char **argv)
|
||||
unsigned char extended = 0;
|
||||
unsigned char canfd = 0;
|
||||
unsigned char canxl = 0;
|
||||
unsigned char mixcc = 1; /* mix default */
|
||||
unsigned char mixfd = 1; /* mix default */
|
||||
unsigned char mixxl = 1; /* mix default */
|
||||
unsigned char brs = 0;
|
||||
unsigned char esi = 0;
|
||||
unsigned char mix = 0;
|
||||
@@ -479,6 +482,7 @@ int main(int argc, char **argv)
|
||||
uint64_t incdata = 0;
|
||||
__u8 *data; /* base pointer for CC/FD or XL data */
|
||||
int incdlc = 0;
|
||||
int priority = -1;
|
||||
unsigned long rnd;
|
||||
unsigned char fixdata[CANFD_MAX_DLEN];
|
||||
unsigned char rand_position[CANFD_MAX_DLEN] = { 0 };
|
||||
@@ -490,7 +494,7 @@ int main(int argc, char **argv)
|
||||
struct can_raw_vcid_options vcid_opts = {
|
||||
.flags = CAN_RAW_XL_VCID_TX_PASS,
|
||||
};
|
||||
static cu_t cu;
|
||||
static union cfu cu;
|
||||
int i;
|
||||
struct ifreq ifr = { 0 };
|
||||
const int enable_canfx = 1;
|
||||
@@ -512,7 +516,7 @@ int main(int argc, char **argv)
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:n:ixc:vh?", long_options, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:P:n:ixc:vh?", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'g':
|
||||
gap = strtod(optarg, NULL);
|
||||
@@ -572,7 +576,6 @@ int main(int argc, char **argv)
|
||||
|
||||
case 'm':
|
||||
mix = 1;
|
||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||
view |= CANLIB_VIEW_INDENT_SFF;
|
||||
break;
|
||||
|
||||
@@ -682,6 +685,14 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
priority = atoi(optarg);
|
||||
if (priority < 0) {
|
||||
printf("socket priority has to be >= 0\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
ignore_enobufs = true;
|
||||
break;
|
||||
@@ -750,6 +761,16 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
||||
|
||||
/*
|
||||
* user can use tc to configure the queuing discipline (e.g. mqprio),
|
||||
* together with SO_PRIORITY option to specify the message send from
|
||||
* this socket should go to which queue.
|
||||
*/
|
||||
if (priority >= 0 &&
|
||||
setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority))) {
|
||||
printf("error setting SO_PRIORITY\n");
|
||||
}
|
||||
|
||||
if (loopback_disable) {
|
||||
const int loopback = 0;
|
||||
|
||||
@@ -757,14 +778,58 @@ int main(int argc, char **argv)
|
||||
&loopback, sizeof(loopback));
|
||||
}
|
||||
|
||||
if (canfd || canxl) {
|
||||
/* get CAN netdevice MTU for frame type capabilities */
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||
perror("SIOCGIFMTU");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check if the frame fits into the CAN netdevice */
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||
perror("SIOCGIFMTU");
|
||||
/* check CAN XL support */
|
||||
if (ifr.ifr_mtu < (int)CANXL_MIN_MTU) {
|
||||
mixxl = 0;
|
||||
if (canxl) {
|
||||
printf("CAN interface not CAN XL capable - sorry.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* check CAN FD support */
|
||||
if (ifr.ifr_mtu < (int)CANFD_MTU) {
|
||||
mixfd = 0;
|
||||
if (canfd) {
|
||||
printf("CAN interface not CAN FD capable - sorry.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable CAN FD on the socket */
|
||||
if (mixfd) {
|
||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||
&enable_canfx, sizeof(enable_canfx))){
|
||||
printf("error when enabling CAN FD support\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable CAN XL on the socket */
|
||||
if (mixxl) {
|
||||
/* interface is ok - try to switch the socket into CAN XL mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES,
|
||||
&enable_canfx, sizeof(enable_canfx))){
|
||||
printf("error when enabling CAN XL support\n");
|
||||
return 1;
|
||||
}
|
||||
/* try to enable the CAN XL VCID pass through mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS,
|
||||
&vcid_opts, sizeof(vcid_opts))) {
|
||||
printf("error when enabling CAN XL VCID pass through\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanitize given values */
|
||||
if (canfd || canxl) {
|
||||
if (canfd) {
|
||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
||||
cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len));
|
||||
@@ -773,41 +838,6 @@ int main(int argc, char **argv)
|
||||
if (cu.fd.len > CANFD_MAX_DLEN)
|
||||
cu.fd.len = CANFD_MAX_DLEN;
|
||||
}
|
||||
|
||||
if (canxl && (ifr.ifr_mtu < (int)CANXL_MIN_MTU)) {
|
||||
printf("CAN interface not CAN XL capable - sorry.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (canfd && (ifr.ifr_mtu < (int)CANFD_MTU)) {
|
||||
printf("CAN interface not CAN FD capable - sorry.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ifr.ifr_mtu == (int)CANFD_MTU) {
|
||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||
&enable_canfx, sizeof(enable_canfx))){
|
||||
printf("error when enabling CAN FD support\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU) {
|
||||
/* interface is ok - try to switch the socket into CAN XL mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES,
|
||||
&enable_canfx, sizeof(enable_canfx))){
|
||||
printf("error when enabling CAN XL support\n");
|
||||
return 1;
|
||||
}
|
||||
/* try to enable the CAN XL VCID pass through mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS,
|
||||
&vcid_opts, sizeof(vcid_opts))) {
|
||||
printf("error when enabling CAN XL VCID pass through\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* sanitize Classical CAN 2.0 frame length */
|
||||
if (len8_dlc) {
|
||||
@@ -967,12 +997,12 @@ int main(int argc, char **argv)
|
||||
rnd = random();
|
||||
|
||||
if (xl_flags_mode == MODE_RANDOM) {
|
||||
cu.xl.flags = rnd & CANXL_SEC;
|
||||
cu.xl.flags = rnd & (CANXL_SEC | CANXL_RRS);
|
||||
} else if (xl_flags_mode == MODE_FIX) {
|
||||
cu.xl.flags = xl_flags;
|
||||
} else if (xl_flags_mode == MODE_INCREMENT) {
|
||||
xl_flags ^= CANXL_SEC;
|
||||
cu.xl.flags = (xl_flags & CANXL_SEC);
|
||||
xl_flags++;
|
||||
cu.xl.flags = (xl_flags & (CANXL_SEC | CANXL_RRS));
|
||||
}
|
||||
|
||||
/* mark CAN XL frame */
|
||||
@@ -1020,8 +1050,31 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
ret = do_send_one(s, &cu, mtu, polltimeout);
|
||||
if (ret)
|
||||
if ((ret == -EINVAL) && mix) {
|
||||
/* mix mode: disable unsupported CAN frame type */
|
||||
switch (mtu) {
|
||||
case CAN_MTU:
|
||||
mixcc = 0;
|
||||
break;
|
||||
case CANFD_MTU:
|
||||
mixfd = 0;
|
||||
break;
|
||||
case CANXL_MTU:
|
||||
mixxl = 0;
|
||||
break;
|
||||
default:
|
||||
printf ("mix mode: unknown MTU");
|
||||
return 1;
|
||||
}
|
||||
if (!mixcc && !mixfd && !mixxl) {
|
||||
printf ("mix mode: no valid CAN frame types\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (ret) {
|
||||
/* other error than -ENOBUFS and -EINVAL */
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (burst_sent_count >= burst_count)
|
||||
burst_sent_count = 0;
|
||||
@@ -1062,18 +1115,41 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (mix) {
|
||||
canfd = 0;
|
||||
canxl = 0;
|
||||
i = random();
|
||||
extended = i & 1;
|
||||
canfd = i & 2;
|
||||
if (canfd) {
|
||||
brs = i & 4;
|
||||
esi = i & 8;
|
||||
if (mixfd) {
|
||||
canfd = i & 2;
|
||||
if (canfd) {
|
||||
brs = i & 4;
|
||||
esi = i & 8;
|
||||
}
|
||||
}
|
||||
if (mixxl) {
|
||||
if (mixfd)
|
||||
canxl = ((i & 96) == 96); /* 1/4 */
|
||||
else
|
||||
canxl = ((i & 32) == 32); /* 1/2 */
|
||||
}
|
||||
if (mixcc) {
|
||||
rtr_frame = ((i & 24) == 24); /* reduce RTR to 1/4 */
|
||||
} else {
|
||||
/* no CC frames allowed - CAN XL-only mode? */
|
||||
if (!canxl && !canfd) {
|
||||
/* force XL or FD frames */
|
||||
if (mixxl)
|
||||
canxl = 1;
|
||||
else if (mixfd) {
|
||||
canfd = 1;
|
||||
brs = i & 4;
|
||||
esi = i & 8;
|
||||
} else {
|
||||
printf ("mix mode: no valid CAN frame types\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* generate CAN XL traffic if the interface is capable */
|
||||
if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU)
|
||||
canxl = ((i & 96) == 96);
|
||||
|
||||
rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-6
@@ -177,7 +177,8 @@ int main(int argc, char **argv)
|
||||
sigset_t sigset;
|
||||
fd_set rdfs;
|
||||
int s[MAXDEV];
|
||||
int socki, accsocket;
|
||||
int socki;
|
||||
int accsocket = -1;
|
||||
canid_t mask[MAXDEV] = {0};
|
||||
canid_t value[MAXDEV] = {0};
|
||||
int inv_filter[MAXDEV] = {0};
|
||||
@@ -191,7 +192,7 @@ int main(int argc, char **argv)
|
||||
.rx_vcid_mask = 0,
|
||||
};
|
||||
struct can_filter rfilter;
|
||||
static cu_t cu; /* union for CAN CC/FD/XL frames */
|
||||
static union cfu cu; /* union for CAN CC/FD/XL frames */
|
||||
const int canfx_on = 1;
|
||||
int nbytes, i, j;
|
||||
struct ifreq ifr;
|
||||
@@ -286,7 +287,7 @@ int main(int argc, char **argv)
|
||||
inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
inaddr.sin_port = htons(port);
|
||||
|
||||
while(bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) {
|
||||
while(running && bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
@@ -295,18 +296,28 @@ int main(int argc, char **argv)
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if loop exited due to signal (during nanosleep) rather than
|
||||
* successful bind.
|
||||
*/
|
||||
if (!running) {
|
||||
close(socki);
|
||||
return 128 + signal_num;
|
||||
}
|
||||
|
||||
if (listen(socki, 3) != 0) {
|
||||
perror("listen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(1) {
|
||||
while(running) {
|
||||
accsocket = accept(socki, (struct sockaddr*)&clientaddr, &sin_size);
|
||||
if (accsocket > 0) {
|
||||
//printf("accepted\n");
|
||||
if (!fork())
|
||||
break;
|
||||
close(accsocket);
|
||||
accsocket = -1;
|
||||
}
|
||||
else if (errno != EINTR) {
|
||||
perror("accept");
|
||||
@@ -314,11 +325,22 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if loop exited due to signal (accept returned EINTR) rather
|
||||
* than successful fork
|
||||
*/
|
||||
if (!running) {
|
||||
if (accsocket > 0)
|
||||
close(accsocket);
|
||||
close(socki);
|
||||
return 128 + signal_num;
|
||||
}
|
||||
|
||||
for (i=0; i<currmax; i++) {
|
||||
|
||||
pr_debug("open %d '%s' m%08X v%08X i%d e%d.\n",
|
||||
i, argv[optind+i], mask[i], value[i],
|
||||
inv_filter[i], err_mask[i]);
|
||||
i, argv[optind+i], mask[i], value[i],
|
||||
inv_filter[i], err_mask[i]);
|
||||
|
||||
if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
perror("socket");
|
||||
|
||||
+27
-60
@@ -48,7 +48,6 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -69,7 +68,7 @@
|
||||
#endif
|
||||
|
||||
#define DEVSZ 22 /* IFNAMSZ + 6 */
|
||||
#define TIMESZ sizeof("(1345212884.318850) ")
|
||||
#define TIMESZ sizeof("(1345212884.318850123) ")
|
||||
#define BUFSZ (TIMESZ + DEVSZ + AFRSZ)
|
||||
|
||||
/* adapt sscanf() functions below on error */
|
||||
@@ -90,12 +89,6 @@ const int canfx_on = 1;
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
struct sleep {
|
||||
struct timeval *sleep_vector;
|
||||
size_t idx;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - replay a compact CAN frame logfile to CAN devices.\n", prg);
|
||||
@@ -124,8 +117,6 @@ static void print_usage(char *prg)
|
||||
"loopback of sent CAN frames)\n");
|
||||
fprintf(stderr, " -v (verbose: print "
|
||||
"sent CAN frames)\n");
|
||||
fprintf(stderr, " -r (real-time: send "
|
||||
"CAN frames in real-time)\n");
|
||||
fprintf(stderr, " -h (show "
|
||||
"this help message)\n\n");
|
||||
fprintf(stderr, "Interface assignment:\n");
|
||||
@@ -270,7 +261,7 @@ int main(int argc, char **argv)
|
||||
struct can_raw_vcid_options vcid_opts = {
|
||||
.flags = CAN_RAW_XL_VCID_TX_PASS,
|
||||
};
|
||||
static cu_t cu;
|
||||
static union cfu cu;
|
||||
static struct timeval today_tv, log_tv, last_log_tv, diff_tv;
|
||||
struct timespec sleep_ts;
|
||||
int s; /* CAN_RAW socket */
|
||||
@@ -289,11 +280,8 @@ int main(int argc, char **argv)
|
||||
int eof, txmtu, i, j;
|
||||
char *fret;
|
||||
unsigned long long sec, usec;
|
||||
bool gap_from_file = false;
|
||||
struct sleep timestamps;
|
||||
struct timeval send_time, act_time, init_trace, init_time;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:l:tin:g:s:xvrh")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:l:tin:g:s:xvh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -348,17 +336,6 @@ int main(int argc, char **argv)
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
if (isatty(fileno(infile))) {
|
||||
fprintf(stderr, "Specify an input file for option -r !\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
gap_from_file = true; /* using time delta from file */
|
||||
init_trace.tv_sec = 0;
|
||||
init_trace.tv_usec = 0;
|
||||
timestamps.idx = 0; /*to avoid warning accessing idx variable*/
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
@@ -391,10 +368,8 @@ int main(int argc, char **argv)
|
||||
printf("interactive mode: press ENTER to process next CAN frame ...\n");
|
||||
}
|
||||
|
||||
if (!gap_from_file) {
|
||||
sleep_ts.tv_sec = gap / 1000;
|
||||
sleep_ts.tv_nsec = (gap % 1000) * 1000000;
|
||||
}
|
||||
sleep_ts.tv_sec = gap / 1000;
|
||||
sleep_ts.tv_nsec = (gap % 1000) * 1000000;
|
||||
|
||||
/* open socket */
|
||||
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
@@ -477,14 +452,20 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
log_tv.tv_sec = sec;
|
||||
log_tv.tv_usec = usec;
|
||||
|
||||
/*
|
||||
* ensure the fractions of seconds are 6 decimal places long to catch
|
||||
* ensure the fractions of seconds are 6 or 9 decimal places long to catch
|
||||
* 3rd party or handcrafted logfiles that treat the timestamp as float
|
||||
*/
|
||||
if (strchr(buf, ')') - strchr(buf, '.') != 7) {
|
||||
fprintf(stderr, "timestamp format in logfile requires 6 decimal places\n");
|
||||
switch (strchr(buf, ')') - strchr(buf, '.')) {
|
||||
case 7: //6
|
||||
log_tv.tv_usec = usec;
|
||||
break;
|
||||
case 10: //9
|
||||
log_tv.tv_usec = usec / 1000;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "timestamp format in logfile requires 6 or 9 decimal places\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -566,39 +547,25 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, device, afrbuf) != 4) {
|
||||
if (sscanf(buf, "(%llu.%llu) %21s %6299s", &sec, &usec, device, afrbuf) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
}
|
||||
log_tv.tv_sec = sec;
|
||||
log_tv.tv_usec = usec;
|
||||
|
||||
if (gap_from_file){
|
||||
if (timestamps.idx == 0){
|
||||
gettimeofday(&init_time, NULL);
|
||||
if (log_tv.tv_sec > 0 || log_tv.tv_usec > 0)
|
||||
init_trace = log_tv;
|
||||
}
|
||||
timersub(&log_tv, &init_trace, &send_time);
|
||||
|
||||
if (timestamps.idx > 0){
|
||||
gettimeofday(&act_time, NULL);
|
||||
timersub(&act_time, &init_time, &act_time);
|
||||
|
||||
while (timercmp(&act_time, &send_time, <)){
|
||||
gettimeofday(&act_time, NULL);
|
||||
timersub(&act_time, &init_time, &act_time);
|
||||
}
|
||||
}
|
||||
timestamps.idx++;
|
||||
}
|
||||
|
||||
/*
|
||||
* ensure the fractions of seconds are 6 decimal places long to catch
|
||||
* ensure the fractions of seconds are 6 or 9 decimal places long to catch
|
||||
* 3rd party or handcrafted logfiles that treat the timestamp as float
|
||||
*/
|
||||
if (strchr(buf, ')') - strchr(buf, '.') != 7) {
|
||||
fprintf(stderr, "timestamp format in logfile requires 6 decimal places\n");
|
||||
switch (strchr(buf, ')') - strchr(buf, '.')) {
|
||||
case 7: //6
|
||||
log_tv.tv_usec = usec;
|
||||
break;
|
||||
case 10: //9
|
||||
log_tv.tv_usec = usec / 1000;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "timestamp format in logfile requires 6 or 9 decimal places\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -615,7 +582,7 @@ int main(int argc, char **argv)
|
||||
|
||||
} /* while frames_to_send ... */
|
||||
|
||||
if (!gap_from_file && nanosleep(&sleep_ts, NULL))
|
||||
if (nanosleep(&sleep_ts, NULL))
|
||||
return 1;
|
||||
|
||||
delay_loops++; /* private statistics */
|
||||
|
||||
@@ -80,7 +80,10 @@ static void print_usage(char *prg)
|
||||
"_{dlc}:\n"
|
||||
" an optional 9..F data length code value when payload length is 8\n"
|
||||
"<flags>:\n"
|
||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n"
|
||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags:\n"
|
||||
" %x CANFD_BRS\n"
|
||||
" %x CANFD_ESI\n"
|
||||
" %x CANFD_FDF\n"
|
||||
"\n"
|
||||
"<vcid>:\n"
|
||||
" 2 hex chars - virtual CAN network identifier (00 .. FF)\n"
|
||||
@@ -100,7 +103,8 @@ static void print_usage(char *prg)
|
||||
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n"
|
||||
" 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n"
|
||||
"\n",
|
||||
prg, prg);
|
||||
prg, prg,
|
||||
CANFD_BRS, CANFD_ESI, CANFD_FDF);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -113,7 +117,7 @@ int main(int argc, char **argv)
|
||||
struct can_raw_vcid_options vcid_opts = {
|
||||
.flags = CAN_RAW_XL_VCID_TX_PASS,
|
||||
};
|
||||
static cu_t cu;
|
||||
static union cfu cu;
|
||||
struct ifreq ifr;
|
||||
|
||||
/* check command line options */
|
||||
|
||||
+11
-11
@@ -161,15 +161,15 @@ void switchvdl(char *delim)
|
||||
|
||||
int comp(const void *elem1, const void *elem2)
|
||||
{
|
||||
unsigned long f = ((struct snif*)elem1)->current.can_id;
|
||||
unsigned long s = ((struct snif*)elem2)->current.can_id;
|
||||
unsigned long f = ((struct snif*)elem1)->current.can_id;
|
||||
unsigned long s = ((struct snif*)elem2)->current.can_id;
|
||||
|
||||
if (f > s)
|
||||
return 1;
|
||||
if (f < s)
|
||||
return -1;
|
||||
if (f > s)
|
||||
return 1;
|
||||
if (f < s)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_usage(char *prg)
|
||||
@@ -741,10 +741,10 @@ int handle_timeo(long currcms)
|
||||
do_clr(i, UPDATE);
|
||||
}
|
||||
else if ((sniftab[i].hold) && (sniftab[i].hold < currcms)) {
|
||||
memset(&sniftab[i].marker.data, 0, max_dlen);
|
||||
print_snifline(i);
|
||||
sniftab[i].hold = 0; /* disable update by hold */
|
||||
}
|
||||
memset(&sniftab[i].marker.data, 0, max_dlen);
|
||||
print_snifline(i);
|
||||
sniftab[i].hold = 0; /* disable update by hold */
|
||||
}
|
||||
else
|
||||
printf("%s", CSR_DOWN); /* skip my line */
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
|
||||
@@ -0,0 +1,5 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
|
||||
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
|
||||
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
|
||||
@@ -0,0 +1,5 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
|
||||
@@ -0,0 +1,5 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
|
||||
+24
-19
@@ -1,19 +1,24 @@
|
||||
|
||||
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
endif()
|
||||
|
||||
file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "[\r\n]" ";" files "${files}")
|
||||
|
||||
foreach(file ${files})
|
||||
message(STATUS "Uninstalling ${file}")
|
||||
if(EXISTS "${file}")
|
||||
file(REMOVE ${file})
|
||||
if (EXISTS "${file}")
|
||||
message(FATAL_ERROR "Problem when removing ${file}, please check your permissions")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "File ${file} does not exist.")
|
||||
endif()
|
||||
endforeach()
|
||||
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
message(FATAL_ERROR
|
||||
"Cannot find install manifest: \
|
||||
${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt"
|
||||
)
|
||||
endif()
|
||||
|
||||
file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "[\r\n]" ";" files "${files}")
|
||||
|
||||
foreach(file ${files})
|
||||
message(STATUS "Uninstalling ${file}")
|
||||
if(EXISTS "${file}")
|
||||
file(REMOVE ${file})
|
||||
if (EXISTS "${file}")
|
||||
message(
|
||||
FATAL_ERROR "Problem when removing ${file}, \
|
||||
please check your permissions"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "File ${file} does not exist.")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR mips)
|
||||
|
||||
set(CMAKE_C_COMPILER mips-linux-gnu-gcc)
|
||||
set(CMAKE_C_COMPILER_TARGET mips-linux-gnu)
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ([2.59])
|
||||
|
||||
AC_INIT([can-utils],[trunk],[linux-can@vger.kernel.org])
|
||||
AC_CONFIG_SRCDIR([lib.c])
|
||||
AC_CONFIG_MACRO_DIR([config/m4])
|
||||
AC_CONFIG_AUX_DIR([config/autoconf])
|
||||
AC_CANONICAL_BUILD
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
# If possible, enable extensions to Posix
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
#AM_MAINTAINER_MODE
|
||||
|
||||
CFLAGS="${CFLAGS} -Wall"
|
||||
|
||||
#
|
||||
# Checks for programs.
|
||||
#
|
||||
AC_PROG_CC
|
||||
LT_INIT(win32-dll)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2 subdir-objects])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
#
|
||||
# Checks for header files.
|
||||
#
|
||||
AC_CHECK_HEADERS([ \
|
||||
fcntl.h \
|
||||
limits.h \
|
||||
locale.h \
|
||||
stdint.h \
|
||||
stdlib.h \
|
||||
string.h \
|
||||
syslog.h \
|
||||
termios.h \
|
||||
unistd.h \
|
||||
\
|
||||
netinet/in.h \
|
||||
\
|
||||
sys/ioctl.h \
|
||||
sys/socket.h \
|
||||
sys/time.h \
|
||||
])
|
||||
|
||||
|
||||
#
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
#
|
||||
AC_C_INLINE
|
||||
AC_SYS_LARGEFILE
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_UINT64_T
|
||||
|
||||
|
||||
#
|
||||
# Checks for library functions.
|
||||
#
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_MKTIME
|
||||
AC_CHECK_FUNCS([ \
|
||||
alarm \
|
||||
gettimeofday \
|
||||
localtime_r \
|
||||
memset \
|
||||
select \
|
||||
setlocale \
|
||||
socket \
|
||||
strchr \
|
||||
strerror \
|
||||
strstr \
|
||||
strtoul \
|
||||
])
|
||||
|
||||
AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork_works" = "yes")
|
||||
|
||||
# glibc versions before 2.17 needs to link with -lrt for clock_nanosleep
|
||||
AC_SEARCH_LIBS([clock_nanosleep], [rt])
|
||||
|
||||
AC_CHECK_DECL(SO_RXQ_OVFL,,
|
||||
[AC_DEFINE([SO_RXQ_OVFL], [40], [SO_RXQ_OVFL])],
|
||||
[[#include <linux/net.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(PF_CAN,,
|
||||
[AC_DEFINE([PF_CAN], [29], [PF_CAN])],
|
||||
[[#include <net/if.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(AF_CAN,,
|
||||
[AC_DEFINE([AF_CAN], [PF_CAN], [AF_CAN])],
|
||||
[[#include <net/if.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(N_SLCAN,,
|
||||
[AC_DEFINE([N_SLCAN], [17], [N_SLCAN])],
|
||||
[[#include <linux/tty.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(SCM_TIMESTAMPING_OPT_STATS,,
|
||||
[AC_DEFINE([SCM_TIMESTAMPING_OPT_STATS], [54], [SCM_TIMESTAMPING_OPT_STATS])],
|
||||
[[#include <linux/net.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(CLOCK_TAI,,
|
||||
[AC_DEFINE([CLOCK_TAI], [11], [CLOCK_TAI])],
|
||||
[[#include <time.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(SO_TXTIME,,
|
||||
[AC_DEFINE([SO_TXTIME], [61], [SO_TXTIME])],
|
||||
[[#include <sys/socket.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(SCM_TXTIME,,
|
||||
[AC_DEFINE([SCM_TXTIME], [SO_TXTIME], [SCM_TXTIME])],
|
||||
[[#include <sys/socket.h>]]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Debugging
|
||||
#
|
||||
AC_MSG_CHECKING([whether to enable debugging])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AS_HELP_STRING([--enable-debug], [enable debugging [[default=no]]]),
|
||||
[case "$enableval" in
|
||||
(y | yes) CONFIG_DEBUG=yes ;;
|
||||
(*) CONFIG_DEBUG=no ;;
|
||||
esac],
|
||||
[CONFIG_DEBUG=no])
|
||||
AC_MSG_RESULT([${CONFIG_DEBUG}])
|
||||
if test "${CONFIG_DEBUG}" = "yes"; then
|
||||
CFLAGS="${CFLAGS} -Wsign-compare -Wfloat-equal -Wformat-security -g -O1"
|
||||
AC_DEFINE(DEBUG, 1, [debugging])
|
||||
else
|
||||
CFLAGS="${CFLAGS} -O2"
|
||||
fi
|
||||
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
GNUmakefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
+2
-1
@@ -182,7 +182,7 @@ struct canfd_frame {
|
||||
/*
|
||||
* defined bits for canxl_frame.flags
|
||||
*
|
||||
* The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
|
||||
* The canxl_frame.flags element contains three bits CANXL_[XLF|SEC|RRS]
|
||||
* and shares the relative position of the struct can[fd]_frame.len element.
|
||||
* The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
|
||||
* As a side effect setting this bit intentionally breaks the length checks
|
||||
@@ -192,6 +192,7 @@ struct canfd_frame {
|
||||
*/
|
||||
#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
|
||||
#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
|
||||
#define CANXL_RRS 0x02 /* Remote Request Substitution */
|
||||
|
||||
/* the 8-bit VCID is optionally placed in the canxl_frame.prio element */
|
||||
#define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */
|
||||
|
||||
@@ -22,6 +22,8 @@ struct regmap {
|
||||
};
|
||||
|
||||
#define pr_info(...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define pr_err(...) fprintf(stderr, ## __VA_ARGS__)
|
||||
#define pr_warn(...) fprintf(stderr, ## __VA_ARGS__)
|
||||
#define pr_cont(...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define BUILD_BUG_ON(...)
|
||||
|
||||
+23
-23
@@ -288,8 +288,8 @@ static int isobusfs_cli_handle_events(struct isobusfs_priv *priv, unsigned int n
|
||||
};
|
||||
|
||||
ret = isobusfs_recv_err(priv->sock_ccm, &emsg);
|
||||
if (ret && ret != -EINTR)
|
||||
return ret;
|
||||
if (ret)
|
||||
pr_warn("error queue reported error: %i", ret);
|
||||
}
|
||||
} else if (ev->data.fd == STDIN_FILENO) {
|
||||
if (!priv->interactive) {
|
||||
@@ -336,7 +336,7 @@ int isobusfs_cli_process_events_and_tasks(struct isobusfs_priv *priv)
|
||||
if (priv->state == ISOBUSFS_CLI_STATE_SELFTEST)
|
||||
dont_wait = true;
|
||||
|
||||
ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, dont_wait);
|
||||
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, dont_wait);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -354,7 +354,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -362,7 +362,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
|
||||
|
||||
/* TODO: this is TX only socket */
|
||||
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_main, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_main, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -370,7 +370,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT);
|
||||
ret = libj1939_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -378,7 +378,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_main, EPOLLIN);
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ static int isobusfs_cli_sock_int_prepare(struct isobusfs_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
STDIN_FILENO, EPOLLIN);
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -419,7 +419,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
|
||||
|
||||
/* TODO: this is TX only socket */
|
||||
addr.can_addr.j1939.pgn = J1939_NO_PGN;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_ccm, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_ccm, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -427,7 +427,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT);
|
||||
ret = libj1939_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -436,7 +436,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
|
||||
return ret;
|
||||
|
||||
/* poll for errors to get confirmation if our packets are send */
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm,
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm,
|
||||
EPOLLERR);
|
||||
}
|
||||
|
||||
@@ -445,23 +445,23 @@ static int isobusfs_cli_sock_nack_prepare(struct isobusfs_priv *priv)
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->sock_nack = ret;
|
||||
|
||||
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_nack, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
|
||||
ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* poll for errors to get confirmation if our packets are send */
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_nack, EPOLLIN);
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -481,11 +481,11 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
|
||||
addr.can_addr.j1939.name = J1939_NO_NAME;
|
||||
addr.can_addr.j1939.addr = J1939_NO_ADDR;
|
||||
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_bcast_rx, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_bcast_rx, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_set_broadcast(priv->sock_bcast_rx);
|
||||
ret = libj1939_set_broadcast(priv->sock_bcast_rx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -493,7 +493,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx,
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx,
|
||||
EPOLLIN);
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ static int isobusfs_cli_sock_prepare(struct isobusfs_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_create_epoll();
|
||||
ret = libj1939_create_epoll();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -647,8 +647,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
bzero(priv, sizeof(*priv));
|
||||
|
||||
isobusfs_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
|
||||
isobusfs_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS);
|
||||
libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
|
||||
libj1939_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS);
|
||||
|
||||
ret = isobusfs_cli_parse_args(priv, argc, argv);
|
||||
if (ret)
|
||||
|
||||
@@ -103,7 +103,7 @@ struct isobusfs_priv {
|
||||
struct isobusfs_buf_log tx_buf_log;
|
||||
enum isobusfs_cli_state state;
|
||||
|
||||
struct isobusfs_cmn cmn;
|
||||
struct libj1939_cmn cmn;
|
||||
uint8_t handle;
|
||||
|
||||
uint32_t read_offset;
|
||||
|
||||
@@ -1077,7 +1077,7 @@ int isobusfs_cli_interactive(struct isobusfs_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
pr_int("unknown comand\n");
|
||||
pr_int("unknown command\n");
|
||||
isobusfs_cli_promt(priv);
|
||||
} else {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
|
||||
@@ -211,7 +211,7 @@ static struct isobusfs_cli_test_dir_path test_dir_patterns[] = {
|
||||
{ "~tilde_dir", true },
|
||||
/* expected result \\vol1\dir1\~\ */
|
||||
{ "\\\\vol1\\dir1\\~", true },
|
||||
/* expected result \\vol1\~\ not clear if it is manufacture speficic dir */
|
||||
/* expected result \\vol1\~\ not clear if it is manufacture specific dir */
|
||||
{ "\\~\\", true },
|
||||
/* expected result \\~\ */
|
||||
{ "\\\\~\\", false },
|
||||
|
||||
+5
-190
@@ -101,7 +101,7 @@ void isobusfs_log(log_level_t level, const char *fmt, ...)
|
||||
va_end(args);
|
||||
|
||||
snprintf(complete_log_entry, sizeof(complete_log_entry),
|
||||
"[%s] [%s]: %s", time_buffer, level_str, log_entry);
|
||||
"[%.40s] [%.10s]: %.150s", time_buffer, level_str, log_entry);
|
||||
|
||||
if (interactive_mode) {
|
||||
add_log_to_buffer(complete_log_entry);
|
||||
@@ -125,29 +125,6 @@ void isobusfs_log_level_set(log_level_t level)
|
||||
log_level = level;
|
||||
}
|
||||
|
||||
int isobusfs_get_timeout_ms(struct timespec *ts)
|
||||
{
|
||||
struct timespec curr_time;
|
||||
int64_t time_diff;
|
||||
int timeout_ms;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &curr_time);
|
||||
time_diff = timespec_diff_ms(ts, &curr_time);
|
||||
if (time_diff < 0) {
|
||||
/* Too late to send next message. Send it now */
|
||||
timeout_ms = 0;
|
||||
} else {
|
||||
if (time_diff > INT_MAX) {
|
||||
warn("timeout too long: %" PRId64 " ms", time_diff);
|
||||
time_diff = INT_MAX;
|
||||
}
|
||||
|
||||
timeout_ms = time_diff;
|
||||
}
|
||||
|
||||
return timeout_ms;
|
||||
}
|
||||
|
||||
const char *isobusfs_error_to_str(enum isobusfs_error err)
|
||||
{
|
||||
switch (err) {
|
||||
@@ -238,15 +215,6 @@ enum isobusfs_error linux_error_to_isobusfs_error(int linux_err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn)
|
||||
{
|
||||
sac->can_family = AF_CAN;
|
||||
sac->can_addr.j1939.addr = J1939_NO_ADDR;
|
||||
sac->can_addr.j1939.name = J1939_NO_NAME;
|
||||
sac->can_addr.j1939.pgn = pgn;
|
||||
}
|
||||
|
||||
static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg,
|
||||
const char *name, struct timespec *cur)
|
||||
{
|
||||
@@ -258,9 +226,9 @@ static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg,
|
||||
if (!(cur->tv_sec | cur->tv_nsec))
|
||||
return;
|
||||
|
||||
fprintf(stderr, " %s: %lu s %lu us (seq=%u/%u, send=%u)",
|
||||
name, cur->tv_sec, cur->tv_nsec / 1000,
|
||||
stats->tskey_sch, stats->tskey_ack, stats->send);
|
||||
fprintf(stderr, " %s: %llu s %llu us (seq=%u/%u, send=%u)",
|
||||
name, (unsigned long long)cur->tv_sec, (unsigned long long)cur->tv_nsec / 1000,
|
||||
stats->tskey_sch, stats->tskey_ack, stats->send);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -520,28 +488,6 @@ int isobusfs_send(int sock, const void *data, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* isobusfs_cmn_open_socket - Open a CAN J1939 socket
|
||||
*
|
||||
* This function opens a CAN J1939 socket and returns the file descriptor
|
||||
* on success. In case of an error, the function returns the negative
|
||||
* error code.
|
||||
*/
|
||||
int isobusfs_cmn_open_socket(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Create a new CAN J1939 socket */
|
||||
ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
|
||||
if (ret < 0) {
|
||||
/* Get the error code and print an error message */
|
||||
ret = -errno;
|
||||
pr_err("socket(j1939): %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* isobusfs_cmn_configure_socket_filter - Configure a J1939 socket filter
|
||||
* @sock: Socket file descriptor
|
||||
@@ -650,47 +596,6 @@ int isobusfs_cmn_configure_error_queue(int sock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* isobusfs_cmn_bind_socket - Bind a J1939 socket to a given address
|
||||
* @sock: socket file descriptor
|
||||
* @addr: pointer to a sockaddr_can structure containing the address
|
||||
* information to bind the socket to
|
||||
*
|
||||
* This function binds a J1939 socket to the specified address. It returns
|
||||
* 0 on successful binding or a negative error code on failure.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bind(sock, (void *)addr, sizeof(*addr));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("failed to bind: %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isobusfs_cmn_socket_prio(int sock, int prio)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
|
||||
&prio, sizeof(prio));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
|
||||
{
|
||||
int ret;
|
||||
@@ -705,34 +610,8 @@ int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* isobusfs_cmn_set_broadcast - Enable broadcast option for a socket
|
||||
* @sock: socket file descriptor
|
||||
*
|
||||
* This function enables the SO_BROADCAST option for the given socket,
|
||||
* allowing it to send and receive broadcast messages. It returns 0 on success
|
||||
* or a negative error code on failure.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int isobusfs_cmn_set_broadcast(int sock)
|
||||
{
|
||||
int broadcast = true;
|
||||
int ret;
|
||||
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
|
||||
sizeof(broadcast));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: linger is currently not supported by the kernel J1939 stack
|
||||
* but it would be nice to have it. Especially if we wont to stop sending
|
||||
* but it would be nice to have it. Especially if we won't to stop sending
|
||||
* messages on a socket when the connection is lost.
|
||||
*/
|
||||
int isobusfs_cmn_set_linger(int sock)
|
||||
@@ -753,70 +632,6 @@ int isobusfs_cmn_set_linger(int sock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events)
|
||||
{
|
||||
struct epoll_event ev = {0};
|
||||
int ret;
|
||||
|
||||
ev.events = events;
|
||||
ev.data.fd = sock;
|
||||
|
||||
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
|
||||
if (ret < 0) {
|
||||
ret = errno;
|
||||
pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isobusfs_cmn_create_epoll(void)
|
||||
{
|
||||
int ret, epoll_fd;
|
||||
|
||||
epoll_fd = epoll_create1(0);
|
||||
if (epoll_fd < 0) {
|
||||
ret = -errno;
|
||||
pr_err("epoll_create1: %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return epoll_fd;
|
||||
}
|
||||
|
||||
int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds,
|
||||
bool dont_wait)
|
||||
{
|
||||
int ret, timeout_ms;
|
||||
|
||||
if (dont_wait)
|
||||
timeout_ms = 0;
|
||||
else
|
||||
timeout_ms = isobusfs_get_timeout_ms(&cmn->next_send_time);
|
||||
|
||||
ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events,
|
||||
cmn->epoll_events_size, timeout_ms);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
if (ret != -EINTR) {
|
||||
*nfds = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*nfds = ret;
|
||||
|
||||
ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("failed to get time: %i (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
|
||||
size_t x)
|
||||
{
|
||||
|
||||
@@ -257,15 +257,6 @@ struct isobusfs_err_msg {
|
||||
struct isobusfs_stats *stats;
|
||||
};
|
||||
|
||||
struct isobusfs_cmn {
|
||||
int epoll_fd;
|
||||
struct epoll_event *epoll_events;
|
||||
size_t epoll_events_size;
|
||||
struct timespec next_send_time;
|
||||
struct timespec last_time;
|
||||
};
|
||||
|
||||
void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
|
||||
int isobusfs_recv_err(int sock, struct isobusfs_err_msg *emsg);
|
||||
|
||||
/*
|
||||
@@ -300,7 +291,6 @@ static inline uint8_t isobusfs_cg_function_to_buf(enum isobusfs_cg cg,
|
||||
const char *isobusfs_error_to_str(enum isobusfs_error err);
|
||||
enum isobusfs_error linux_error_to_isobusfs_error(int linux_err);
|
||||
|
||||
int isobusfs_get_timeout_ms(struct timespec *ts);
|
||||
void isobusfs_send_nack(int sock, struct isobusfs_msg *msg);
|
||||
void isobufs_store_tx_data(struct isobusfs_buf_log *buffer, uint8_t *data);
|
||||
void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer);
|
||||
@@ -313,20 +303,11 @@ int isobusfs_send(int sock, const void *data, size_t len,
|
||||
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
|
||||
size_t x);
|
||||
|
||||
int isobusfs_cmn_open_socket(void);
|
||||
int isobusfs_cmn_configure_socket_filter(int sock, pgn_t pgn);
|
||||
int isobusfs_cmn_configure_error_queue(int sock);
|
||||
int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr);
|
||||
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr);
|
||||
int isobusfs_cmn_set_broadcast(int sock);
|
||||
int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);
|
||||
int isobusfs_cmn_create_epoll(void);
|
||||
int isobusfs_cmn_socket_prio(int sock, int prio);
|
||||
int isobusfs_cmn_set_linger(int sock);
|
||||
|
||||
int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds,
|
||||
bool dont_wait);
|
||||
|
||||
/* ============ directory handling ============ */
|
||||
int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable)
|
||||
ret = access(path, mode);
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
pr_err("failed to acces path %s, for read %s. %s", path,
|
||||
pr_err("failed to access path %s, for read %s. %s", path,
|
||||
writable ? "and write" : "", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
+22
-22
@@ -70,7 +70,7 @@ static int isobusfs_srv_rx_fs(struct isobusfs_srv_priv *priv,
|
||||
cg);
|
||||
|
||||
/* ISO 11783-13:2021 - Annex C.1.1 Overview:
|
||||
* If a client sends a command, which is not defined withing this
|
||||
* If a client sends a command, which is not defined within this
|
||||
* documentation, the file server shall respond with a
|
||||
* NACK (ISO 11783-3:2018 Chapter 5.4.5)
|
||||
*/
|
||||
@@ -221,8 +221,8 @@ static int isobusfs_srv_handle_events(struct isobusfs_srv_priv *priv, unsigned i
|
||||
};
|
||||
|
||||
ret = isobusfs_recv_err(priv->sock_fss, &emsg);
|
||||
if (ret && ret != -EINTR)
|
||||
return ret;
|
||||
if (ret)
|
||||
pr_warn("error queue reported error: %i", ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ static int isobusfs_srv_process_events_and_tasks(struct isobusfs_srv_priv *priv)
|
||||
{
|
||||
int ret, nfds;
|
||||
|
||||
ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, false);
|
||||
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -268,7 +268,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
|
||||
struct sockaddr_can addr = priv->addr;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -279,15 +279,15 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
|
||||
return ret;
|
||||
|
||||
/* keep address and name and overwrite PGN */
|
||||
/* TOOD: actually, this is PGN input filter. Should we use different
|
||||
/* TODO: actually, this is PGN input filter. Should we use different
|
||||
* PGN?
|
||||
*/
|
||||
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_fss, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_fss, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_set_broadcast(priv->sock_fss);
|
||||
ret = libj1939_set_broadcast(priv->sock_fss);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -295,7 +295,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS);
|
||||
ret = libj1939_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -308,7 +308,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
|
||||
return ret;
|
||||
|
||||
/* poll for errors to get confirmation if our packets are send */
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss,
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss,
|
||||
EPOLLERR);
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv)
|
||||
struct sockaddr_can addr = priv->addr;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -325,12 +325,12 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv)
|
||||
|
||||
/* keep address and name and overwrite PGN */
|
||||
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_in, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_in, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in,
|
||||
EPOLLIN);
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in,
|
||||
EPOLLIN);
|
||||
}
|
||||
|
||||
static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv)
|
||||
@@ -338,24 +338,24 @@ static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv)
|
||||
struct sockaddr_can addr = priv->addr;
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->sock_nack = ret;
|
||||
|
||||
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
|
||||
ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr);
|
||||
ret = libj1939_bind_socket(priv->sock_nack, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
|
||||
ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* poll for errors to get confirmation if our packets are send */
|
||||
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_nack, EPOLLIN);
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_nack, EPOLLIN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,7 +370,7 @@ static int isobusfs_srv_sock_prepare(struct isobusfs_srv_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = isobusfs_cmn_create_epoll();
|
||||
ret = libj1939_create_epoll();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -720,7 +720,7 @@ static int isobusfs_srv_parse_args(struct isobusfs_srv_priv *priv, int argc,
|
||||
}
|
||||
|
||||
if (!local_name_set)
|
||||
pr_warn("local name is not set. Wont be able to generate proper manufacturer-specific directory name. Falling mack to MCMC0000");
|
||||
pr_warn("local name is not set. Won't be able to generate proper manufacturer-specific directory name. Falling mack to MCMC0000");
|
||||
isobusfs_srv_generate_mfs_dir_name(priv);
|
||||
|
||||
pr_debug("Server configuration:");
|
||||
@@ -762,7 +762,7 @@ int main(int argc, char *argv[])
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
/* Initialize sockaddr_can with a non-configurable PGN */
|
||||
isobusfs_init_sockaddr_can(&priv->addr, J1939_NO_PGN);
|
||||
libj1939_init_sockaddr_can(&priv->addr, J1939_NO_PGN);
|
||||
|
||||
priv->server_version = ISOBUSFS_SRV_VERSION;
|
||||
/* Parse command line arguments */
|
||||
|
||||
@@ -103,7 +103,7 @@ struct isobusfs_srv_priv {
|
||||
int clients_count;
|
||||
struct isobusfs_buf_log tx_buf_log;
|
||||
|
||||
struct isobusfs_cmn cmn;
|
||||
struct libj1939_cmn cmn;
|
||||
|
||||
struct isobusfs_srv_volume volumes[ISOBUSFS_SRV_MAX_VOLUMES];
|
||||
int volume_count;
|
||||
|
||||
+20
-12
@@ -213,14 +213,14 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = isobusfs_cmn_open_socket();
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
client->sock = ret;
|
||||
|
||||
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
|
||||
ret = isobusfs_cmn_bind_socket(client->sock, &addr);
|
||||
ret = libj1939_bind_socket(client->sock, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -243,7 +243,7 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv,
|
||||
goto close_socket;
|
||||
}
|
||||
|
||||
ret = isobusfs_cmn_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT);
|
||||
ret = libj1939_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -464,15 +464,17 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
|
||||
struct isobusfs_cm_vol_stat_req *req =
|
||||
(struct isobusfs_cm_vol_stat_req *)msg->buf;
|
||||
char isobusfs_volume_path[ISOBUSFS_MAX_VOLUME_NAME_LENGTH];
|
||||
size_t path_len, req_name_len, resp_name_len;
|
||||
char linux_path[ISOBUSFS_SRV_MAX_PATH_LEN];
|
||||
struct isobusfs_srv_volume *volume = NULL;
|
||||
struct isobusfs_srv_client *client;
|
||||
const char *path;
|
||||
size_t path_len;
|
||||
int ret, i;
|
||||
|
||||
req_name_len = le16toh(req->name_len);
|
||||
|
||||
pr_debug("< rx volume status request. mode: %x, length: %d, name: %s",
|
||||
req->volume_mode, req->name_len, req->name);
|
||||
req->volume_mode, req_name_len, req->name);
|
||||
|
||||
client = isobusfs_srv_get_client_by_msg(priv, msg);
|
||||
if (!client) {
|
||||
@@ -480,12 +482,12 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
|
||||
return ISOBUSFS_ERR_OTHER;
|
||||
}
|
||||
|
||||
if (req->name_len == 0) {
|
||||
if (req_name_len == 0) {
|
||||
path = client->current_dir;
|
||||
path_len = sizeof(client->current_dir);
|
||||
} else {
|
||||
path = req->name;
|
||||
path_len = req->name_len;
|
||||
path_len = req_name_len;
|
||||
}
|
||||
|
||||
ret = isobusfs_extract_volume_name(path, path_len, isobusfs_volume_path,
|
||||
@@ -495,11 +497,12 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
|
||||
return ISOBUSFS_ERR_OTHER;
|
||||
}
|
||||
|
||||
resp->name_len = strlen(isobusfs_volume_path);
|
||||
resp_name_len = strlen(isobusfs_volume_path);
|
||||
resp->name_len = htole16(resp_name_len);
|
||||
/* the isobusfs_volume_path is already null terminated
|
||||
* by isobusfs_extract_volume_name()
|
||||
*/
|
||||
memcpy(resp->name, isobusfs_volume_path, resp->name_len + 1);
|
||||
memcpy(resp->name, isobusfs_volume_path, resp_name_len + 1);
|
||||
|
||||
ret = isobusfs_path_to_linux_path(priv, isobusfs_volume_path,
|
||||
sizeof(isobusfs_volume_path),
|
||||
@@ -530,7 +533,7 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
|
||||
|
||||
if (req->volume_mode & ISOBUSFS_VOL_MODE_PREP_TO_REMOVE) {
|
||||
if (!volume->removable ||
|
||||
(req->name_len == 0 &&
|
||||
(req_name_len == 0 &&
|
||||
0 /* Current directory is not set condition */)) {
|
||||
/* Volume is not removable, or the Path Name Length of
|
||||
* request is zero and the current directory is not set
|
||||
@@ -571,10 +574,15 @@ static int isobusfs_srv_volume_status_resp(struct isobusfs_srv_priv *priv,
|
||||
ret = isobusfs_srv_process_volume_status_request(priv, msg, &resp);
|
||||
resp.error_code = ret;
|
||||
|
||||
buf_size = sizeof(resp);
|
||||
buf_size = sizeof(resp) - sizeof(resp.name) + le16toh(resp.name_len);
|
||||
if (buf_size < ISOBUSFS_MIN_TRANSFER_LENGH) {
|
||||
/* Fill the rest of the buffer with 0xFF. We need to fill
|
||||
* only buffers under 8 bytes. Padding for ETP/TP is done
|
||||
* by the kernel.
|
||||
*/
|
||||
memset(((uint8_t *) &resp) + buf_size, 0xFF,
|
||||
ISOBUSFS_MIN_TRANSFER_LENGH - buf_size);
|
||||
buf_size = ISOBUSFS_MIN_TRANSFER_LENGH;
|
||||
memset(((uint8_t *) &resp) + sizeof(resp), 0xFF, buf_size - sizeof(resp));
|
||||
} else if (buf_size > ISOBUSFS_MAX_TRANSFER_LENGH) {
|
||||
pr_warn("volume status response too long");
|
||||
resp.error_code = ISOBUSFS_ERR_OUT_OF_MEM;
|
||||
|
||||
@@ -662,8 +662,8 @@ static int isobusfs_srv_dh_ccd_res(struct isobusfs_srv_priv *priv,
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We assime, the relative path stored in res->name is not longer
|
||||
* than absolue path
|
||||
* We assume, the relative path stored in res->name is not longer
|
||||
* than absolute path
|
||||
*/
|
||||
if (req->name_len > ISOBUSFS_SRV_MAX_PATH_LEN) {
|
||||
pr_warn("path too long");
|
||||
@@ -697,7 +697,7 @@ static int isobusfs_srv_dh_ccd_res(struct isobusfs_srv_priv *priv,
|
||||
process_error:
|
||||
if (ret < 0) {
|
||||
/* linux_error_to_isobusfs_error() can't distinguish between
|
||||
* -EINVAL vor SRC and DST, so we have to do it manually.
|
||||
* -EINVAL for SRC and DST, so we have to do it manually.
|
||||
*/
|
||||
if (ret == -EINVAL)
|
||||
error_code = ISOBUSFS_ERR_INVALID_DST_NAME;
|
||||
|
||||
@@ -686,7 +686,7 @@ send_response:
|
||||
goto free_res;
|
||||
}
|
||||
|
||||
pr_debug("> tx: Read File Response. Error code: %d (%s), readed size: %d",
|
||||
pr_debug("> tx: Read File Response. Error code: %d (%s), read size: %d",
|
||||
error_code, isobusfs_error_to_str(error_code), readed_size);
|
||||
|
||||
free_res:
|
||||
|
||||
+118
-93
@@ -72,6 +72,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -b <can_id> (broadcast can_id, Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
|
||||
fprintf(stderr, " -c (color mode)\n");
|
||||
@@ -197,11 +198,12 @@ int main(int argc, char **argv)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_can addr;
|
||||
struct can_filter rfilter[2];
|
||||
struct can_filter rfilter[3];
|
||||
struct canfd_frame frame;
|
||||
int nbytes, i;
|
||||
canid_t src = NO_CAN_ID;
|
||||
canid_t dst = NO_CAN_ID;
|
||||
canid_t bst = NO_CAN_ID;
|
||||
int ext = 0;
|
||||
int extaddr = 0;
|
||||
int extany = 0;
|
||||
@@ -222,7 +224,7 @@ int main(int argc, char **argv)
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_usec = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:d:ax:X:ct:u?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:d:b:ax:X:ct:u?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
src = strtoul(optarg, NULL, 16);
|
||||
@@ -236,6 +238,12 @@ int main(int argc, char **argv)
|
||||
dst |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
bst = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
bst |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
color = 1;
|
||||
break;
|
||||
@@ -321,7 +329,18 @@ int main(int argc, char **argv)
|
||||
rfilter[1].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
|
||||
if (bst & CAN_EFF_FLAG) {
|
||||
rfilter[2].can_id = bst & (CAN_EFF_MASK | CAN_EFF_FLAG);
|
||||
rfilter[2].can_mask = (CAN_EFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
|
||||
} else {
|
||||
rfilter[2].can_id = bst & CAN_SFF_MASK;
|
||||
rfilter[2].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
|
||||
}
|
||||
|
||||
if (bst != NO_CAN_ID)
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
|
||||
else
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter) - sizeof(rfilter[0]));
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
@@ -353,8 +372,14 @@ int main(int argc, char **argv)
|
||||
rx_extaddr != frame.data[0])
|
||||
continue;
|
||||
|
||||
if (color)
|
||||
printf("%s", (frame.can_id == src) ? FGRED : FGBLUE);
|
||||
if (color) {
|
||||
if (frame.can_id == src)
|
||||
printf("%s", FGRED);
|
||||
else if (frame.can_id == dst)
|
||||
printf("%s", FGBLUE);
|
||||
else if (frame.can_id == bst)
|
||||
printf("%s", FGGREEN);
|
||||
}
|
||||
|
||||
if (timestamp) {
|
||||
ioctl(s, SIOCGSTAMP, &tv);
|
||||
@@ -401,112 +426,112 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
printf(" %s %8X", argv[optind], frame.can_id & CAN_EFF_MASK);
|
||||
else
|
||||
printf(" %s %3X", argv[optind], frame.can_id & CAN_SFF_MASK);
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
printf(" %s %8X", argv[optind], frame.can_id & CAN_EFF_MASK);
|
||||
else
|
||||
printf(" %s %3X", argv[optind], frame.can_id & CAN_SFF_MASK);
|
||||
|
||||
if (ext)
|
||||
printf("{%02X}", frame.data[0]);
|
||||
if (ext)
|
||||
printf("{%02X}", frame.data[0]);
|
||||
|
||||
if (nbytes == CAN_MTU)
|
||||
printf(" [%d] ", frame.len);
|
||||
else
|
||||
printf(" [%02d] ", frame.len);
|
||||
if (nbytes == CAN_MTU)
|
||||
printf(" [%d] ", frame.len);
|
||||
else
|
||||
printf(" [%02d] ", frame.len);
|
||||
|
||||
datidx = 0;
|
||||
n_pci = frame.data[ext];
|
||||
datidx = 0;
|
||||
n_pci = frame.data[ext];
|
||||
|
||||
switch (n_pci & 0xF0) {
|
||||
case 0x00:
|
||||
is_ff = 1;
|
||||
if (n_pci & 0xF) {
|
||||
printf("[SF] ln: %-4d data:", n_pci & 0xF);
|
||||
datidx = ext+1;
|
||||
} else {
|
||||
printf("[SF] ln: %-4d data:", frame.data[ext + 1]);
|
||||
datidx = ext+2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
is_ff = 1;
|
||||
fflen = ((n_pci & 0x0F)<<8) + frame.data[ext+1];
|
||||
if (fflen)
|
||||
datidx = ext+2;
|
||||
else {
|
||||
fflen = (frame.data[ext+2]<<24) +
|
||||
(frame.data[ext+3]<<16) +
|
||||
(frame.data[ext+4]<<8) +
|
||||
frame.data[ext+5];
|
||||
datidx = ext+6;
|
||||
}
|
||||
printf("[FF] ln: %-4lu data:", fflen);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
printf("[CF] sn: %X data:", n_pci & 0x0F);
|
||||
switch (n_pci & 0xF0) {
|
||||
case 0x00:
|
||||
is_ff = 1;
|
||||
if (n_pci & 0xF) {
|
||||
printf("[SF] ln: %-4d data:", n_pci & 0xF);
|
||||
datidx = ext+1;
|
||||
break;
|
||||
} else {
|
||||
printf("[SF] ln: %-4d data:", frame.data[ext + 1]);
|
||||
datidx = ext+2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x30:
|
||||
n_pci &= 0x0F;
|
||||
printf("[FC] FC: %d ", n_pci);
|
||||
case 0x10:
|
||||
is_ff = 1;
|
||||
fflen = ((n_pci & 0x0F)<<8) + frame.data[ext+1];
|
||||
if (fflen)
|
||||
datidx = ext+2;
|
||||
else {
|
||||
fflen = (frame.data[ext+2]<<24) +
|
||||
(frame.data[ext+3]<<16) +
|
||||
(frame.data[ext+4]<<8) +
|
||||
frame.data[ext+5];
|
||||
datidx = ext+6;
|
||||
}
|
||||
printf("[FF] ln: %-4lu data:", fflen);
|
||||
break;
|
||||
|
||||
if (n_pci > 3)
|
||||
n_pci = 3;
|
||||
case 0x20:
|
||||
printf("[CF] sn: %X data:", n_pci & 0x0F);
|
||||
datidx = ext+1;
|
||||
break;
|
||||
|
||||
printf("= %s # ", fc_info[n_pci]);
|
||||
case 0x30:
|
||||
n_pci &= 0x0F;
|
||||
printf("[FC] FC: %d ", n_pci);
|
||||
|
||||
printf("BS: %d %s# ", frame.data[ext+1],
|
||||
(frame.data[ext+1])? "":"= off ");
|
||||
if (n_pci > 3)
|
||||
n_pci = 3;
|
||||
|
||||
i = frame.data[ext+2];
|
||||
printf("STmin: 0x%02X = ", i);
|
||||
printf("= %s # ", fc_info[n_pci]);
|
||||
|
||||
if (i < 0x80)
|
||||
printf("%d ms", i);
|
||||
else if (i > 0xF0 && i < 0xFA)
|
||||
printf("%d us", (i & 0x0F) * 100);
|
||||
else
|
||||
printf("reserved");
|
||||
break;
|
||||
printf("BS: %d %s# ", frame.data[ext+1],
|
||||
(frame.data[ext+1])? "":"= off ");
|
||||
|
||||
default:
|
||||
printf("[??]");
|
||||
i = frame.data[ext+2];
|
||||
printf("STmin: 0x%02X = ", i);
|
||||
|
||||
if (i < 0x80)
|
||||
printf("%d ms", i);
|
||||
else if (i > 0xF0 && i < 0xFA)
|
||||
printf("%d us", (i & 0x0F) * 100);
|
||||
else
|
||||
printf("reserved");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("[??]");
|
||||
}
|
||||
|
||||
if (datidx && frame.len > datidx) {
|
||||
printf(" ");
|
||||
for (i = datidx; i < frame.len; i++) {
|
||||
printf("%02X ", frame.data[i]);
|
||||
}
|
||||
|
||||
if (datidx && frame.len > datidx) {
|
||||
printf(" ");
|
||||
if (asc) {
|
||||
printf("%*s", ((7-ext) - (frame.len-datidx))*3 + 5 ,
|
||||
"- '");
|
||||
for (i = datidx; i < frame.len; i++) {
|
||||
printf("%02X ", frame.data[i]);
|
||||
}
|
||||
|
||||
if (asc) {
|
||||
printf("%*s", ((7-ext) - (frame.len-datidx))*3 + 5 ,
|
||||
"- '");
|
||||
for (i = datidx; i < frame.len; i++) {
|
||||
printf("%c",((frame.data[i] > 0x1F) &&
|
||||
(frame.data[i] < 0x7F))?
|
||||
frame.data[i] : '.');
|
||||
}
|
||||
printf("'");
|
||||
}
|
||||
if (uds_output && is_ff) {
|
||||
int offset = 3;
|
||||
if (asc)
|
||||
offset = 1;
|
||||
printf("%*s", ((7-ext) - (frame.len-datidx))*offset + 3,
|
||||
" - ");
|
||||
print_uds_message(frame.data[datidx], frame.data[datidx+2]);
|
||||
is_ff = 0;
|
||||
printf("%c",((frame.data[i] > 0x1F) &&
|
||||
(frame.data[i] < 0x7F))?
|
||||
frame.data[i] : '.');
|
||||
}
|
||||
printf("'");
|
||||
}
|
||||
if (uds_output && is_ff) {
|
||||
int offset = 3;
|
||||
if (asc)
|
||||
offset = 1;
|
||||
printf("%*s", ((7-ext) - (frame.len-datidx))*offset + 3,
|
||||
" - ");
|
||||
print_uds_message(frame.data[datidx], frame.data[datidx+2]);
|
||||
is_ff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (color)
|
||||
printf("%s", ATTRESET);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
if (color)
|
||||
printf("%s", ATTRESET);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
+162
-162
@@ -243,177 +243,177 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check extended address if provided */
|
||||
if (ext && extaddr != frame.data[0])
|
||||
continue;
|
||||
|
||||
/* only get flow control information from dst CAN ID */
|
||||
if (frame.can_id == dst) {
|
||||
/* check extended address if provided */
|
||||
if (ext && extaddr != frame.data[0])
|
||||
if (rx_ext && frame.data[0] != rx_extaddr)
|
||||
continue;
|
||||
|
||||
/* only get flow control information from dst CAN ID */
|
||||
if (frame.can_id == dst) {
|
||||
/* check extended address if provided */
|
||||
if (rx_ext && frame.data[0] != rx_extaddr)
|
||||
continue;
|
||||
n_pci = frame.data[rx_ext];
|
||||
/* check flow control PCI only */
|
||||
if ((n_pci & 0xF0) != 0x30)
|
||||
continue;
|
||||
|
||||
n_pci = frame.data[rx_ext];
|
||||
/* check flow control PCI only */
|
||||
if ((n_pci & 0xF0) != 0x30)
|
||||
continue;
|
||||
bs = frame.data[rx_ext + 1];
|
||||
stmin = frame.data[rx_ext + 2];
|
||||
}
|
||||
|
||||
bs = frame.data[rx_ext + 1];
|
||||
stmin = frame.data[rx_ext + 2];
|
||||
/* data content starts and index datidx */
|
||||
datidx = 0;
|
||||
|
||||
n_pci = frame.data[ext];
|
||||
switch (n_pci & 0xF0) {
|
||||
|
||||
case 0x00:
|
||||
/* SF */
|
||||
if (n_pci & 0xF) {
|
||||
fflen = rcvlen = n_pci & 0xF;
|
||||
datidx = ext+1;
|
||||
} else {
|
||||
fflen = rcvlen = frame.data[ext + 1];
|
||||
datidx = ext+2;
|
||||
}
|
||||
|
||||
/* data content starts and index datidx */
|
||||
datidx = 0;
|
||||
|
||||
n_pci = frame.data[ext];
|
||||
switch (n_pci & 0xF0) {
|
||||
|
||||
case 0x00:
|
||||
/* SF */
|
||||
if (n_pci & 0xF) {
|
||||
fflen = rcvlen = n_pci & 0xF;
|
||||
datidx = ext+1;
|
||||
} else {
|
||||
fflen = rcvlen = frame.data[ext + 1];
|
||||
datidx = ext+2;
|
||||
}
|
||||
|
||||
/* ignore incorrect SF PDUs */
|
||||
if (frame.len < rcvlen + datidx)
|
||||
fflen = rcvlen = 0;
|
||||
|
||||
/* get number of digits for printing */
|
||||
fflen_digits = getdigits(fflen);
|
||||
|
||||
/* get CAN FD bitrate & LL_DL setting information */
|
||||
brs = frame.flags & CANFD_BRS;
|
||||
ll_dl = frame.len;
|
||||
if (ll_dl < 8)
|
||||
ll_dl = 8;
|
||||
|
||||
ioctl(s, SIOCGSTAMP, &start_tv);
|
||||
|
||||
/* determine CAN frame mode for this PDU */
|
||||
if (nbytes == CAN_MTU)
|
||||
canfd_on = 0;
|
||||
else
|
||||
canfd_on = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
/* FF */
|
||||
fflen = ((n_pci & 0x0F)<<8) + frame.data[ext+1];
|
||||
if (fflen)
|
||||
datidx = ext+2;
|
||||
else {
|
||||
fflen = (frame.data[ext+2]<<24) +
|
||||
(frame.data[ext+3]<<16) +
|
||||
(frame.data[ext+4]<<8) +
|
||||
frame.data[ext+5];
|
||||
datidx = ext+6;
|
||||
}
|
||||
|
||||
/* to increase the time resolution we multiply fflen with 1000 later */
|
||||
if (fflen >= (UINT32_MAX / 1000)) {
|
||||
printf("fflen %lu is more than ~4.2 MB - ignoring PDU\n", fflen);
|
||||
fflush(stdout);
|
||||
fflen = rcvlen = 0;
|
||||
continue;
|
||||
}
|
||||
rcvlen = frame.len - datidx;
|
||||
last_sn = 0;
|
||||
|
||||
/* get number of digits for printing */
|
||||
fflen_digits = getdigits(fflen);
|
||||
|
||||
/* get CAN FD bitrate & LL_DL setting information */
|
||||
brs = frame.flags & CANFD_BRS;
|
||||
ll_dl = frame.len;
|
||||
|
||||
ioctl(s, SIOCGSTAMP, &start_tv);
|
||||
|
||||
/* determine CAN frame mode for this PDU */
|
||||
if (nbytes == CAN_MTU)
|
||||
canfd_on = 0;
|
||||
else
|
||||
canfd_on = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
/* CF */
|
||||
if (rcvlen) {
|
||||
sn = n_pci & 0x0F;
|
||||
if (sn == ((last_sn + 1) & 0xF)) {
|
||||
last_sn = sn;
|
||||
datidx = ext+1;
|
||||
rcvlen += frame.len - datidx;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* PDU reception in process */
|
||||
if (rcvlen) {
|
||||
if (rcvlen > fflen)
|
||||
rcvlen = fflen;
|
||||
|
||||
percent = (rcvlen * 100 / fflen);
|
||||
printf("\r %3lu%% ", percent);
|
||||
|
||||
printf("|");
|
||||
|
||||
if (percent > 100)
|
||||
percent = 100;
|
||||
|
||||
for (i=0; i < NUMBAR; i++){
|
||||
if (i < (int)(percent/PERCENTRES))
|
||||
printf("X");
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
printf("| %*lu/%lu ", fflen_digits, rcvlen, fflen);
|
||||
}
|
||||
|
||||
/* PDU complete */
|
||||
if (rcvlen && rcvlen >= fflen) {
|
||||
|
||||
printf("\r%s %02d%c (BS:%2hhu # ", canfd_on?"CAN-FD":"CAN2.0", ll_dl, brs?'*':' ', bs);
|
||||
if (stmin < 0x80)
|
||||
printf("STmin:%3hhu msec)", stmin);
|
||||
else if (stmin > 0xF0 && stmin < 0xFA)
|
||||
printf("STmin:%3u usec)", (stmin & 0xF) * 100);
|
||||
else
|
||||
printf("STmin: invalid )");
|
||||
|
||||
printf(" : %lu byte in ", fflen);
|
||||
|
||||
/* calculate time */
|
||||
ioctl(s, SIOCGSTAMP, &end_tv);
|
||||
diff_tv.tv_sec = end_tv.tv_sec - start_tv.tv_sec;
|
||||
diff_tv.tv_usec = end_tv.tv_usec - start_tv.tv_usec;
|
||||
if (diff_tv.tv_usec < 0)
|
||||
diff_tv.tv_sec--, diff_tv.tv_usec += 1000000;
|
||||
if (diff_tv.tv_sec < 0)
|
||||
diff_tv.tv_sec = diff_tv.tv_usec = 0;
|
||||
|
||||
/* check devisor to be not zero */
|
||||
if (diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000){
|
||||
printf("%llu.%06llus ", (unsigned long long)diff_tv.tv_sec, (unsigned long long)diff_tv.tv_usec);
|
||||
printf("=> %lu byte/s", (fflen * 1000) /
|
||||
(unsigned long)(diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000));
|
||||
} else
|
||||
printf("(no time available) ");
|
||||
|
||||
printf("\n");
|
||||
/* wait for next PDU */
|
||||
/* ignore incorrect SF PDUs */
|
||||
if (frame.len < rcvlen + datidx)
|
||||
fflen = rcvlen = 0;
|
||||
|
||||
/* get number of digits for printing */
|
||||
fflen_digits = getdigits(fflen);
|
||||
|
||||
/* get CAN FD bitrate & LL_DL setting information */
|
||||
brs = frame.flags & CANFD_BRS;
|
||||
ll_dl = frame.len;
|
||||
if (ll_dl < 8)
|
||||
ll_dl = 8;
|
||||
|
||||
ioctl(s, SIOCGSTAMP, &start_tv);
|
||||
|
||||
/* determine CAN frame mode for this PDU */
|
||||
if (nbytes == CAN_MTU)
|
||||
canfd_on = 0;
|
||||
else
|
||||
canfd_on = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
/* FF */
|
||||
fflen = ((n_pci & 0x0F)<<8) + frame.data[ext+1];
|
||||
if (fflen)
|
||||
datidx = ext+2;
|
||||
else {
|
||||
fflen = (frame.data[ext+2]<<24) +
|
||||
(frame.data[ext+3]<<16) +
|
||||
(frame.data[ext+4]<<8) +
|
||||
frame.data[ext+5];
|
||||
datidx = ext+6;
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
/* to increase the time resolution we multiply fflen with 1000 later */
|
||||
if (fflen >= (UINT32_MAX / 1000)) {
|
||||
printf("fflen %lu is more than ~4.2 MB - ignoring PDU\n", fflen);
|
||||
fflush(stdout);
|
||||
fflen = rcvlen = 0;
|
||||
continue;
|
||||
}
|
||||
rcvlen = frame.len - datidx;
|
||||
last_sn = 0;
|
||||
|
||||
/* get number of digits for printing */
|
||||
fflen_digits = getdigits(fflen);
|
||||
|
||||
/* get CAN FD bitrate & LL_DL setting information */
|
||||
brs = frame.flags & CANFD_BRS;
|
||||
ll_dl = frame.len;
|
||||
|
||||
ioctl(s, SIOCGSTAMP, &start_tv);
|
||||
|
||||
/* determine CAN frame mode for this PDU */
|
||||
if (nbytes == CAN_MTU)
|
||||
canfd_on = 0;
|
||||
else
|
||||
canfd_on = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
/* CF */
|
||||
if (rcvlen) {
|
||||
sn = n_pci & 0x0F;
|
||||
if (sn == ((last_sn + 1) & 0xF)) {
|
||||
last_sn = sn;
|
||||
datidx = ext+1;
|
||||
rcvlen += frame.len - datidx;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* PDU reception in process */
|
||||
if (rcvlen) {
|
||||
if (rcvlen > fflen)
|
||||
rcvlen = fflen;
|
||||
|
||||
percent = (rcvlen * 100 / fflen);
|
||||
printf("\r %3lu%% ", percent);
|
||||
|
||||
printf("|");
|
||||
|
||||
if (percent > 100)
|
||||
percent = 100;
|
||||
|
||||
for (i=0; i < NUMBAR; i++){
|
||||
if (i < (int)(percent/PERCENTRES))
|
||||
printf("X");
|
||||
else
|
||||
printf(".");
|
||||
}
|
||||
printf("| %*lu/%lu ", fflen_digits, rcvlen, fflen);
|
||||
}
|
||||
|
||||
/* PDU complete */
|
||||
if (rcvlen && rcvlen >= fflen) {
|
||||
|
||||
printf("\r%s %02d%c (BS:%2hhu # ", canfd_on?"CAN-FD":"CAN2.0", ll_dl, brs?'*':' ', bs);
|
||||
if (stmin < 0x80)
|
||||
printf("STmin:%3hhu msec)", stmin);
|
||||
else if (stmin > 0xF0 && stmin < 0xFA)
|
||||
printf("STmin:%3u usec)", (stmin & 0xF) * 100);
|
||||
else
|
||||
printf("STmin: invalid )");
|
||||
|
||||
printf(" : %lu byte in ", fflen);
|
||||
|
||||
/* calculate time */
|
||||
ioctl(s, SIOCGSTAMP, &end_tv);
|
||||
diff_tv.tv_sec = end_tv.tv_sec - start_tv.tv_sec;
|
||||
diff_tv.tv_usec = end_tv.tv_usec - start_tv.tv_usec;
|
||||
if (diff_tv.tv_usec < 0)
|
||||
diff_tv.tv_sec--, diff_tv.tv_usec += 1000000;
|
||||
if (diff_tv.tv_sec < 0)
|
||||
diff_tv.tv_sec = diff_tv.tv_usec = 0;
|
||||
|
||||
/* check devisor to be not zero */
|
||||
if (diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000){
|
||||
printf("%llu.%06llus ", (unsigned long long)diff_tv.tv_sec, (unsigned long long)diff_tv.tv_usec);
|
||||
printf("=> %lu byte/s", (fflen * 1000) /
|
||||
(unsigned long)(diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000));
|
||||
} else
|
||||
printf("(no time available) ");
|
||||
|
||||
printf("\n");
|
||||
/* wait for next PDU */
|
||||
fflen = rcvlen = 0;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
+155
-155
@@ -82,183 +82,183 @@ void print_usage(char *prg)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_can addr;
|
||||
static struct can_isotp_options opts;
|
||||
static struct can_isotp_fc_options fcopts;
|
||||
static struct can_isotp_ll_options llopts;
|
||||
int opt, i;
|
||||
extern int optind, opterr, optopt;
|
||||
__u32 force_rx_stmin = 0;
|
||||
int loop = 0;
|
||||
int s;
|
||||
struct sockaddr_can addr;
|
||||
static struct can_isotp_options opts;
|
||||
static struct can_isotp_fc_options fcopts;
|
||||
static struct can_isotp_ll_options llopts;
|
||||
int opt, i;
|
||||
extern int optind, opterr, optopt;
|
||||
__u32 force_rx_stmin = 0;
|
||||
int loop = 0;
|
||||
|
||||
unsigned char msg[BUFSIZE];
|
||||
int nbytes;
|
||||
unsigned char msg[BUFSIZE];
|
||||
int nbytes;
|
||||
|
||||
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
|
||||
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:b:m:w:f:lFL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:b:m:w:f:lFL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.ext_address,
|
||||
&opts.rx_ext_address);
|
||||
case 'x':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.ext_address,
|
||||
&opts.rx_ext_address);
|
||||
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_EXTEND_ADDR;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
|
||||
else {
|
||||
printf("incorrect extended addr values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_EXTEND_ADDR;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
|
||||
else {
|
||||
printf("incorrect extended addr values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.txpad_content,
|
||||
&opts.rxpad_content);
|
||||
case 'p':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.txpad_content,
|
||||
&opts.rxpad_content);
|
||||
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_TX_PADDING;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
|
||||
else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
|
||||
opts.flags |= CAN_ISOTP_RX_PADDING;
|
||||
else {
|
||||
printf("incorrect padding values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_TX_PADDING;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
|
||||
else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
|
||||
opts.flags |= CAN_ISOTP_RX_PADDING;
|
||||
else {
|
||||
printf("incorrect padding values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'P':
|
||||
if (optarg[0] == 'l')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_LEN;
|
||||
else if (optarg[0] == 'c')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
|
||||
else if (optarg[0] == 'a')
|
||||
opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
|
||||
else {
|
||||
printf("unknown padding check option '%c'.\n", optarg[0]);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
if (optarg[0] == 'l')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_LEN;
|
||||
else if (optarg[0] == 'c')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
|
||||
else if (optarg[0] == 'a')
|
||||
opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
|
||||
else {
|
||||
printf("unknown padding check option '%c'.\n", optarg[0]);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
case 'b':
|
||||
fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
case 'm':
|
||||
fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
case 'w':
|
||||
fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
opts.flags |= CAN_ISOTP_FORCE_RXSTMIN;
|
||||
force_rx_stmin = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'f':
|
||||
opts.flags |= CAN_ISOTP_FORCE_RXSTMIN;
|
||||
force_rx_stmin = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
loop = 1;
|
||||
break;
|
||||
case 'l':
|
||||
loop = 1;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
opts.flags |= CAN_ISOTP_DYN_FC_PARMS;
|
||||
break;
|
||||
case 'F':
|
||||
opts.flags |= CAN_ISOTP_DYN_FC_PARMS;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
&llopts.tx_dl,
|
||||
&llopts.tx_flags) != 3) {
|
||||
printf("unknown link layer options '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
&llopts.tx_dl,
|
||||
&llopts.tx_flags) != 3) {
|
||||
printf("unknown link layer options '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
break;
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown option %c\n", opt);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind != 1) ||
|
||||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
|
||||
(addr.can_addr.tp.rx_id == NO_CAN_ID)) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts));
|
||||
|
||||
if (llopts.tx_dl) {
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
|
||||
perror("link layer sockopt");
|
||||
exit(1);
|
||||
default:
|
||||
fprintf(stderr, "Unknown option %c\n", opt);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.flags & CAN_ISOTP_FORCE_RXSTMIN)
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &force_rx_stmin, sizeof(force_rx_stmin));
|
||||
if ((argc - optind != 1) ||
|
||||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
|
||||
(addr.can_addr.tp.rx_id == NO_CAN_ID)) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts));
|
||||
|
||||
if (llopts.tx_dl) {
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
|
||||
perror("link layer sockopt");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.flags & CAN_ISOTP_FORCE_RXSTMIN)
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &force_rx_stmin, sizeof(force_rx_stmin));
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
do {
|
||||
nbytes = read(s, msg, BUFSIZE);
|
||||
if (nbytes > 0 && nbytes < BUFSIZE)
|
||||
for (i=0; i < nbytes; i++)
|
||||
printf("%02X ", msg[i]);
|
||||
printf("\n");
|
||||
} while (loop);
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
do {
|
||||
nbytes = read(s, msg, BUFSIZE);
|
||||
if (nbytes > 0 && nbytes < BUFSIZE)
|
||||
for (i=0; i < nbytes; i++)
|
||||
printf("%02X ", msg[i]);
|
||||
printf("\n");
|
||||
} while (loop);
|
||||
|
||||
close(s);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+200
-200
@@ -86,238 +86,238 @@ void print_usage(char *prg)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_can addr;
|
||||
static struct can_isotp_options opts;
|
||||
static struct can_isotp_ll_options llopts;
|
||||
int opt;
|
||||
extern int optind, opterr, optopt;
|
||||
unsigned int loops = 1; /* one (== no) loop by default */
|
||||
useconds_t usecs = 0; /* wait before sending the PDU */
|
||||
__u32 force_tx_stmin = 0;
|
||||
unsigned char buf[BUFSIZE];
|
||||
int buflen = 0;
|
||||
int datalen = 0;
|
||||
int retval = 0;
|
||||
int s;
|
||||
struct sockaddr_can addr;
|
||||
static struct can_isotp_options opts;
|
||||
static struct can_isotp_ll_options llopts;
|
||||
int opt;
|
||||
extern int optind, opterr, optopt;
|
||||
unsigned int loops = 1; /* one (== no) loop by default */
|
||||
useconds_t usecs = 0; /* wait before sending the PDU */
|
||||
__u32 force_tx_stmin = 0;
|
||||
unsigned char buf[BUFSIZE];
|
||||
int buflen = 0;
|
||||
int datalen = 0;
|
||||
int retval = 0;
|
||||
|
||||
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
|
||||
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:l:g:bSCL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:l:g:bSCL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.ext_address,
|
||||
&opts.rx_ext_address);
|
||||
case 'x':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.ext_address,
|
||||
&opts.rx_ext_address);
|
||||
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_EXTEND_ADDR;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
|
||||
else {
|
||||
printf("incorrect extended addr values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_EXTEND_ADDR;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
|
||||
else {
|
||||
printf("incorrect extended addr values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.txpad_content,
|
||||
&opts.rxpad_content);
|
||||
case 'p':
|
||||
{
|
||||
int elements = sscanf(optarg, "%hhx:%hhx",
|
||||
&opts.txpad_content,
|
||||
&opts.rxpad_content);
|
||||
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_TX_PADDING;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
|
||||
else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
|
||||
opts.flags |= CAN_ISOTP_RX_PADDING;
|
||||
else {
|
||||
printf("incorrect padding values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (elements == 1)
|
||||
opts.flags |= CAN_ISOTP_TX_PADDING;
|
||||
else if (elements == 2)
|
||||
opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
|
||||
else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
|
||||
opts.flags |= CAN_ISOTP_RX_PADDING;
|
||||
else {
|
||||
printf("incorrect padding values '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'P':
|
||||
if (optarg[0] == 'l')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_LEN;
|
||||
else if (optarg[0] == 'c')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
|
||||
else if (optarg[0] == 'a')
|
||||
opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
|
||||
else {
|
||||
printf("unknown padding check option '%c'.\n", optarg[0]);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
if (optarg[0] == 'l')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_LEN;
|
||||
else if (optarg[0] == 'c')
|
||||
opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
|
||||
else if (optarg[0] == 'a')
|
||||
opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
|
||||
else {
|
||||
printf("unknown padding check option '%c'.\n", optarg[0]);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if (!strncmp(optarg, ZERO_STRING, strlen(ZERO_STRING)))
|
||||
opts.frame_txtime = CAN_ISOTP_FRAME_TXTIME_ZERO;
|
||||
else
|
||||
opts.frame_txtime = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 't':
|
||||
if (!strncmp(optarg, ZERO_STRING, strlen(ZERO_STRING)))
|
||||
opts.frame_txtime = CAN_ISOTP_FRAME_TXTIME_ZERO;
|
||||
else
|
||||
opts.frame_txtime = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
opts.flags |= CAN_ISOTP_FORCE_TXSTMIN;
|
||||
force_tx_stmin = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'f':
|
||||
opts.flags |= CAN_ISOTP_FORCE_TXSTMIN;
|
||||
force_tx_stmin = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
datalen = strtoul(optarg, NULL, 10);
|
||||
if (!datalen || datalen >= BUFSIZE) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
datalen = strtoul(optarg, NULL, 10);
|
||||
if (!datalen || datalen >= BUFSIZE) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (optarg[0] == 'i') {
|
||||
loops = 0; /* infinite loop */
|
||||
} else {
|
||||
loops = strtoul(optarg, NULL, 10);
|
||||
if (!loops) {
|
||||
fprintf(stderr, "Invalid argument for option -l!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (optarg[0] == 'i') {
|
||||
loops = 0; /* infinite loop */
|
||||
} else {
|
||||
loops = strtoul(optarg, NULL, 10);
|
||||
if (!loops) {
|
||||
fprintf(stderr, "Invalid argument for option -l!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
usecs = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'g':
|
||||
usecs = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
|
||||
break;
|
||||
case 'b':
|
||||
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
opts.flags |= CAN_ISOTP_SF_BROADCAST;
|
||||
break;
|
||||
case 'S':
|
||||
opts.flags |= CAN_ISOTP_SF_BROADCAST;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
opts.flags |= CAN_ISOTP_CF_BROADCAST;
|
||||
break;
|
||||
case 'C':
|
||||
opts.flags |= CAN_ISOTP_CF_BROADCAST;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
&llopts.tx_dl,
|
||||
&llopts.tx_flags) != 3) {
|
||||
printf("unknown link layer options '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
&llopts.tx_dl,
|
||||
&llopts.tx_flags) != 3) {
|
||||
printf("unknown link layer options '%s'.\n", optarg);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
break;
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown option %c\n", opt);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "Unknown option %c\n", opt);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST)
|
||||
|
||||
if ((argc - optind != 1) ||
|
||||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
|
||||
((opts.flags & BC_FLAGS) == BC_FLAGS) ||
|
||||
((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
|
||||
(!(opts.flags & BC_FLAGS)))) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
|
||||
perror("sockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (llopts.tx_dl) {
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
|
||||
perror("link layer sockopt");
|
||||
exit(1);
|
||||
if ((argc - optind != 1) ||
|
||||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
|
||||
((opts.flags & BC_FLAGS) == BC_FLAGS) ||
|
||||
((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
|
||||
(!(opts.flags & BC_FLAGS)))) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.flags & CAN_ISOTP_FORCE_TXSTMIN)
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &force_tx_stmin, sizeof(force_tx_stmin));
|
||||
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
|
||||
perror("sockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!datalen) {
|
||||
while (buflen < BUFSIZE && scanf("%hhx", &buf[buflen]) == 1)
|
||||
buflen++;
|
||||
} else {
|
||||
for (buflen = 0; buflen < datalen; buflen++)
|
||||
buf[buflen] = ((buflen % 0xFF) + 1) & 0xFF;
|
||||
}
|
||||
if (llopts.tx_dl) {
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
|
||||
perror("link layer sockopt");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.flags & CAN_ISOTP_FORCE_TXSTMIN)
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &force_tx_stmin, sizeof(force_tx_stmin));
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!datalen) {
|
||||
while (buflen < BUFSIZE && scanf("%hhx", &buf[buflen]) == 1)
|
||||
buflen++;
|
||||
} else {
|
||||
for (buflen = 0; buflen < datalen; buflen++)
|
||||
buf[buflen] = ((buflen % 0xFF) + 1) & 0xFF;
|
||||
}
|
||||
|
||||
loop:
|
||||
if (usecs)
|
||||
usleep(usecs);
|
||||
if (usecs)
|
||||
usleep(usecs);
|
||||
|
||||
retval = write(s, buf, buflen);
|
||||
if (retval < 0) {
|
||||
perror("write");
|
||||
return retval;
|
||||
}
|
||||
retval = write(s, buf, buflen);
|
||||
if (retval < 0) {
|
||||
perror("write");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (retval != buflen)
|
||||
fprintf(stderr, "wrote only %d from %d byte\n", retval, buflen);
|
||||
if (retval != buflen)
|
||||
fprintf(stderr, "wrote only %d from %d byte\n", retval, buflen);
|
||||
|
||||
if (loops) {
|
||||
if (--loops)
|
||||
goto loop;
|
||||
} else {
|
||||
goto loop;
|
||||
}
|
||||
if (loops) {
|
||||
if (--loops)
|
||||
goto loop;
|
||||
} else {
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* due to a Kernel internal wait queue the PDU is sent completely
|
||||
* before close() returns.
|
||||
*/
|
||||
close(s);
|
||||
/*
|
||||
* due to a Kernel internal wait queue the PDU is sent completely
|
||||
* before close() returns.
|
||||
*/
|
||||
close(s);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,500 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-only
|
||||
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/if.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "j1939_timedate_cmn.h"
|
||||
|
||||
#define J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS 10
|
||||
|
||||
struct j1939_timedate_cli_priv {
|
||||
int sock_nack;
|
||||
int sock_main;
|
||||
|
||||
struct sockaddr_can sockname;
|
||||
struct sockaddr_can peername;
|
||||
|
||||
struct j1939_timedate_stats stats;
|
||||
|
||||
struct libj1939_cmn cmn;
|
||||
struct timespec wait_until_time;
|
||||
|
||||
bool utc;
|
||||
bool broadcast;
|
||||
bool done;
|
||||
};
|
||||
|
||||
static void print_time_date_packet(struct j1939_timedate_cli_priv *priv,
|
||||
const struct j1939_timedate_msg *msg)
|
||||
{
|
||||
const struct j1939_time_date_packet *tdp =
|
||||
(const struct j1939_time_date_packet *)msg->buf;
|
||||
char timezone_offset[] = "+00:00 (Local Time)";
|
||||
char time_buffer[64];
|
||||
int actual_hour, actual_minute;
|
||||
int actual_year, actual_month;
|
||||
double actual_seconds;
|
||||
double actual_day;
|
||||
|
||||
if (msg->len < (int)sizeof(*tdp)) {
|
||||
pr_warn("received too short time and date packet: %zi",
|
||||
msg->len);
|
||||
return;
|
||||
}
|
||||
|
||||
actual_year = 1985 + tdp->year;
|
||||
actual_month = tdp->month;
|
||||
actual_day = tdp->day * 0.25;
|
||||
actual_hour = tdp->hours;
|
||||
actual_minute = tdp->minutes;
|
||||
actual_seconds = tdp->seconds * 0.25;
|
||||
|
||||
if (tdp->local_hour_offset == 125) {
|
||||
snprintf(timezone_offset, sizeof(timezone_offset),
|
||||
"+00:00 (Local Time)");
|
||||
} else if (!priv->utc) {
|
||||
actual_hour += tdp->local_hour_offset;
|
||||
actual_minute += tdp->local_minute_offset;
|
||||
|
||||
/* Wraparound for hours and minutes if needed */
|
||||
if (actual_minute >= 60) {
|
||||
actual_minute -= 60;
|
||||
actual_hour++;
|
||||
} else if (actual_minute < 0) {
|
||||
actual_minute += 60;
|
||||
actual_hour--;
|
||||
}
|
||||
|
||||
if (actual_hour >= 24) {
|
||||
actual_hour -= 24;
|
||||
actual_day++;
|
||||
} else if (actual_hour < 0) {
|
||||
actual_hour += 24;
|
||||
actual_day--;
|
||||
}
|
||||
|
||||
snprintf(timezone_offset, sizeof(timezone_offset), "%+03d:%02d",
|
||||
tdp->local_hour_offset, abs(tdp->local_minute_offset));
|
||||
} else {
|
||||
snprintf(timezone_offset, sizeof(timezone_offset),
|
||||
"+00:00 (UTC)");
|
||||
}
|
||||
|
||||
snprintf(time_buffer, sizeof(time_buffer),
|
||||
"%d-%02d-%02.0f %02d:%02d:%05.2f%.20s",
|
||||
actual_year, actual_month, actual_day, actual_hour,
|
||||
actual_minute, actual_seconds, timezone_offset);
|
||||
|
||||
printf("SA: 0x%02X, NAME: 0x%016llX, Time: %s\n",
|
||||
msg->peername.can_addr.j1939.addr,
|
||||
msg->peername.can_addr.j1939.name, time_buffer);
|
||||
|
||||
if (!priv->broadcast)
|
||||
priv->done = true;
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_rx_buf(struct j1939_timedate_cli_priv *priv,
|
||||
struct j1939_timedate_msg *msg)
|
||||
{
|
||||
pgn_t pgn = msg->peername.can_addr.j1939.pgn;
|
||||
int ret = 0;
|
||||
|
||||
switch (pgn) {
|
||||
case J1939_PGN_TD:
|
||||
print_time_date_packet(priv, msg);
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: unsupported PGN: %x", __func__, pgn);
|
||||
/* Not a critical error */
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_rx_one(struct j1939_timedate_cli_priv *priv,
|
||||
int sock)
|
||||
{
|
||||
struct j1939_timedate_msg *msg;
|
||||
int flags = 0;
|
||||
int ret;
|
||||
|
||||
msg = malloc(sizeof(*msg));
|
||||
if (!msg) {
|
||||
pr_err("can't allocate rx msg struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->buf_size = J1939_TIMEDATE_MAX_TRANSFER_LENGH;
|
||||
msg->peer_addr_len = sizeof(msg->peername);
|
||||
msg->sock = sock;
|
||||
|
||||
ret = recvfrom(sock, &msg->buf[0], msg->buf_size, flags,
|
||||
(struct sockaddr *)&msg->peername, &msg->peer_addr_len);
|
||||
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("recvfrom() failed: %i %s", ret, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < 3) {
|
||||
pr_warn("received too short message: %i", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg->len = ret;
|
||||
|
||||
ret = j1939_timedate_cli_rx_buf(priv, msg);
|
||||
if (ret < 0) {
|
||||
pr_warn("failed to process rx buf: %i (%s)\n", ret,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_handle_events(struct j1939_timedate_cli_priv *priv,
|
||||
unsigned int nfds)
|
||||
{
|
||||
int ret;
|
||||
unsigned int n;
|
||||
|
||||
for (n = 0; n < nfds && n < priv->cmn.epoll_events_size; ++n) {
|
||||
struct epoll_event *ev = &priv->cmn.epoll_events[n];
|
||||
|
||||
if (!ev->events) {
|
||||
warn("no events");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->events & POLLIN) {
|
||||
ret = j1939_timedate_cli_rx_one(priv, ev->data.fd);
|
||||
if (ret) {
|
||||
warn("recv one");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_process_events_and_tasks(struct j1939_timedate_cli_priv *priv)
|
||||
{
|
||||
int ret, nfds;
|
||||
|
||||
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nfds > 0) {
|
||||
ret = j1939_timedate_cli_handle_events(priv, nfds);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_send_req(struct j1939_timedate_cli_priv *priv)
|
||||
{
|
||||
struct sockaddr_can addr = priv->peername;
|
||||
uint8_t data[3] = {0};
|
||||
int ret;
|
||||
|
||||
addr.can_addr.j1939.pgn = J1939_PGN_REQUEST_PGN;
|
||||
|
||||
data[0] = J1939_PGN_TD & 0xff;
|
||||
data[1] = (J1939_PGN_TD >> 8) & 0xff;
|
||||
data[2] = (J1939_PGN_TD >> 16) & 0xff;
|
||||
|
||||
ret = sendto(priv->sock_main, data, sizeof(data), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
pr_warn("failed to send data: %i (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_sock_main_prepare(struct j1939_timedate_cli_priv *priv)
|
||||
{
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->sock_main = ret;
|
||||
|
||||
ret = libj1939_bind_socket(priv->sock_main, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = libj1939_socket_prio(priv->sock_main,
|
||||
J1939_TIMEDATE_PRIO_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = libj1939_set_broadcast(priv->sock_main);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_main, EPOLLIN);
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_sock_nack_prepare(struct j1939_timedate_cli_priv *priv)
|
||||
{
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->sock_nack = ret;
|
||||
|
||||
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
|
||||
ret = libj1939_bind_socket(priv->sock_nack, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_nack, EPOLLIN);
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_sock_prepare(struct j1939_timedate_cli_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libj1939_create_epoll();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->cmn.epoll_fd = ret;
|
||||
|
||||
priv->cmn.epoll_events = calloc(J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS,
|
||||
sizeof(struct epoll_event));
|
||||
if (!priv->cmn.epoll_events)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->cmn.epoll_events_size = J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS;
|
||||
|
||||
ret = j1939_timedate_cli_sock_main_prepare(priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return j1939_timedate_cli_sock_nack_prepare(priv);
|
||||
}
|
||||
|
||||
static void j1939_timedate_cli_print_help(void)
|
||||
{
|
||||
printf("Usage: j1939_timedate-cli [options]\n");
|
||||
printf("Options:\n");
|
||||
printf(" --interface <interface_name> or -i <interface_name>\n");
|
||||
printf(" Specifies the CAN interface to use (mandatory).\n");
|
||||
printf(" --local-address <local_address_hex> or -a <local_address_hex>\n");
|
||||
printf(" Specifies the local address in hexadecimal (mandatory if local name is not provided).\n");
|
||||
printf(" --local-name <local_name_hex> or -n <local_name_hex>\n");
|
||||
printf(" Specifies the local NAME in hexadecimal (mandatory if local address is not provided).\n");
|
||||
printf(" --remote-address <remote_address_hex> or -r <remote_address_hex>\n");
|
||||
printf(" Specifies the remote address in hexadecimal (optional).\n");
|
||||
printf(" --remote-name <remote_name_hex> or -m <remote_name_hex>\n");
|
||||
printf(" Specifies the remote NAME in hexadecimal (optional).\n");
|
||||
printf(" --utc or -u\n");
|
||||
printf(" Outputs the time in UTC format.\n");
|
||||
printf("\n");
|
||||
printf("Note:\n");
|
||||
printf(" Local address and local name are mutually exclusive and one must be provided.\n");
|
||||
printf(" Remote address and remote name are mutually exclusive. \n");
|
||||
printf(" If no remote property is provided, the broadcast address will be used.\n");
|
||||
printf("\n");
|
||||
printf("Behavior:\n");
|
||||
printf(" In unicast mode (remote address or remote name provided),\n");
|
||||
printf(" the client will send a request and wait for the first response, then exit.\n");
|
||||
printf(" In broadcast mode (no remote address or remote name provided),\n");
|
||||
printf(" the program will wait 1000 milliseconds to collect responses, then exit.\n");
|
||||
printf("\n");
|
||||
printf("Time Output Formats:\n");
|
||||
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 (Local Time) - when no time zone information is received.\n");
|
||||
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 (UTC) - when the --utc option is used.\n");
|
||||
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 - default response with time zone offset automatically calculated.\n");
|
||||
printf("\n");
|
||||
printf("Complete Message Format:\n");
|
||||
printf(" The message will include the Source Address (SA) and J1939 NAME, formatted as follows:\n");
|
||||
printf(" SA: 0x60, NAME: 0x0000000000000000, Time: 2024-05-16 20:23:40.00+02:00\n");
|
||||
printf(" If the NAME is known, it will have a non-zero value.\n");
|
||||
printf("\n");
|
||||
printf("Usage Examples:\n");
|
||||
printf(" j1939acd -r 64-95 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0 &\n");
|
||||
printf("\n");
|
||||
printf(" Broadcast mode:\n");
|
||||
printf(" j1939-timedate-cli -i vcan0 -a 0x80\n");
|
||||
printf("\n");
|
||||
printf(" Unicast mode:\n");
|
||||
printf(" j1939-timedate-cli -i vcan0 -a 0x80 -r 0x90\n");
|
||||
printf("\n");
|
||||
printf(" Using NAMEs instead of addresses:\n");
|
||||
printf(" j1939acd -r 64-95 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0 &\n");
|
||||
printf(" j1939-timedate-cli -i vcan0 -n 0x1122334455667788\n");
|
||||
}
|
||||
|
||||
static int j1939_timedate_cli_parse_args(struct j1939_timedate_cli_priv *priv, int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_can *remote = &priv->peername;
|
||||
struct sockaddr_can *local = &priv->sockname;
|
||||
bool local_address_set = false;
|
||||
bool local_name_set = false;
|
||||
bool remote_address_set = false;
|
||||
bool remote_name_set = false;
|
||||
bool interface_set = false;
|
||||
int long_index = 0;
|
||||
int opt;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"interface", required_argument, 0, 'i'},
|
||||
{"local-address", required_argument, 0, 'a'},
|
||||
{"local-name", required_argument, 0, 'n'},
|
||||
{"remote-address", required_argument, 0, 'r'},
|
||||
{"remote-name", required_argument, 0, 'm'},
|
||||
{"utc", no_argument, 0, 'u'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "a:n:r:m:i:u", long_options, &long_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
local->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
|
||||
local_address_set = true;
|
||||
break;
|
||||
case 'n':
|
||||
local->can_addr.j1939.name = strtoull(optarg, NULL, 16);
|
||||
local_name_set = true;
|
||||
break;
|
||||
case 'r':
|
||||
remote->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
|
||||
remote_address_set = true;
|
||||
break;
|
||||
case 'm':
|
||||
remote->can_addr.j1939.name = strtoull(optarg, NULL, 16);
|
||||
remote_name_set = true;
|
||||
break;
|
||||
case 'i':
|
||||
local->can_ifindex = if_nametoindex(optarg);
|
||||
if (!local->can_ifindex) {
|
||||
pr_err("Interface %s not found. Error: %d (%s)\n",
|
||||
optarg, errno, strerror(errno));
|
||||
return -EINVAL;
|
||||
}
|
||||
remote->can_ifindex = local->can_ifindex;
|
||||
interface_set = true;
|
||||
break;
|
||||
case 'u':
|
||||
priv->utc = true;
|
||||
break;
|
||||
default:
|
||||
j1939_timedate_cli_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!interface_set) {
|
||||
pr_err("interface not specified");
|
||||
j1939_timedate_cli_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((local_address_set && local_name_set) ||
|
||||
(remote_address_set && remote_name_set)) {
|
||||
pr_err("Local address and local name or remote address and remote name are mutually exclusive\n");
|
||||
j1939_timedate_cli_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!local_address_set && !local_name_set) {
|
||||
pr_err("Local address and local name not specified. One of them is required\n");
|
||||
j1939_timedate_cli_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If no remote address is set, set it to broadcast */
|
||||
if (!remote_address_set && !remote_name_set) {
|
||||
remote->can_addr.j1939.addr = J1939_NO_ADDR;
|
||||
priv->broadcast = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct j1939_timedate_cli_priv *priv;
|
||||
struct timespec ts;
|
||||
int64_t time_diff;
|
||||
int ret;
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (!priv)
|
||||
err(EXIT_FAILURE, "can't allocate priv");
|
||||
|
||||
bzero(priv, sizeof(*priv));
|
||||
|
||||
libj1939_init_sockaddr_can(&priv->sockname, J1939_PGN_TD);
|
||||
libj1939_init_sockaddr_can(&priv->peername, J1939_PGN_REQUEST_PGN);
|
||||
|
||||
ret = j1939_timedate_cli_parse_args(priv, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = j1939_timedate_cli_sock_prepare(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
priv->cmn.next_send_time = ts;
|
||||
priv->wait_until_time = priv->cmn.next_send_time;
|
||||
/* Wait one second to collect all responses by default */
|
||||
timespec_add_ms(&priv->wait_until_time, 1000);
|
||||
|
||||
ret = j1939_timedate_cli_send_req(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (1) {
|
||||
ret = j1939_timedate_cli_process_events_and_tasks(priv);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (priv->done)
|
||||
break;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
time_diff = timespec_diff_ms(&priv->wait_until_time, &ts);
|
||||
if (time_diff < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
close(priv->cmn.epoll_fd);
|
||||
free(priv->cmn.epoll_events);
|
||||
|
||||
close(priv->sock_main);
|
||||
close(priv->sock_nack);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-only
|
||||
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
|
||||
|
||||
#ifndef _J1939_TIMEDATE_H_
|
||||
#define _J1939_TIMEDATE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <endian.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "../libj1939.h"
|
||||
#include "../lib.h"
|
||||
|
||||
/* SAE J1939-71:2002 - 5.3 pgn54528 - Time/Date Adjust - TDA - */
|
||||
#define J1939_PGN_TDA 0x0d500 /* 54528 */
|
||||
/* SAE J1939-71:2002 - 5.3 pgn65254 - Time/Date - TD - */
|
||||
#define J1939_PGN_TD 0x0fee6 /* 65254 */
|
||||
|
||||
#define J1939_PGN_REQUEST_PGN 0x0ea00 /* 59904 */
|
||||
|
||||
/* ISO 11783-3:2018 - 5.4.5 Acknowledgment */
|
||||
#define ISOBUS_PGN_ACK 0x0e800 /* 59392 */
|
||||
|
||||
#define J1939_TIMEDATE_PRIO_DEFAULT 6
|
||||
|
||||
#define J1939_TIMEDATE_MAX_TRANSFER_LENGH 8
|
||||
|
||||
struct j1939_timedate_stats {
|
||||
int err;
|
||||
uint32_t tskey_sch;
|
||||
uint32_t tskey_ack;
|
||||
uint32_t send;
|
||||
};
|
||||
|
||||
struct j1939_timedate_msg {
|
||||
uint8_t buf[J1939_TIMEDATE_MAX_TRANSFER_LENGH];
|
||||
size_t buf_size;
|
||||
ssize_t len; /* length of received message */
|
||||
struct sockaddr_can peername;
|
||||
socklen_t peer_addr_len;
|
||||
int sock;
|
||||
};
|
||||
|
||||
struct j1939_timedate_err_msg {
|
||||
struct sock_extended_err *serr;
|
||||
struct scm_timestamping *tss;
|
||||
struct j1939_timedate_stats *stats;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct time_date_packet - Represents the PGN 65254 Time/Date packet
|
||||
*
|
||||
* @seconds: Seconds since the last minute (0-59) with a scaling factor,
|
||||
* meaning each increment represents 0.25 seconds.
|
||||
* @minutes: Minutes since the last hour (0-59) with no scaling.
|
||||
* @hours: Hours since midnight (0-23) with no scaling.
|
||||
* @month: Current month (1-12) with no scaling.
|
||||
* @day: Day of the month with a scaling factor, each increment represents 0.25
|
||||
* day.
|
||||
* @year: Year offset since 1985, each increment represents one year.
|
||||
* @local_minute_offset: Offset in minutes from UTC, can range from -125 to 125
|
||||
* minutes.
|
||||
* @local_hour_offset: Offset in hours from UTC, can range from -125 to 125
|
||||
* hours.
|
||||
*
|
||||
* This structure defines each component of the Time/Date as described in
|
||||
* PGN 65254, using each byte to represent different components of the standard
|
||||
* UTC time and optionally adjusted local time based on offsets.
|
||||
*/
|
||||
struct j1939_time_date_packet {
|
||||
uint8_t seconds;
|
||||
uint8_t minutes;
|
||||
uint8_t hours;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t year;
|
||||
int8_t local_minute_offset;
|
||||
int8_t local_hour_offset;
|
||||
};
|
||||
|
||||
#endif /* !_J1939_TIMEDATE_H_ */
|
||||
@@ -0,0 +1,456 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-only
|
||||
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/if.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "j1939_timedate_cmn.h"
|
||||
|
||||
#define J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS 10
|
||||
|
||||
struct j1939_timedate_srv_priv {
|
||||
int sock_nack;
|
||||
int sock_main;
|
||||
|
||||
struct sockaddr_can sockname;
|
||||
|
||||
struct j1939_timedate_stats stats;
|
||||
|
||||
struct libj1939_cmn cmn;
|
||||
};
|
||||
|
||||
static void gmtime_to_j1939_pgn_65254_td(struct j1939_time_date_packet *tdp)
|
||||
{
|
||||
struct tm utc_tm_buf, local_tm_buf;
|
||||
int hour_offset, minute_offset;
|
||||
struct tm *utc_tm, *local_tm;
|
||||
int year_since_1985;
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
utc_tm = gmtime_r(&now, &utc_tm_buf);
|
||||
local_tm = localtime_r(&now, &local_tm_buf);
|
||||
|
||||
if (local_tm) {
|
||||
/* Calculate the offsets */
|
||||
hour_offset = local_tm->tm_hour - utc_tm->tm_hour;
|
||||
minute_offset = local_tm->tm_min - utc_tm->tm_min;
|
||||
|
||||
/* Handle date rollover */
|
||||
if (local_tm->tm_mday != utc_tm->tm_mday) {
|
||||
if (local_tm->tm_hour < 12)
|
||||
hour_offset += 24; /* past midnight */
|
||||
else
|
||||
hour_offset -= 24; /* before midnight */
|
||||
}
|
||||
} else {
|
||||
/* The local time offsets cannot be determined at the moment */
|
||||
hour_offset = 0xF9;
|
||||
minute_offset = 0xFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Seconds (spn959):
|
||||
* Resolution: 0.25 /bit, 0 offset
|
||||
* Data Range: 0 to 250 (0 to 62.5 seconds)
|
||||
* Operational Range: 0 to 239 (0 to 59.75 seconds)
|
||||
*/
|
||||
tdp->seconds = (uint8_t)(utc_tm->tm_sec / 0.25);
|
||||
if (tdp->seconds > 239)
|
||||
tdp->seconds = 239;
|
||||
|
||||
/*
|
||||
* Minutes (spn960):
|
||||
* Resolution: 1 min/bit, 0 offset
|
||||
* Data Range: 0 to 250 (0 to 250 minutes)
|
||||
* Operational Range: 0 to 59 (0 to 59 minutes)
|
||||
*/
|
||||
tdp->minutes = (uint8_t)utc_tm->tm_min;
|
||||
if (tdp->minutes > 59)
|
||||
tdp->minutes = 59;
|
||||
|
||||
/*
|
||||
* Hours (spn961):
|
||||
* Resolution: 1 hr/bit, 0 offset
|
||||
* Data Range: 0 to 250 (0 to 250 hours)
|
||||
* Operational Range: 0 to 23 (0 to 23 hours)
|
||||
*/
|
||||
tdp->hours = (uint8_t)utc_tm->tm_hour;
|
||||
if (tdp->hours > 23)
|
||||
tdp->hours = 23;
|
||||
|
||||
/*
|
||||
* Day (spn962):
|
||||
* Resolution: 0.25 /bit, 0 offset
|
||||
* Data Range: 0 to 250 (0 to 62.5 days)
|
||||
* Operational Range: 1 to 127 (0.25 to 31.75 days)
|
||||
*/
|
||||
tdp->day = (uint8_t)(utc_tm->tm_mday / 0.25);
|
||||
if (tdp->day < 1 || tdp->day > 127)
|
||||
tdp->day = 1;
|
||||
|
||||
/*
|
||||
* Month (spn963):
|
||||
* Resolution: 1 month/bit, 0 offset
|
||||
* Data Range: 0 to 250 (0 to 250 months)
|
||||
* Operational Range: 1 to 12 (1 to 12 months)
|
||||
*/
|
||||
tdp->month = (uint8_t)(utc_tm->tm_mon + 1);
|
||||
if (tdp->month < 1 || tdp->month > 12)
|
||||
tdp->month = 1;
|
||||
|
||||
/*
|
||||
* Year (spn964):
|
||||
* Resolution: 1 year/bit, 1985 offset
|
||||
* Data Range: 0 to 250 (1985 to 2235)
|
||||
* Operational Range: 0 to 250 (1985 to 2235)
|
||||
*/
|
||||
year_since_1985 = utc_tm->tm_year - 85;
|
||||
if (year_since_1985 < 0) {
|
||||
/* Fallback to year 1985 if year is before 1985 */
|
||||
tdp->year = 0;
|
||||
} else if (year_since_1985 > 250) {
|
||||
/* Fallback to year 2235 if year is beyond 2235 */
|
||||
tdp->year = 250;
|
||||
} else {
|
||||
tdp->year = (uint8_t)year_since_1985;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local minute offset (spn1601):
|
||||
* Resolution: 1 min/bit, -125 offset
|
||||
* Data Range: -125 to 125 minutes
|
||||
* Operational Range: -59 to 59 minutes
|
||||
*/
|
||||
tdp->local_minute_offset = (int8_t)minute_offset;
|
||||
|
||||
/*
|
||||
* Local hour offset (spn1602):
|
||||
* Resolution: 1 hr/bit, -125 offset
|
||||
* Data Range: -125 to +125 hours
|
||||
* Operational Range: -24 to +23 hours
|
||||
* Note: If the local hour offset parameter is equal to 125 (0xFA),
|
||||
* the local time then the time parameter is the local time instead of
|
||||
* UTC.
|
||||
*/
|
||||
tdp->local_hour_offset = (int8_t)hour_offset;
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_send_res(struct j1939_timedate_srv_priv *priv,
|
||||
struct sockaddr_can *addr)
|
||||
{
|
||||
struct sockaddr_can peername = *addr;
|
||||
struct j1939_time_date_packet tdp;
|
||||
int ret;
|
||||
|
||||
gmtime_to_j1939_pgn_65254_td(&tdp);
|
||||
|
||||
peername.can_addr.j1939.pgn = J1939_PGN_TD;
|
||||
ret = sendto(priv->sock_main, &tdp, sizeof(tdp), 0,
|
||||
(struct sockaddr *)&peername, sizeof(peername));
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
pr_warn("failed to send data: %i (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check if the received message is a request for the time and date
|
||||
static int j1939_timedate_srv_process_request(struct j1939_timedate_srv_priv *priv,
|
||||
struct j1939_timedate_msg *msg)
|
||||
{
|
||||
|
||||
if (msg->buf[0] != (J1939_PGN_TD & 0xff) ||
|
||||
msg->buf[1] != ((J1939_PGN_TD >> 8) & 0xff) ||
|
||||
msg->buf[2] != ((J1939_PGN_TD >> 16) & 0xff)) {
|
||||
/* Don't care, not a time and date request */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return j1939_timedate_srv_send_res(priv, &msg->peername);
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_rx_buf(struct j1939_timedate_srv_priv *priv, struct j1939_timedate_msg *msg)
|
||||
{
|
||||
pgn_t pgn = msg->peername.can_addr.j1939.pgn;
|
||||
int ret = 0;
|
||||
|
||||
switch (pgn) {
|
||||
case J1939_PGN_REQUEST_PGN:
|
||||
ret = j1939_timedate_srv_process_request(priv, msg);
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: unsupported PGN: %x", __func__, pgn);
|
||||
/* Not a critical error */
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_rx_one(struct j1939_timedate_srv_priv *priv, int sock)
|
||||
{
|
||||
struct j1939_timedate_msg *msg;
|
||||
int flags = 0;
|
||||
int ret;
|
||||
|
||||
msg = malloc(sizeof(*msg));
|
||||
if (!msg) {
|
||||
pr_err("can't allocate rx msg struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->buf_size = J1939_TIMEDATE_MAX_TRANSFER_LENGH;
|
||||
msg->peer_addr_len = sizeof(msg->peername);
|
||||
msg->sock = sock;
|
||||
|
||||
ret = recvfrom(sock, &msg->buf[0], msg->buf_size, flags,
|
||||
(struct sockaddr *)&msg->peername, &msg->peer_addr_len);
|
||||
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("recvfrom() failed: %i %s", ret, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < 3) {
|
||||
pr_warn("received too short message: %i", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg->len = ret;
|
||||
|
||||
ret = j1939_timedate_srv_rx_buf(priv, msg);
|
||||
if (ret < 0) {
|
||||
pr_warn("failed to process rx buf: %i (%s)\n", ret,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_handle_events(struct j1939_timedate_srv_priv *priv,
|
||||
unsigned int nfds)
|
||||
{
|
||||
int ret;
|
||||
unsigned int n;
|
||||
|
||||
for (n = 0; n < nfds && n < priv->cmn.epoll_events_size; ++n) {
|
||||
struct epoll_event *ev = &priv->cmn.epoll_events[n];
|
||||
|
||||
if (!ev->events) {
|
||||
warn("no events");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->events & POLLIN) {
|
||||
ret = j1939_timedate_srv_rx_one(priv, ev->data.fd);
|
||||
if (ret) {
|
||||
warn("recv one");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_process_events_and_tasks(struct j1939_timedate_srv_priv *priv)
|
||||
{
|
||||
int ret, nfds;
|
||||
|
||||
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nfds > 0) {
|
||||
ret = j1939_timedate_srv_handle_events(priv, nfds);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_sock_main_prepare(struct j1939_timedate_srv_priv *priv)
|
||||
{
|
||||
struct sockaddr_can addr = priv->sockname;
|
||||
int ret;
|
||||
|
||||
ret = libj1939_open_socket();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->sock_main = ret;
|
||||
|
||||
ret = libj1939_bind_socket(priv->sock_main, &addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = libj1939_socket_prio(priv->sock_main,
|
||||
J1939_TIMEDATE_PRIO_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = libj1939_set_broadcast(priv->sock_main);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
|
||||
priv->sock_main, EPOLLIN);
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_sock_prepare(struct j1939_timedate_srv_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libj1939_create_epoll();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->cmn.epoll_fd = ret;
|
||||
|
||||
priv->cmn.epoll_events = calloc(J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS,
|
||||
sizeof(struct epoll_event));
|
||||
if (!priv->cmn.epoll_events)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->cmn.epoll_events_size = J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS;
|
||||
|
||||
return j1939_timedate_srv_sock_main_prepare(priv);
|
||||
}
|
||||
|
||||
static void j1939_timedate_srv_print_help(void)
|
||||
{
|
||||
printf("Usage: j1939-timedate-srv [options]\n");
|
||||
printf("Options:\n");
|
||||
printf(" --interface <interface_name> or -i <interface_name>\n");
|
||||
printf(" Specifies the CAN interface to use (mandatory).\n");
|
||||
printf(" --local-address <local_address_hex> or -a <local_address_hex>\n");
|
||||
printf(" Specifies the local address in hexadecimal (mandatory if\n");
|
||||
printf(" local name is not provided).\n");
|
||||
printf(" --local-name <local_name_hex> or -n <local_name_hex>\n");
|
||||
printf(" Specifies the local NAME in hexadecimal (mandatory if\n");
|
||||
printf(" local address is not provided).\n");
|
||||
printf("\n");
|
||||
printf("Note: Local address and local name are mutually exclusive and one\n");
|
||||
printf(" must be provided.\n");
|
||||
printf("\n");
|
||||
printf("Usage Examples:\n");
|
||||
printf(" Using local address:\n");
|
||||
printf(" j1939-timedate-srv -i vcan0 -a 0x90\n");
|
||||
printf("\n");
|
||||
printf(" Using local NAME:\n");
|
||||
printf(" j1939acd -r 64-95 -c /tmp/1122334455667789.jacd 1122334455667789 vcan0 &\n");
|
||||
printf(" j1939-timedate-srv -i vcan0 -n 0x1122334455667789\n");
|
||||
}
|
||||
|
||||
static int j1939_timedate_srv_parse_args(struct j1939_timedate_srv_priv *priv,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_can *local = &priv->sockname;
|
||||
bool local_address_set = false;
|
||||
bool local_name_set = false;
|
||||
bool interface_set = false;
|
||||
int long_index = 0;
|
||||
int opt;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"interface", required_argument, 0, 'i'},
|
||||
{"local-address", required_argument, 0, 'a'},
|
||||
{"local-name", required_argument, 0, 'n'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "a:n:i:", long_options, &long_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
local->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
|
||||
local_address_set = true;
|
||||
break;
|
||||
case 'n':
|
||||
local->can_addr.j1939.name = strtoull(optarg, NULL, 16);
|
||||
local_name_set = true;
|
||||
break;
|
||||
case 'i':
|
||||
local->can_ifindex = if_nametoindex(optarg);
|
||||
if (!local->can_ifindex) {
|
||||
pr_err("Interface %s not found. Error: %d (%s)\n",
|
||||
optarg, errno, strerror(errno));
|
||||
return -EINVAL;
|
||||
}
|
||||
interface_set = true;
|
||||
break;
|
||||
default:
|
||||
j1939_timedate_srv_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!interface_set) {
|
||||
pr_err("interface not specified");
|
||||
j1939_timedate_srv_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (local_address_set && local_name_set) {
|
||||
pr_err("local address and local name or remote address and remote name are mutually exclusive");
|
||||
j1939_timedate_srv_print_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct j1939_timedate_srv_priv *priv;
|
||||
struct timespec ts;
|
||||
int ret;
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (!priv)
|
||||
err(EXIT_FAILURE, "can't allocate priv");
|
||||
|
||||
bzero(priv, sizeof(*priv));
|
||||
|
||||
libj1939_init_sockaddr_can(&priv->sockname, J1939_PGN_REQUEST_PGN);
|
||||
|
||||
ret = j1939_timedate_srv_parse_args(priv, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
priv->cmn.next_send_time = ts;
|
||||
|
||||
ret = j1939_timedate_srv_sock_prepare(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (1) {
|
||||
ret = j1939_timedate_srv_process_events_and_tasks(priv);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
close(priv->cmn.epoll_fd);
|
||||
free(priv->cmn.epoll_events);
|
||||
|
||||
close(priv->sock_main);
|
||||
close(priv->sock_nack);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+9
-23
@@ -38,7 +38,6 @@ static const char help_msg[] =
|
||||
" e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
|
||||
" -c, --cache=FILE Cache file to save/restore the source address" "\n"
|
||||
" -a, --address=ADDRESS Start with Source Address ADDRESS" "\n"
|
||||
" -p, --prefix=STR Prefix to use when logging" "\n"
|
||||
"\n"
|
||||
"NAME is the 64bit nodename" "\n"
|
||||
"\n"
|
||||
@@ -54,14 +53,13 @@ static struct option long_opts[] = {
|
||||
{ "range", required_argument, NULL, 'r', },
|
||||
{ "cache", required_argument, NULL, 'c', },
|
||||
{ "address", required_argument, NULL, 'a', },
|
||||
{ "prefix", required_argument, NULL, 'p', },
|
||||
{ },
|
||||
};
|
||||
#else
|
||||
#define getopt_long(argc, argv, optstring, longopts, longindex) \
|
||||
getopt((argc), (argv), (optstring))
|
||||
#endif
|
||||
static const char optstring[] = "vr:c:a:p:?";
|
||||
static const char optstring[] = "vr:c:a:?";
|
||||
|
||||
/* byte swap functions */
|
||||
static inline int host_is_little_endian(void)
|
||||
@@ -114,10 +112,10 @@ static struct {
|
||||
int sig_alrm;
|
||||
int sig_usr1;
|
||||
int state;
|
||||
#define STATE_INITIAL 0
|
||||
#define STATE_REQ_SENT 1
|
||||
#define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */
|
||||
#define STATE_OPERATIONAL 3
|
||||
#define STATE_INITIAL 0
|
||||
#define STATE_REQ_SENT 1
|
||||
#define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */
|
||||
#define STATE_OPERATIONAL 3
|
||||
} s = {
|
||||
.intf = default_intf,
|
||||
.ranges = default_range,
|
||||
@@ -128,8 +126,8 @@ static struct {
|
||||
struct {
|
||||
uint64_t name;
|
||||
int flags;
|
||||
#define F_USE 0x01
|
||||
#define F_SEEN 0x02
|
||||
#define F_USE 0x01
|
||||
#define F_SEEN 0x02
|
||||
} addr[J1939_IDLE_ADDR /* =254 */];
|
||||
|
||||
/* lookup by name */
|
||||
@@ -211,7 +209,7 @@ static int open_socket(const char *device, uint64_t name)
|
||||
if (s.verbose)
|
||||
fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_FILTER, <filter>, %zd);\n", sizeof(filt));
|
||||
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER,
|
||||
&filt, sizeof(filt));
|
||||
&filt, sizeof(filt));
|
||||
if (ret < 0)
|
||||
err(1, "setsockopt filter");
|
||||
|
||||
@@ -219,7 +217,7 @@ static int open_socket(const char *device, uint64_t name)
|
||||
if (s.verbose)
|
||||
fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BROADCAST, %d, %zd);\n", value, sizeof(value));
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
|
||||
&value, sizeof(value));
|
||||
&value, sizeof(value));
|
||||
if (ret < 0)
|
||||
err(1, "setsockopt set broadcast");
|
||||
|
||||
@@ -466,9 +464,6 @@ int main(int argc, char *argv[])
|
||||
struct sockaddr_can saddr;
|
||||
uint64_t cmd_name;
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
program_invocation_name = program_invocation_short_name;
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
@@ -484,15 +479,6 @@ int main(int argc, char *argv[])
|
||||
case 'a':
|
||||
s.current_sa = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'p':
|
||||
#ifdef _GNU_SOURCE
|
||||
if (asprintf(&program_invocation_name, "%s.%s",
|
||||
program_invocation_short_name, optarg) < 0)
|
||||
err(1, "asprintf(program invocation name)");
|
||||
#else
|
||||
err(0, "compile with -D_GNU_SOURCE to use -p");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
|
||||
+20
-29
@@ -31,11 +31,11 @@
|
||||
* strict type-checking.. See the
|
||||
* "unnecessary" pointer comparison.
|
||||
*/
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
|
||||
struct j1939cat_stats {
|
||||
@@ -97,17 +97,8 @@ static const char help_msg[] =
|
||||
|
||||
static const char optstring[] = "?hi:vs:rp:P:R:B";
|
||||
|
||||
|
||||
static void j1939cat_init_sockaddr_can(struct sockaddr_can *sac)
|
||||
{
|
||||
sac->can_family = AF_CAN;
|
||||
sac->can_addr.j1939.addr = J1939_NO_ADDR;
|
||||
sac->can_addr.j1939.name = J1939_NO_NAME;
|
||||
sac->can_addr.j1939.pgn = J1939_NO_PGN;
|
||||
}
|
||||
|
||||
static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd,
|
||||
const void *buf, size_t buf_size)
|
||||
const void *buf, size_t buf_size)
|
||||
{
|
||||
ssize_t num_sent;
|
||||
int flags = 0;
|
||||
@@ -141,7 +132,7 @@ static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd,
|
||||
}
|
||||
|
||||
static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *name,
|
||||
struct timespec *cur)
|
||||
struct timespec *cur)
|
||||
{
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
|
||||
@@ -149,8 +140,8 @@ static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *nam
|
||||
return;
|
||||
|
||||
fprintf(stderr, " %s: %llu s %llu us (seq=%03u, send=%07u)",
|
||||
name, (unsigned long long)cur->tv_sec, (unsigned long long)cur->tv_nsec / 1000,
|
||||
stats->tskey, stats->send);
|
||||
name, (unsigned long long)cur->tv_sec, (unsigned long long)cur->tv_nsec / 1000,
|
||||
stats->tskey, stats->send);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -235,7 +226,7 @@ static int j1939cat_extract_serr(struct j1939cat_priv *priv)
|
||||
stats->tskey = serr->ee_data;
|
||||
|
||||
j1939cat_print_timestamp(priv, j1939cat_tstype_to_str(serr->ee_info),
|
||||
&tss->ts[0]);
|
||||
&tss->ts[0]);
|
||||
|
||||
if (serr->ee_info == SCM_TSTAMP_SCHED)
|
||||
return -EINTR;
|
||||
@@ -347,7 +338,7 @@ static int j1939cat_recv_err(struct j1939cat_priv *priv)
|
||||
}
|
||||
|
||||
static int j1939cat_send_loop(struct j1939cat_priv *priv, int out_fd, char *buf,
|
||||
size_t buf_size)
|
||||
size_t buf_size)
|
||||
{
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
ssize_t count;
|
||||
@@ -420,7 +411,7 @@ static int j1939cat_send_loop(struct j1939cat_priv *priv, int out_fd, char *buf,
|
||||
}
|
||||
|
||||
static int j1939cat_sendfile(struct j1939cat_priv *priv, int out_fd, int in_fd,
|
||||
off_t *offset, size_t count)
|
||||
off_t *offset, size_t count)
|
||||
{
|
||||
int ret = EXIT_SUCCESS;
|
||||
off_t orig = 0;
|
||||
@@ -626,7 +617,7 @@ static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
|
||||
|
||||
if (priv->todo_prio >= 0) {
|
||||
ret = setsockopt(priv->sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
|
||||
&priv->todo_prio, sizeof(priv->todo_prio));
|
||||
&priv->todo_prio, sizeof(priv->todo_prio));
|
||||
if (ret < 0) {
|
||||
warn("set priority %i", priv->todo_prio);
|
||||
return EXIT_FAILURE;
|
||||
@@ -642,11 +633,11 @@ static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
|
||||
}
|
||||
|
||||
sock_opt = SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_OPT_CMSG |
|
||||
SOF_TIMESTAMPING_TX_ACK |
|
||||
SOF_TIMESTAMPING_TX_SCHED |
|
||||
SOF_TIMESTAMPING_OPT_STATS | SOF_TIMESTAMPING_OPT_TSONLY |
|
||||
SOF_TIMESTAMPING_OPT_ID | SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
SOF_TIMESTAMPING_OPT_CMSG |
|
||||
SOF_TIMESTAMPING_TX_ACK |
|
||||
SOF_TIMESTAMPING_TX_SCHED |
|
||||
SOF_TIMESTAMPING_OPT_STATS | SOF_TIMESTAMPING_OPT_TSONLY |
|
||||
SOF_TIMESTAMPING_OPT_ID | SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
|
||||
if (setsockopt(priv->sock, SOL_SOCKET, SO_TIMESTAMPING,
|
||||
(char *) &sock_opt, sizeof(sock_opt)))
|
||||
@@ -766,8 +757,8 @@ int main(int argc, char *argv[])
|
||||
priv->polltimeout = 100000;
|
||||
priv->repeat = 1;
|
||||
|
||||
j1939cat_init_sockaddr_can(&priv->sockname);
|
||||
j1939cat_init_sockaddr_can(&priv->peername);
|
||||
libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
|
||||
libj1939_init_sockaddr_can(&priv->peername, J1939_NO_PGN);
|
||||
|
||||
ret = j1939cat_parse_args(priv, argc, argv);
|
||||
if (ret)
|
||||
|
||||
+10
-10
@@ -76,7 +76,7 @@ static struct {
|
||||
static const int ival_1 = 1;
|
||||
|
||||
static char ctrlmsg[
|
||||
CMSG_SPACE(sizeof(struct timeval))
|
||||
CMSG_SPACE(sizeof(struct timeval))
|
||||
+ CMSG_SPACE(sizeof(uint8_t)) /* dest addr */
|
||||
+ CMSG_SPACE(sizeof(uint64_t)) /* dest name */
|
||||
+ CMSG_SPACE(sizeof(uint8_t)) /* priority */
|
||||
@@ -99,7 +99,7 @@ int main(int argc, char **argv)
|
||||
int filter = 0;
|
||||
uint8_t priority, dst_addr;
|
||||
uint64_t dst_name;
|
||||
long recvflags;
|
||||
uint64_t recvflags;
|
||||
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
@@ -230,11 +230,11 @@ int main(int argc, char **argv)
|
||||
case SOL_SOCKET:
|
||||
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
|
||||
memcpy(&tdut, CMSG_DATA(cmsg), sizeof(tdut));
|
||||
recvflags |= 1 << cmsg->cmsg_type;
|
||||
recvflags |= 1ULL << cmsg->cmsg_type;
|
||||
}
|
||||
break;
|
||||
case SOL_CAN_J1939:
|
||||
recvflags |= 1 << cmsg->cmsg_type;
|
||||
recvflags |= 1ULL << cmsg->cmsg_type;
|
||||
if (cmsg->cmsg_type == SCM_J1939_DEST_ADDR)
|
||||
dst_addr = *CMSG_DATA(cmsg);
|
||||
else if (cmsg->cmsg_type == SCM_J1939_DEST_NAME)
|
||||
@@ -245,7 +245,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
}
|
||||
if (recvflags & (1 << SCM_TIMESTAMP)) {
|
||||
if (recvflags & (1ULL << SCM_TIMESTAMP)) {
|
||||
if ('z' == s.time) {
|
||||
if (!tref.tv_sec)
|
||||
tref = tdut;
|
||||
@@ -264,15 +264,15 @@ abs_time:
|
||||
struct tm tm;
|
||||
tm = *localtime(&tdut.tv_sec);
|
||||
printf("(%04u%02u%02uT%02u%02u%02u.%04llu)",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
(unsigned long long)tdut.tv_usec/100);
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
(unsigned long long)tdut.tv_usec/100);
|
||||
}
|
||||
}
|
||||
printf(" %s ", libj1939_addr2str(&src));
|
||||
if (recvflags & (1 << SCM_J1939_DEST_NAME))
|
||||
if (recvflags & (1ULL << SCM_J1939_DEST_NAME))
|
||||
printf("%016llx ", (unsigned long long)dst_name);
|
||||
else if (recvflags & (1 << SCM_J1939_DEST_ADDR))
|
||||
else if (recvflags & (1ULL << SCM_J1939_DEST_ADDR))
|
||||
printf("%02x ", dst_addr);
|
||||
else
|
||||
printf("- ");
|
||||
|
||||
@@ -68,9 +68,9 @@ static struct {
|
||||
int pkt_len;
|
||||
int priority;
|
||||
int defined;
|
||||
#define DEF_SRC 1
|
||||
#define DEF_DST 2
|
||||
#define DEF_PRIO 4
|
||||
#define DEF_SRC 1
|
||||
#define DEF_DST 2
|
||||
#define DEF_PRIO 4
|
||||
struct sockaddr_can src, dst;
|
||||
} s = {
|
||||
.priority = 6,
|
||||
@@ -94,9 +94,6 @@ int main(int argc, char **argv)
|
||||
struct pollfd pfd[2];
|
||||
uint8_t *buf;
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
program_invocation_name = program_invocation_short_name;
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
|
||||
@@ -83,8 +83,8 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
|
||||
|
||||
/* CAN DLC to real data length conversion helpers */
|
||||
|
||||
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
static const unsigned char dlc2len[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from raw data length code (DLC) */
|
||||
unsigned char can_fd_dlc2len(unsigned char dlc)
|
||||
@@ -92,16 +92,17 @@ unsigned char can_fd_dlc2len(unsigned char dlc)
|
||||
return dlc2len[dlc & 0x0F];
|
||||
}
|
||||
|
||||
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
9, 9, 9, 9, /* 9 - 12 */
|
||||
10, 10, 10, 10, /* 13 - 16 */
|
||||
11, 11, 11, 11, /* 17 - 20 */
|
||||
12, 12, 12, 12, /* 21 - 24 */
|
||||
13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
||||
static const unsigned char len2dlc[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
9, 9, 9, 9, /* 9 - 12 */
|
||||
10, 10, 10, 10, /* 13 - 16 */
|
||||
11, 11, 11, 11, /* 17 - 20 */
|
||||
12, 12, 12, 12, /* 21 - 24 */
|
||||
13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
unsigned char can_fd_len2dlc(unsigned char len)
|
||||
@@ -154,7 +155,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_canframe(char *cs, cu_t *cu)
|
||||
int parse_canframe(char *cs, union cfu *cu)
|
||||
{
|
||||
/* documentation see lib.h */
|
||||
|
||||
@@ -169,21 +170,23 @@ int parse_canframe(char *cs, cu_t *cu)
|
||||
|
||||
memset(cu, 0, sizeof(*cu)); /* init CAN CC/FD/XL frame, e.g. LEN = 0 */
|
||||
|
||||
if (len < 4)
|
||||
return 0;
|
||||
if (len >= 4 && cs[3] == CANID_DELIM) { /* 3 digits SFF CAN ID */
|
||||
|
||||
if (cs[3] == CANID_DELIM) { /* 3 digits SFF */
|
||||
idx = 4; /* start of frame data */
|
||||
|
||||
idx = 4;
|
||||
/* get 3 digits SFF CAN ID value */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||
return 0;
|
||||
cu->cc.can_id |= tmp << (2 - i) * 4;
|
||||
}
|
||||
|
||||
} else if (cs[5] == CANID_DELIM) { /* 5 digits CAN XL VCID/PRIO*/
|
||||
} else if (len >= 21 && cs[5] == CANID_DELIM && cs[20] == CANID_DELIM) {
|
||||
/* 5 digits CAN XL VCID/PRIO - but also check for 2nd '#' here */
|
||||
|
||||
idx = 6;
|
||||
idx = 6; /* start of CAN XL frame extra content (AF, SDT, etc) */
|
||||
|
||||
/* get 5 digits CAN XL VCID/PRIO */
|
||||
for (i = 0; i < 5; i++) {
|
||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||
return 0;
|
||||
@@ -195,9 +198,11 @@ int parse_canframe(char *cs, cu_t *cu)
|
||||
cu->xl.prio &= CANXL_PRIO_MASK;
|
||||
cu->xl.prio |= tmp;
|
||||
|
||||
} else if (cs[8] == CANID_DELIM) { /* 8 digits EFF */
|
||||
} else if (len >= 9 && cs[8] == CANID_DELIM) { /* 8 digits EFF CAN ID */
|
||||
|
||||
idx = 9;
|
||||
idx = 9; /* start of frame data */
|
||||
|
||||
/* get 8 digits EFF CAN ID value */
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||
return 0;
|
||||
@@ -238,11 +243,12 @@ int parse_canframe(char *cs, cu_t *cu)
|
||||
cu->fd.flags |= CANFD_FDF; /* dual-use */
|
||||
idx += 2;
|
||||
|
||||
} else if (cs[idx + 14] == CANID_DELIM) { /* CAN XL frame '#80:00:11223344#' */
|
||||
} else if (idx == 6) { /* CAN XL frame extra content '#80:00:11223344#' */
|
||||
maxdlen = CANXL_MAX_DLEN;
|
||||
mtu = CANXL_MTU;
|
||||
data = cu->xl.data; /* fill CAN XL data */
|
||||
data = cu->xl.data; /* overwrite pointer to CAN XL data */
|
||||
|
||||
/* get CAN XL frame extra content */
|
||||
if ((cs[idx + 2] != XL_HDR_DELIM) || (cs[idx + 5] != XL_HDR_DELIM))
|
||||
return 0;
|
||||
|
||||
@@ -276,6 +282,7 @@ int parse_canframe(char *cs, cu_t *cu)
|
||||
idx++; /* skip CANID_DELIM */
|
||||
}
|
||||
|
||||
/* copy CAN frame data content */
|
||||
for (i = 0, dlen = 0; i < maxdlen; i++) {
|
||||
if (cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */
|
||||
idx++;
|
||||
@@ -308,7 +315,7 @@ int parse_canframe(char *cs, cu_t *cu)
|
||||
return mtu;
|
||||
}
|
||||
|
||||
int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep)
|
||||
int snprintf_canframe(char *buf, size_t size, union cfu *cu, int sep)
|
||||
{
|
||||
/* documentation see lib.h */
|
||||
|
||||
@@ -432,7 +439,7 @@ int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep)
|
||||
return offset;
|
||||
}
|
||||
|
||||
int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view)
|
||||
int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view)
|
||||
{
|
||||
/* documentation see lib.h */
|
||||
|
||||
@@ -777,8 +784,8 @@ static int snprintf_error_ctrl(char *buf, size_t len, const struct canfd_frame *
|
||||
|
||||
n += snprintf(buf + n, len - n, "{");
|
||||
n += snprintf_error_data(buf + n, len - n, cf->data[1],
|
||||
controller_problems,
|
||||
ARRAY_SIZE(controller_problems));
|
||||
controller_problems,
|
||||
ARRAY_SIZE(controller_problems));
|
||||
n += snprintf(buf + n, len - n, "}");
|
||||
|
||||
return n;
|
||||
@@ -793,8 +800,8 @@ static int snprintf_error_prot(char *buf, size_t len, const struct canfd_frame *
|
||||
|
||||
n += snprintf(buf + n, len - n, "{{");
|
||||
n += snprintf_error_data(buf + n, len - n, cf->data[2],
|
||||
protocol_violation_types,
|
||||
ARRAY_SIZE(protocol_violation_types));
|
||||
protocol_violation_types,
|
||||
ARRAY_SIZE(protocol_violation_types));
|
||||
n += snprintf(buf + n, len - n, "}{");
|
||||
if (cf->data[3] > 0 &&
|
||||
cf->data[3] < ARRAY_SIZE(protocol_violation_locations))
|
||||
@@ -819,7 +826,7 @@ static int snprintf_error_cnt(char *buf, size_t len, const struct canfd_frame *c
|
||||
}
|
||||
|
||||
int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
|
||||
const char* sep)
|
||||
const char* sep)
|
||||
{
|
||||
canid_t class, mask;
|
||||
int i, n = 0, classes = 0;
|
||||
@@ -858,7 +865,7 @@ int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf
|
||||
n += tmp_n;
|
||||
if (mask == CAN_ERR_LOSTARB)
|
||||
n += snprintf_error_lostarb(buf + n, len - n,
|
||||
cf);
|
||||
cf);
|
||||
if (mask == CAN_ERR_CRTL)
|
||||
n += snprintf_error_ctrl(buf + n, len - n, cf);
|
||||
if (mask == CAN_ERR_PROT)
|
||||
@@ -878,7 +885,7 @@ int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf
|
||||
}
|
||||
|
||||
int64_t timespec_diff_ms(struct timespec *ts1,
|
||||
struct timespec *ts2)
|
||||
struct timespec *ts2)
|
||||
{
|
||||
int64_t diff = (ts1->tv_sec - ts2->tv_sec) * 1000;
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define pr_debug(fmt, args...) printf(fmt, ##args)
|
||||
#else
|
||||
@@ -57,11 +59,11 @@ static inline int pr_debug(const char* fmt, ...) {return 0;}
|
||||
#endif
|
||||
|
||||
/* CAN CC/FD/XL frame union */
|
||||
typedef union {
|
||||
union cfu {
|
||||
struct can_frame cc;
|
||||
struct canfd_frame fd;
|
||||
struct canxl_frame xl;
|
||||
} cu_t;
|
||||
};
|
||||
|
||||
/*
|
||||
* The buffer size for ASCII CAN frame string representations
|
||||
@@ -108,7 +110,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen);
|
||||
*
|
||||
*/
|
||||
|
||||
int parse_canframe(char *cs, cu_t *cu);
|
||||
int parse_canframe(char *cs, union cfu *cu);
|
||||
/*
|
||||
* Transfers a valid ASCII string describing a CAN frame into the CAN union
|
||||
* containing CAN CC/FD/XL structs.
|
||||
@@ -178,7 +180,7 @@ int parse_canframe(char *cs, cu_t *cu);
|
||||
* - CAN FD frames do not have a RTR bit
|
||||
*/
|
||||
|
||||
int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep);
|
||||
int snprintf_canframe(char *buf, size_t size, union cfu *cu, int sep);
|
||||
/*
|
||||
* Creates a CAN frame hexadecimal output in compact format.
|
||||
* The CAN data[] is separated by '.' when sep != 0.
|
||||
@@ -211,7 +213,7 @@ int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep);
|
||||
|
||||
#define SWAP_DELIMITER '`'
|
||||
|
||||
int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view);
|
||||
int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view);
|
||||
/*
|
||||
* Creates a CAN frame hexadecimal output in user readable format.
|
||||
*
|
||||
|
||||
+264
-5
@@ -11,19 +11,24 @@
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
#include "lib.h"
|
||||
|
||||
/* static data */
|
||||
static struct if_nameindex *saved;
|
||||
@@ -195,3 +200,257 @@ const char *libj1939_addr2str(const struct sockaddr_can *can)
|
||||
return buf;
|
||||
}
|
||||
|
||||
void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn)
|
||||
{
|
||||
sac->can_family = AF_CAN;
|
||||
sac->can_addr.j1939.addr = J1939_NO_ADDR;
|
||||
sac->can_addr.j1939.name = J1939_NO_NAME;
|
||||
sac->can_addr.j1939.pgn = pgn;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_open_socket - Open a new J1939 socket
|
||||
*
|
||||
* This function opens a new J1939 socket.
|
||||
*
|
||||
* Return: The file descriptor of the new socket, or a negative error code.
|
||||
*/
|
||||
int libj1939_open_socket(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Create a new CAN J1939 socket */
|
||||
ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
|
||||
if (ret < 0) {
|
||||
/* Get the error code and print an error message */
|
||||
ret = -errno;
|
||||
pr_err("socket(j1939): %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_bind_socket - Bind a J1939 socket to a specific address
|
||||
* @sock: The file descriptor of the socket
|
||||
* @addr: The address to bind to
|
||||
*
|
||||
* This function binds a J1939 socket to a specific address.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code.
|
||||
*/
|
||||
int libj1939_bind_socket(int sock, struct sockaddr_can *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bind(sock, (void *)addr, sizeof(*addr));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("failed to bind: %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_connect_socket - Connects a socket to a CAN address.
|
||||
* @sock: The socket file descriptor.
|
||||
* @addr: The CAN address to connect to.
|
||||
*
|
||||
* This function attempts to establish a connection between the given socket
|
||||
* and the specified CAN address. If the connection fails, it logs an error
|
||||
* message with the error code and a description of the error.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int libj1939_connect_socket(int sock, struct sockaddr_can *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = connect(sock, (void *)addr, sizeof(*addr));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("failed to connect socket: %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_socket_prio - Set the priority of a J1939 socket
|
||||
* @sock: The file descriptor of the socket
|
||||
* @prio: The priority to set
|
||||
*
|
||||
* This function sets the priority of a J1939 socket.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code.
|
||||
*/
|
||||
int libj1939_socket_prio(int sock, int prio)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
|
||||
&prio, sizeof(prio));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret,
|
||||
strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_set_broadcast - Enable broadcast on a J1939 socket
|
||||
* @sock: The file descriptor of the socket
|
||||
*
|
||||
* This function enables broadcast on a J1939 socket.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code.
|
||||
*/
|
||||
int libj1939_set_broadcast(int sock)
|
||||
{
|
||||
int broadcast = true;
|
||||
int ret;
|
||||
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
|
||||
sizeof(broadcast));
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_add_socket_to_epoll - Add a socket to an epoll instance
|
||||
* @epoll_fd: The file descriptor of the epoll instance
|
||||
* @sock: The file descriptor of the socket
|
||||
* @events: The events to monitor
|
||||
*
|
||||
* This function adds a socket to an epoll instance.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code.
|
||||
*/
|
||||
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events)
|
||||
{
|
||||
struct epoll_event ev = {0};
|
||||
int ret;
|
||||
|
||||
ev.events = events;
|
||||
ev.data.fd = sock;
|
||||
|
||||
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
|
||||
if (ret < 0) {
|
||||
ret = errno;
|
||||
pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_create_epoll - Create a new epoll instance
|
||||
*
|
||||
* This function creates a new epoll instance.
|
||||
*
|
||||
* Return: The file descriptor of the new epoll instance, or a negative error
|
||||
* code.
|
||||
*/
|
||||
int libj1939_create_epoll(void)
|
||||
{
|
||||
int ret, epoll_fd;
|
||||
|
||||
epoll_fd = epoll_create1(0);
|
||||
if (epoll_fd < 0) {
|
||||
ret = -errno;
|
||||
pr_err("epoll_create1: %d (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return epoll_fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_get_timeout_ms - Get the timeout in milliseconds until a specific
|
||||
* time
|
||||
* @ts: The time to wait for
|
||||
* @return: The timeout in milliseconds until the specified time
|
||||
*
|
||||
* This function calculates the timeout in milliseconds until a specific time.
|
||||
*
|
||||
* Return: The timeout in milliseconds until the specified time.
|
||||
*/
|
||||
static int libj1939_get_timeout_ms(struct timespec *ts)
|
||||
{
|
||||
struct timespec curr_time;
|
||||
int64_t time_diff;
|
||||
int timeout_ms;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &curr_time);
|
||||
time_diff = timespec_diff_ms(ts, &curr_time);
|
||||
if (time_diff < 0) {
|
||||
/* Too late to send next message. Send it now */
|
||||
timeout_ms = 0;
|
||||
} else {
|
||||
if (time_diff > INT_MAX) {
|
||||
pr_warn("timeout too long: %" PRId64 " ms", time_diff);
|
||||
time_diff = INT_MAX;
|
||||
}
|
||||
|
||||
timeout_ms = time_diff;
|
||||
}
|
||||
|
||||
return timeout_ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* libj1939_prepare_for_events - Prepare and wait for events on an epoll
|
||||
* @cmn: The common J1939 instance data
|
||||
* @nfds: The number of file descriptors that are ready
|
||||
* @dont_wait: Don't wait for events, just check if there are any
|
||||
*
|
||||
* This function calculates the timeout until the next message should be sent
|
||||
* or any other event should be handled, prepares the epoll instance for events
|
||||
* by waiting for the specified timeout or until an event occurs, and waits for
|
||||
* events on the epoll instance.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code.
|
||||
*/
|
||||
int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds,
|
||||
bool dont_wait)
|
||||
{
|
||||
int ret, timeout_ms;
|
||||
|
||||
if (dont_wait)
|
||||
timeout_ms = 0;
|
||||
else
|
||||
timeout_ms = libj1939_get_timeout_ms(&cmn->next_send_time);
|
||||
|
||||
ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events,
|
||||
cmn->epoll_events_size, timeout_ms);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
if (ret != -EINTR) {
|
||||
*nfds = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*nfds = ret;
|
||||
|
||||
ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_err("failed to get time: %i (%s)", ret, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+25
-1
@@ -13,9 +13,12 @@
|
||||
/* needed on some 64 bit platforms to get consistent 64-bit types */
|
||||
#define __SANE_USERSPACE_TYPES__
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/j1939.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifndef J1939_LIB_H
|
||||
#define J1939_LIB_H
|
||||
@@ -24,10 +27,31 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct libj1939_cmn {
|
||||
int epoll_fd;
|
||||
struct epoll_event *epoll_events;
|
||||
size_t epoll_events_size;
|
||||
struct timespec next_send_time;
|
||||
struct timespec last_time;
|
||||
};
|
||||
|
||||
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr);
|
||||
extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can);
|
||||
extern const char *libj1939_addr2str(const struct sockaddr_can *can);
|
||||
|
||||
void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
|
||||
|
||||
int libj1939_open_socket(void);
|
||||
int libj1939_bind_socket(int sock, struct sockaddr_can *addr);
|
||||
int libj1939_connect_socket(int sock, struct sockaddr_can *addr);
|
||||
int libj1939_socket_prio(int sock, int prio);
|
||||
int libj1939_set_broadcast(int sock);
|
||||
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);
|
||||
int libj1939_create_epoll(void);
|
||||
|
||||
int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds,
|
||||
bool dont_wait);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -54,6 +54,15 @@
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
#define ASC_F_XLF 0x00400000
|
||||
#define ASC_F_RES 0x00800000
|
||||
#define ASC_F_SEC 0x01000000
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static void print_usage(char *prg)
|
||||
@@ -65,18 +74,17 @@ static void print_usage(char *prg)
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
|
||||
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
|
||||
fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n");
|
||||
fprintf(stderr, " -f (use CANFD format also for CAN CC)\n");
|
||||
fprintf(stderr, " -x (use CANXL format also for CAN CC/FD)\n");
|
||||
fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n");
|
||||
}
|
||||
|
||||
static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
|
||||
static void can_asc(struct can_frame *cf, int devno, int nortrdlc,
|
||||
char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
unsigned int i, dlc;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
int dlc;
|
||||
struct can_frame *cf = (struct can_frame *)cfd; /* for len8_dlc */
|
||||
|
||||
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
|
||||
|
||||
@@ -93,7 +101,7 @@ static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
fprintf(outfile, "%-15s %s ", id, dir);
|
||||
fprintf(outfile, "%-15s %-4s ", id, dir);
|
||||
|
||||
if (cf->len == CAN_MAX_DLC &&
|
||||
cf->len8_dlc > CAN_MAX_DLC &&
|
||||
@@ -120,19 +128,13 @@ static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
|
||||
static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
|
||||
char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
unsigned int flags = 0;
|
||||
unsigned int dlen = cf->len;
|
||||
unsigned int dlc = can_fd_len2dlc(dlen);
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
|
||||
/* check for extra info */
|
||||
if (strlen(extra_info) > 0) {
|
||||
/* only the first char is defined so far */
|
||||
@@ -140,7 +142,7 @@ static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
fprintf(outfile, "CANFD %3d %s ", devno, dir); /* 3 column channel number right aligned */
|
||||
fprintf(outfile, "CANFD %3d %-4s ", devno, dir); /* 3 column channel number right aligned */
|
||||
|
||||
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
|
||||
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
@@ -174,16 +176,127 @@ static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
|
||||
|
||||
fprintf(outfile, "%2d", dlen);
|
||||
|
||||
for (i = 0; i < (int)dlen; i++) {
|
||||
for (i = 0; i < dlen; i++) {
|
||||
fprintf(outfile, " %02X", cf->data[i]);
|
||||
}
|
||||
|
||||
fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags);
|
||||
}
|
||||
|
||||
static void canxl_asc(union cfu *cu, int devno, int mtu,
|
||||
char *extra_info, FILE *outfile)
|
||||
{
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
char *frametype;
|
||||
unsigned char *dataptr;
|
||||
unsigned int i, dlen, dlc, flags = 0;
|
||||
|
||||
/* check for extra info */
|
||||
if (strlen(extra_info) > 0) {
|
||||
/* only the first char is defined so far */
|
||||
if (extra_info[0] == 'T')
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
switch (mtu) {
|
||||
case CANXL_MTU:
|
||||
sprintf(id, "%X", cu->xl.prio & CANXL_PRIO_MASK);
|
||||
frametype = "XLFF";
|
||||
|
||||
dataptr = &cu->xl.data[0];
|
||||
dlen = cu->xl.len;
|
||||
dlc = dlen - 1;
|
||||
flags = (ASC_F_XLF | ASC_F_FDF | ASC_F_BRS);
|
||||
|
||||
if (cu->xl.flags & CANXL_SEC)
|
||||
flags |= ASC_F_SEC;
|
||||
if (cu->xl.flags & CANXL_RRS)
|
||||
flags |= ASC_F_RES;
|
||||
break;
|
||||
|
||||
case CANFD_MTU:
|
||||
if (cu->fd.can_id & CAN_EFF_FLAG) {
|
||||
sprintf(id, "%Xx", cu->fd.can_id & CAN_EFF_MASK);
|
||||
frametype = "FEFF";
|
||||
} else {
|
||||
sprintf(id, "%X", cu->fd.can_id & CAN_SFF_MASK);
|
||||
frametype = "FBFF";
|
||||
}
|
||||
|
||||
dataptr = &cu->fd.data[0];
|
||||
dlen = cu->fd.len;
|
||||
dlc = can_fd_len2dlc(dlen);
|
||||
flags = ASC_F_FDF;
|
||||
if (cu->fd.flags & CANFD_BRS)
|
||||
flags |= ASC_F_BRS;
|
||||
if (cu->fd.flags & CANFD_ESI)
|
||||
flags |= ASC_F_ESI;
|
||||
break;
|
||||
|
||||
case CAN_MTU:
|
||||
if (cu->cc.can_id & CAN_EFF_FLAG) {
|
||||
sprintf(id, "%Xx", cu->cc.can_id & CAN_EFF_MASK);
|
||||
frametype = "CEFF";
|
||||
} else {
|
||||
sprintf(id, "%X", cu->cc.can_id & CAN_SFF_MASK);
|
||||
frametype = "CBFF";
|
||||
}
|
||||
|
||||
dataptr = &cu->cc.data[0];
|
||||
dlen = cu->cc.len;
|
||||
dlc = dlen ;
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((dlen == CAN_MAX_DLEN) && (cu->cc.len8_dlc > CAN_MAX_DLEN) &&
|
||||
(cu->cc.len8_dlc <= CAN_MAX_RAW_DLC))
|
||||
dlc = cu->cc.len8_dlc;
|
||||
|
||||
if (cu->cc.can_id & CAN_RTR_FLAG) {
|
||||
/* no data length but dlc for RTR frames */
|
||||
dlen = 0;
|
||||
flags = ASC_F_RTR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(outfile, "CANXL %3d %-4s ", devno, dir); /* 3 column channel number and direction */
|
||||
|
||||
fprintf(outfile, "%s 984438 4656 ", frametype); /* frame type / msg duration / bit count */
|
||||
|
||||
fprintf(outfile, "%9s ", id); /* ID / symbolic name (empty) */
|
||||
|
||||
if (mtu == CANXL_MTU) /* SDT, SEC bit for CAN XL only */
|
||||
fprintf(outfile, "%02x %d ", cu->xl.sdt, (cu->xl.flags & CANXL_SEC)?1:0);
|
||||
|
||||
fprintf(outfile, "%x %d", dlc, dlen); /* DLC and data length */
|
||||
|
||||
if (mtu == CANXL_MTU) /* SBC / PCRC / VCID / AF */
|
||||
fprintf(outfile, " 1 1f96 %02x %08x",
|
||||
(unsigned char)((cu->xl.prio >> CANXL_VCID_OFFSET) & CANXL_VCID_VAL_MASK),
|
||||
cu->xl.af);
|
||||
|
||||
for (i = 0; i < dlen; i++) {
|
||||
fprintf(outfile, " %02x", dataptr[i]);
|
||||
}
|
||||
|
||||
if (mtu == CANFD_MTU) /* stuff field */
|
||||
fprintf(outfile, " 8");
|
||||
|
||||
fprintf(outfile, " 123123 %08x %08x", flags, 0); /* fcsc, msg flags, msg flags ext */
|
||||
|
||||
fprintf(outfile, /* bitrate settings for CC/FD/XL */
|
||||
" 000000050005000e 0000000000a00010"
|
||||
" 0000000a000a001d 0000000000a00002"
|
||||
" 000000100010000f 0000000000a00001");
|
||||
}
|
||||
|
||||
#define DEVSZ 22
|
||||
#define EXTRASZ 20
|
||||
#define TIMESZ sizeof("(1345212884.318850) ")
|
||||
#define TIMESZ sizeof("(1345212884.318850123) ")
|
||||
#define BUFSZ (DEVSZ + AFRSZ + EXTRASZ + TIMESZ)
|
||||
|
||||
/* adapt sscanf() functions below on error */
|
||||
@@ -201,15 +314,15 @@ int main(int argc, char **argv)
|
||||
{
|
||||
static char buf[BUFSZ], device[DEVSZ], afrbuf[AFRSZ], extra_info[EXTRASZ];
|
||||
|
||||
static cu_t cu;
|
||||
static union cfu cu;
|
||||
static struct timeval tv, start_tv;
|
||||
FILE *infile = stdin;
|
||||
FILE *outfile = stdout;
|
||||
static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu;
|
||||
static int maxdev, devno, i, crlf, fdfmt, xlfmt, nortrdlc, d4, opt, mtu;
|
||||
int print_banner = 1;
|
||||
unsigned long long sec, usec;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:O:4nfxr?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -235,6 +348,10 @@ int main(int argc, char **argv)
|
||||
fdfmt = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
xlfmt = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
nortrdlc = 1;
|
||||
break;
|
||||
@@ -290,7 +407,22 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
tv.tv_sec = sec;
|
||||
tv.tv_usec = usec;
|
||||
|
||||
/*
|
||||
* ensure the fractions of seconds are 6 or 9 decimal places long to catch
|
||||
* 3rd party or handcrafted logfiles that treat the timestamp as float
|
||||
*/
|
||||
switch (strchr(buf, ')') - strchr(buf, '.')) {
|
||||
case 7: //6
|
||||
tv.tv_usec = usec;
|
||||
break;
|
||||
case 10: //9
|
||||
tv.tv_usec = usec / 1000;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "timestamp format in logfile requires 6 or 9 decimal places\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_banner) { /* print banner */
|
||||
print_banner = 0;
|
||||
@@ -300,6 +432,9 @@ int main(int argc, char **argv)
|
||||
(crlf)?"\r\n":"\n");
|
||||
fprintf(outfile, "no internal events logged%s",
|
||||
(crlf)?"\r\n":"\n");
|
||||
fprintf(outfile, "// version 18.2.0%s", (crlf)?"\r\n":"\n");
|
||||
fprintf(outfile, "// Measurement UUID: cc9c7b54-68ae-"
|
||||
"46d2-a43a-6aa87df7dd74%s", (crlf)?"\r\n":"\n");
|
||||
}
|
||||
|
||||
for (i = 0, devno = 0; i < maxdev; i++) {
|
||||
@@ -313,14 +448,8 @@ int main(int argc, char **argv)
|
||||
|
||||
mtu = parse_canframe(afrbuf, &cu);
|
||||
|
||||
/* convert only CAN CC and CAN FD frames */
|
||||
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) {
|
||||
printf("no valid CAN CC/FD frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* we don't support error message frames in CAN FD */
|
||||
if ((mtu == CANFD_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
|
||||
/* no error message frames in non CAN CC frames */
|
||||
if ((mtu != CAN_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
|
||||
continue;
|
||||
|
||||
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
|
||||
@@ -335,10 +464,12 @@ int main(int argc, char **argv)
|
||||
else
|
||||
fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec);
|
||||
|
||||
if ((mtu == CAN_MTU) && (fdfmt == 0))
|
||||
can_asc(&cu.fd, devno, nortrdlc, extra_info, outfile);
|
||||
else
|
||||
if ((mtu == CAN_MTU) && (fdfmt == 0) && (xlfmt == 0))
|
||||
can_asc(&cu.cc, devno, nortrdlc, extra_info, outfile);
|
||||
else if ((mtu != CANXL_MTU) && (xlfmt == 0))
|
||||
canfd_asc(&cu.fd, devno, mtu, extra_info, outfile);
|
||||
else
|
||||
canxl_asc(&cu, devno, mtu, extra_info, outfile);
|
||||
|
||||
if (crlf)
|
||||
fprintf(outfile, "\r");
|
||||
|
||||
+4
-4
@@ -51,7 +51,7 @@
|
||||
#include "lib.h"
|
||||
|
||||
#define DEVSZ 22
|
||||
#define TIMESZ 22 /* sizeof("(1345212884.318850) ") */
|
||||
#define TIMESZ 25 /* sizeof("(1345212884.318850123) ") */
|
||||
#define BUFSZ (DEVSZ + AFRSZ + TIMESZ)
|
||||
|
||||
/* adapt sscanf() functions below on error */
|
||||
@@ -61,14 +61,14 @@
|
||||
#if (DEVSZ != 22)
|
||||
#error "DEVSZ value does not fit sscanf restrictions!"
|
||||
#endif
|
||||
#if (TIMESZ != 22)
|
||||
#if (TIMESZ != 25)
|
||||
#error "TIMESZ value does not fit sscanf restrictions!"
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static char buf[BUFSZ], timestamp[TIMESZ], device[DEVSZ], afrbuf[AFRSZ];
|
||||
static cu_t cu;
|
||||
static union cfu cu;
|
||||
int mtu;
|
||||
|
||||
while (fgets(buf, BUFSZ-1, stdin)) {
|
||||
@@ -78,7 +78,7 @@ int main(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%21s %21s %6299s", timestamp, device, afrbuf) != 3)
|
||||
if (sscanf(buf, "%24s %21s %6299s", timestamp, device, afrbuf) != 3)
|
||||
return 1;
|
||||
|
||||
mtu = parse_canframe(afrbuf, &cu);
|
||||
|
||||
@@ -72,8 +72,7 @@ int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
return 0;
|
||||
|
||||
/* maybe it's something like "spi0.0" */
|
||||
tmp = strchr(file_path, '/');
|
||||
if (tmp)
|
||||
if (strchr(file_path, '/'))
|
||||
return -ENOENT;
|
||||
|
||||
/* first try literally */
|
||||
|
||||
@@ -160,7 +160,7 @@ static int look_up_uart_speed(long int s)
|
||||
return B3500000;
|
||||
#endif
|
||||
#ifdef B3710000
|
||||
case 3710000
|
||||
case 3710000:
|
||||
return B3710000;
|
||||
#endif
|
||||
#ifdef B4000000
|
||||
@@ -370,8 +370,13 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* retrieve the name of the created CAN netdevice */
|
||||
if (ioctl(fd, SIOCGIFNAME, ifr.ifr_name) < 0) {
|
||||
perror("ioctl SIOCGIFNAME");
|
||||
exit(EXIT_FAILURE);
|
||||
if (name) {
|
||||
perror("ioctl SIOCGIFNAME");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
/* Graceful degradation: we only needed the name for display. */
|
||||
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "<unknown>");
|
||||
}
|
||||
}
|
||||
|
||||
syslogger(LOG_NOTICE, "attached TTY %s to netdevice %s\n", ttypath, ifr.ifr_name);
|
||||
|
||||
+6
-6
@@ -197,7 +197,7 @@ int main(int argc, char *argv[])
|
||||
if (verbose)
|
||||
fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &%i);\n", todo_prio);
|
||||
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
|
||||
&todo_prio, sizeof(todo_prio));
|
||||
&todo_prio, sizeof(todo_prio));
|
||||
if (ret < 0)
|
||||
err(1, "set priority %i", todo_prio);
|
||||
}
|
||||
@@ -246,7 +246,7 @@ int main(int argc, char *argv[])
|
||||
if (verbose)
|
||||
fprintf(stderr, "- sendto(, <dat>, %i, 0, %s, %zi);\n", todo_send, libj1939_addr2str(&peername), sizeof(peername));
|
||||
ret = sendto(sock, dat, todo_send, 0,
|
||||
(void *)&peername, sizeof(peername));
|
||||
(void *)&peername, sizeof(peername));
|
||||
} else {
|
||||
/*
|
||||
* we may do sendto(sock, dat, todo_send, 0, NULL, 0)
|
||||
@@ -266,14 +266,14 @@ int main(int argc, char *argv[])
|
||||
fprintf(stderr, "- while (1)\n");
|
||||
while (todo_echo || todo_recv) {
|
||||
/*
|
||||
* re-use peername for storing the sender's peername of
|
||||
* reuse peername for storing the sender's peername of
|
||||
* received packets
|
||||
*/
|
||||
if (verbose)
|
||||
fprintf(stderr, "- recvfrom(, <dat>, %zi, 0, &<peername>, %zi);\n", sizeof(peername), sizeof(peername));
|
||||
peernamelen = sizeof(peername);
|
||||
ret = recvfrom(sock, dat, sizeof(dat), 0,
|
||||
(void *)&peername, &peernamelen);
|
||||
(void *)&peername, &peernamelen);
|
||||
if (ret < 0) {
|
||||
if (EINTR == errno) {
|
||||
if (verbose)
|
||||
@@ -287,7 +287,7 @@ int main(int argc, char *argv[])
|
||||
if (verbose)
|
||||
fprintf(stderr, "- sendto(, <dat>, %i, 0, %s, %i);\n", ret, libj1939_addr2str(&peername), peernamelen);
|
||||
ret = sendto(sock, dat, ret, 0,
|
||||
(void *)&peername, peernamelen);
|
||||
(void *)&peername, peernamelen);
|
||||
if (ret < 0)
|
||||
err(1, "sendto");
|
||||
}
|
||||
@@ -297,7 +297,7 @@ int main(int argc, char *argv[])
|
||||
if (todo_names && peername.can_addr.j1939.name)
|
||||
printf("%016llx ", peername.can_addr.j1939.name);
|
||||
printf("%02x %05x:", peername.can_addr.j1939.addr,
|
||||
peername.can_addr.j1939.pgn);
|
||||
peername.can_addr.j1939.pgn);
|
||||
for (i = 0, j = 0; i < ret; ++i, j++) {
|
||||
if (j == 8) {
|
||||
printf("\n%05x ", i);
|
||||
|
||||
Reference in New Issue
Block a user