Compare commits

...

32 Commits

Author SHA1 Message Date
Carsten Schmidt 4b029cf125
Merge 15ed00a985 into 7fb81e6779 2025-03-20 02:28:14 +00:00
Marc Kleine-Budde 7fb81e6779
Merge pull request #593 from yegorich/static-libs
CMakeLists.txt: add an option to control shared library creation
2025-03-12 09:27:14 +01:00
Yegor Yefremov a904183b4e CMakeLists.txt: add an option to control shared library creation
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2025-03-11 18:19:08 +01:00
Marc Kleine-Budde e2172546aa
Merge pull request #591 from zeljkoavramovic/master
README.md : mention new canerrsim tool and add a link to existing J1939 kernel module installation document
2025-03-03 15:47:02 +01:00
Zeljko Avramovic 705b3202a9 added new canerrsim tool and a link to already existing can-j1939-install-kernel-module.md 2025-03-03 15:27:02 +01:00
Marc Kleine-Budde 31a59be02f
Merge pull request #588 from marckleinebudde/makefile-detect-libgps
Makefile: rely on pkg-config to detect presence of libgps
2025-03-03 13:24:18 +01:00
Marc Kleine-Budde 4d908bd7cf
Merge pull request #590 from marckleinebudde/fix-makefile-into-ci
github-actions: fix used compiler
2025-03-03 13:22:57 +01:00
Marc Kleine-Budde 837e2bb343 github-actions: fix used compiler
Fixes: 130e0dced2 ("github-actions: compile with gcc and clang using Makefile")
2025-03-03 13:20:50 +01:00
Marc Kleine-Budde ec16ef97ff Makefile: rely on pkg-config to detect presence of libgps
Link: 71b2aec834 (commitcomment-153191516)
Fixes: 71b2aec ("j1939-vehicle-position-srv: Introduce J1939 and NMEA 2000 Vehicle Position Server")
2025-03-03 13:14:05 +01:00
Marc Kleine-Budde 651c8818dd
Merge pull request #589 from marckleinebudde/integrate-makefile-into-ci
github-actions: compile with gcc and clang using Makefile
2025-03-03 13:13:02 +01:00
Marc Kleine-Budde 130e0dced2 github-actions: compile with gcc and clang using Makefile 2025-03-03 13:08:26 +01:00
Marc Kleine-Budde ff90f4ec21
Merge pull request #586 from marckleinebudde/fix-typo-update-gitignore
Fix typos and update gitignore
2025-03-03 10:24:07 +01:00
Marc Kleine-Budde e3ee283443 gitignore: ignore new tools if building with Makefile 2025-03-03 10:18:25 +01:00
Marc Kleine-Budde e8130a3575 treewide: fix typos 2025-03-03 10:18:25 +01:00
Marc Kleine-Budde 1250c12a30
Merge pull request #585 from marckleinebudde/fix-makefile
Makefile: remove erroneous '\'
2025-03-03 10:14:53 +01:00
Marc Kleine-Budde 9b5b030877 Makefile: remove erroneous '\'
This should at least fix the `No rule to make target` error:

```
cc -O2 -Wall -Wno-parentheses -Wsign-compare -I. -Iinclude -DAF_CAN=PF_CAN -DPF_CAN=29 -DSO_RXQ_OVFL=40 -DSCM_TIMESTAMPING_OPT_STATS=54 -DCLOCK_TAI=11 -DSO_TXTIME=61 -DSCM_TXTIME=SO_TXTIME -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE  -c -o j1939_vehicle_position/j1939_vehicle_position_srv.o j1939_vehicle_position/j1939_vehicle_position_srv.c
j1939_vehicle_position/j1939_vehicle_position_srv.c:7:10: fatal error: gps.h: No such file or directory
    7 | #include <gps.h>
      |          ^~~~~~~
compilation terminated.
make: *** [<builtin>: j1939_vehicle_position/j1939_vehicle_position_srv.o] Error 1
make: *** No rule to make target 'cc', needed by 'j1939-vehicle-position-srv'.
make: *** No rule to make target '-lgps', needed by 'j1939-vehicle-position-srv'.
make: *** No rule to make target '-o', needed by 'j1939-vehicle-position-srv'.
```

Link: 71b2aec834 (commitcomment-153191516)
Fixes: 71b2aec834 ("j1939-vehicle-position-srv: Introduce J1939 and NMEA 2000 Vehicle Position Server")
2025-03-03 10:09:48 +01:00
Marc Kleine-Budde da3914c491
Merge pull request #528 from marckleinebudde/canerrsim
canerrsim
2025-03-02 17:19:38 +01:00
Marc Kleine-Budde 18b1e7970a
Merge pull request #553 from olerem/j1939_vehicle_position
J1939 vehicle position
2025-03-02 17:19:09 +01:00
Zeljko Avramovic 491cabea07 canerrsim: add
Link: https://github.com/linux-can/can-utils/issues/525#issue-2311379340
2025-03-02 17:16:21 +01:00
Marc Kleine-Budde f1cea504a4
Merge pull request #583 from yegorich/typos
isobusfs: fix typos
2025-03-02 17:09:17 +01:00
Marc Kleine-Budde 900c7e9f6e
Merge pull request #584 from yegorich/fix-switch-case
slcand.c: add the missing case colon
2025-03-02 17:08:23 +01:00
Yegor Yefremov b208876e65 slcand.c: add the missing case colon
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2025-03-02 15:51:45 +01:00
Yegor Yefremov 72a9fd8ccd isobusfs: fix typos
Typos were found with codespell.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2025-03-02 15:44:40 +01:00
Marc Kleine-Budde e448d542e8 github-actions: install libgps-dev where available 2025-03-01 22:30:29 +01:00
Oleksij Rempel 71b2aec834 j1939-vehicle-position-srv: Introduce J1939 and NMEA 2000 Vehicle Position Server
This patch adds `j1939-vehicle-position-srv`, a server for sending
vehicle position data over CAN using J1939 or NMEA 2000 protocols. It
retrieves GPS data from gpsd or simulates data if gpsd is unavailable.
By default, it operates in J1939 profile but can switch to NMEA 2000
with the `-p nmea2000` option.

Usage Examples:
1. With gpsd:
   j1939acd -r 64-95 -c /tmp/1122334455667789.jacd 1122334455667789 vcan0 &
   j1939-vehicle-position-srv -i vcan0 -n 0x1122334455667789

2. In simulation mode without gpsd:
   j1939-vehicle-position-srv -i vcan0 -s -p nmea2000

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
[Yegor: add CMakeLists.txt integration]
Co-developed-by: Yegor Yefremov <yegorslists@googlemail.com>
2025-03-01 22:29:11 +01:00
Marc Kleine-Budde a24bff8b08
Merge pull request #582 from yegorich/clangd
CMakeLists.txt: enable CMAKE_EXPORT_COMPILE_COMMANDS by default
2025-03-01 16:47:48 +01:00
Yegor Yefremov fe9ea67814 CMakeLists.txt: enable CMAKE_EXPORT_COMPILE_COMMANDS by default
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2025-03-01 16:15:08 +01:00
Oleksij Rempel e8559479fb libj1939: Add function to connect a socket
Introduce `libj1939_connect_socket` function to handle socket
connections.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2025-03-01 13:28:52 +01:00
Marc Kleine-Budde 6050aa155d
Merge pull request #581 from yegorich/cmake-linting
CMakeLists.txt: remove unneeded spaces
2025-03-01 12:33:50 +01:00
Yegor Yefremov 302184f383 CMakeLists.txt: remove unneeded spaces
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2025-03-01 10:51:12 +01:00
Oliver Hartkopp c542c9ada7 gitignore: remove accidentally added Makefile item
Fixes: 4577316bd6 ("Update .gitignore")
Link: https://github.com/linux-can/can-utils/pull/577#issuecomment-2690362731
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-02-28 21:34:03 +01:00
Carsten Schmidt 15ed00a985 Read PDU to send from binary file. 2023-03-25 16:41:45 +01:00
20 changed files with 3677 additions and 32 deletions

View File

@ -30,7 +30,45 @@ jobs:
podman run --name stable -di --userns=keep-id:uid=1000,gid=1000 -v "$PWD":/home -w /home ${{ matrix.release }} bash 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 uname -a
podman exec -i stable id 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 -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} \ podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \
clang \ clang \
cmake \ cmake \
@ -38,52 +76,67 @@ jobs:
gcc-aarch64-linux-gnu \ gcc-aarch64-linux-gnu \
gcc-arm-linux-gnueabihf \ gcc-arm-linux-gnueabihf \
gcc-mips-linux-gnu \ gcc-mips-linux-gnu \
libgps-dev \
make 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 - name: Configure & Build with gcc
env: env:
cc: gcc cc: gcc
run: | run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -B build-${cc} 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} podman exec -i stable cmake --build build-${cc}
- name: Configure & Build with clang - name: Configure & Build with clang
env: env:
cc: clang cc: clang
run: | run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -B build-${cc} 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} podman exec -i stable cmake --build build-${cc}
- name: Configure & Build with arm-linux-gnueabihf-gcc - name: Configure & Build with arm-linux-gnueabihf-gcc
env: env:
toolchain: arm-linux-gnueabihf-gcc toolchain: arm-linux-gnueabihf-gcc
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
run: | run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain} 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} podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with arm-linux-gnueabihf-clang - name: Configure & Build with arm-linux-gnueabihf-clang
if: if:
${{ matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim' }} matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim'
env: env:
toolchain: arm-linux-gnueabihf-clang toolchain: arm-linux-gnueabihf-clang
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
run: | run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain} 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} podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with aarch64-linux-gnu-gcc - name: Configure & Build with aarch64-linux-gnu-gcc
env: env:
toolchain: aarch64-linux-gnu-gcc toolchain: aarch64-linux-gnu-gcc
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
run: | run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain} 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} podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with aarch64-linux-gnu-clang - name: Configure & Build with aarch64-linux-gnu-clang
if: if:
${{ matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim' }} matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim'
env: env:
toolchain: aarch64-linux-gnu-clang toolchain: aarch64-linux-gnu-clang
gps: ${{ matrix.release == 'ubuntu:20.04' && 'OFF' || 'ON' }}
run: | run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain} 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} podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with mips-linux-gnu-gcc - name: Configure & Build with mips-linux-gnu-gcc
@ -93,6 +146,20 @@ jobs:
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain} podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain}
podman exec -i stable cmake --build 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 - name: Show logs
if: ${{ failure() }} if: ${{ failure() }}
run: | run: |

3
.gitignore vendored
View File

@ -6,7 +6,6 @@
.ccls-cache .ccls-cache
CMakeCache.txt CMakeCache.txt
CMakeFiles/ CMakeFiles/
Makefile
cmake_install.cmake cmake_install.cmake
compile_commands.json compile_commands.json
tags tags
@ -17,6 +16,7 @@ tags
/can-calc-bit-timing /can-calc-bit-timing
/canbusload /canbusload
/candump /candump
/canerrsim
/canfdtest /canfdtest
/cangen /cangen
/cangw /cangw
@ -40,6 +40,7 @@ tags
/j1939sr /j1939sr
/j1939-timedate-cli /j1939-timedate-cli
/j1939-timedate-srv /j1939-timedate-srv
/j1939-vehicle-position-srv
/log2asc /log2asc
/log2long /log2long
/mcp251xfd-dump /mcp251xfd-dump

View File

@ -4,16 +4,27 @@ project(can-utils LANGUAGES C)
message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake version: ${CMAKE_VERSION}")
include (CheckFunctionExists) include(CheckFunctionExists)
include (CheckSymbolExists) include(CheckSymbolExists)
include (GNUInstallDirs) include(GNUInstallDirs)
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
endif() 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 # Add an option to enable treating warnings as errors
option(ENABLE_WERROR "Treat all compiler warnings as errors" OFF) 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)
find_package(PkgConfig REQUIRED)
if(ENABLE_GPS)
pkg_check_modules(GPS REQUIRED libgps)
endif()
if(ENABLE_WERROR) if(ENABLE_WERROR)
add_compile_options(-Werror) add_compile_options(-Werror)
@ -32,8 +43,8 @@ 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} -DSO_TXTIME=61")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TXTIME=SO_TXTIME") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TXTIME=SO_TXTIME")
include_directories (.) include_directories(.)
include_directories (./include) include_directories(./include)
check_function_exists(fork HAVE_FORK) check_function_exists(fork HAVE_FORK)
@ -67,6 +78,10 @@ set(PROGRAMS_J1939_TIMEDATE
j1939-timedate-cli j1939-timedate-cli
) )
set(PROGRAMS_J1939_VEHICLE_POSITION
j1939-vehicle-position-srv
)
set(PROGRAMS_ISOBUSFS set(PROGRAMS_ISOBUSFS
isobusfs-srv isobusfs-srv
isobusfs-cli isobusfs-cli
@ -74,6 +89,7 @@ set(PROGRAMS_ISOBUSFS
set(PROGRAMS set(PROGRAMS
${PROGRAMS_CANLIB} ${PROGRAMS_CANLIB}
canerrsim
canfdtest canfdtest
cangw cangw
cansniffer cansniffer
@ -114,7 +130,7 @@ if(NOT ANDROID)
PRIVATE can PRIVATE can
) )
add_library(isobusfs SHARED add_library(isobusfs
isobusfs/isobusfs_cmn.c isobusfs/isobusfs_cmn.c
isobusfs/isobusfs_cmn_dh.c isobusfs/isobusfs_cmn_dh.c
) )
@ -191,6 +207,24 @@ if(NOT ANDROID)
j1939-timedate-srv j1939-timedate-srv
DESTINATION ${CMAKE_INSTALL_BINDIR}) DESTINATION ${CMAKE_INSTALL_BINDIR})
if(ENABLE_GPS)
set(PUBLIC_HEADER_J1939_VEHICLE_POSITION
j1939_vehicle_position/j1939_vehicle_position_cmn.h
)
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()
endif() endif()
add_library(can STATIC add_library(can STATIC

View File

@ -46,6 +46,7 @@ MAKEFLAGS := -k
CFLAGS := -O2 -Wall -Wno-parentheses -Wsign-compare CFLAGS := -O2 -Wall -Wno-parentheses -Wsign-compare
HAVE_FORK := $(shell ./check_cc.sh "$(CC)" fork_test.c) 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 += \ CPPFLAGS += \
-I. \ -I. \
@ -67,6 +68,11 @@ PROGRAMS_J1939_TIMEDATE := \
j1939-timedate-srv \ j1939-timedate-srv \
j1939-timedate-cli j1939-timedate-cli
ifeq ($(HAVE_LIBGPS),1)
PROGRAMS_J1939_VEHICLE_POSITION := \
j1939-vehicle-position-srv
endif
PROGRAMS_ISOBUSFS := \ PROGRAMS_ISOBUSFS := \
isobusfs-srv \ isobusfs-srv \
isobusfs-cli isobusfs-cli
@ -98,6 +104,7 @@ PROGRAMS_SLCAN := \
PROGRAMS := \ PROGRAMS := \
$(PROGRAMS_CANGW) \ $(PROGRAMS_CANGW) \
$(PROGRAMS_J1939_TIMEDATE) \ $(PROGRAMS_J1939_TIMEDATE) \
$(PROGRAMS_J1939_VEHICLE_POSITION) \
$(PROGRAMS_ISOBUSFS) \ $(PROGRAMS_ISOBUSFS) \
$(PROGRAMS_ISOTP) \ $(PROGRAMS_ISOTP) \
$(PROGRAMS_J1939) \ $(PROGRAMS_J1939) \
@ -106,6 +113,7 @@ PROGRAMS := \
can-calc-bit-timing \ can-calc-bit-timing \
canbusload \ canbusload \
candump \ candump \
canerrsim \
canfdtest \ canfdtest \
cangen \ cangen \
cansequence \ cansequence \
@ -126,7 +134,8 @@ endif
all: $(PROGRAMS) all: $(PROGRAMS)
clean: clean:
rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o j1939_timedate/*.o rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o j1939_timedate/*.o \
j1939_vehicle_position/*.o
install: install:
mkdir -p $(DESTDIR)$(PREFIX)/bin mkdir -p $(DESTDIR)$(PREFIX)/bin
@ -153,6 +162,8 @@ isobusfs_srv.o: lib.h libj1939.h
isobusfs_c.o: lib.h libj1939.h isobusfs_c.o: lib.h libj1939.h
j1939_timedate_srv.o: lib.h libj1939.h j1939_timedate_srv.o: lib.h libj1939.h
j1939_timedate_cli.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 canframelen.o: canframelen.h
asc2log: asc2log.o lib.o asc2log: asc2log.o lib.o
@ -182,6 +193,12 @@ j1939-timedate-cli: lib.o \
j1939_timedate/j1939_timedate_cli.o j1939_timedate/j1939_timedate_cli.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -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 \ isobusfs-srv: lib.o \
libj1939.o \ libj1939.o \
isobusfs/isobusfs_cmn.o \ isobusfs/isobusfs_cmn.o \

View File

@ -29,6 +29,7 @@ subsystem (aka SocketCAN):
* canbusload : calculate and display the CAN busload * canbusload : calculate and display the CAN busload
* can-calc-bit-timing : userspace version of in-kernel bitrate calculation * can-calc-bit-timing : userspace version of in-kernel bitrate calculation
* canfdtest : Full-duplex test program (DUT and host part) * 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) #### ISO-TP tools [ISO15765-2:2016 for Linux](https://github.com/hartkopp/can-isotp)
* isotpsend : send a single ISO-TP PDU * isotpsend : send a single ISO-TP PDU
@ -75,4 +76,4 @@ Follow the link to see examples on how this tools can be used:
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/html/latest/networking/can.html) * [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/html/latest/networking/can.html)
* [Elinux.org CAN Bus Page](http://elinux.org/CAN_Bus) * [Elinux.org CAN Bus Page](http://elinux.org/CAN_Bus)
* [Debian Package Description](https://packages.debian.org/sid/can-utils) * [Debian Package Description](https://packages.debian.org/sid/can-utils)
* [J1939 kernel module installation on Debian](can-j1939-install-kernel-module.md)

564
canerrsim.c 100644
View File

@ -0,0 +1,564 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// 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 <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 err_exit(const char *msg)
{
printf("%s", msg);
exit(EXIT_FAILURE);
}
void show_custom_format_and_exit(const char *param, const char *format)
{
char str_buf[80];
sprintf(str_buf, format, param);
err_exit(str_buf);
}
void show_invalid_option(const char *option)
{
show_custom_format_and_exit(option, "Error: Invalid option %s\n");
}
void show_err_and_exit(const char *err_type)
{
show_custom_format_and_exit(err_type, "Error: You can only have one %s parameter!\n");
}
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;
char tmp_str[256];
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");
// set interface name
strcpy(ifr.ifr_name, argv[1]); // can0, vcan0...
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
sprintf(tmp_str, "Error setting CAN interface name %s", argv[1]);
err_exit(tmp_str);
}
// 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");
// Send CAN error frame
if (write(sock, &frame, sizeof(frame)) < 0)
err_exit("Error writing to socket");
else
printf("CAN error frame sent\n");
close(sock);
return 0;
}

View File

@ -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); isobusfs_cli_promt(priv);
} else { } else {
if (errno != EAGAIN && errno != EWOULDBLOCK) if (errno != EAGAIN && errno != EWOULDBLOCK)

View File

@ -211,7 +211,7 @@ static struct isobusfs_cli_test_dir_path test_dir_patterns[] = {
{ "~tilde_dir", true }, { "~tilde_dir", true },
/* expected result \\vol1\dir1\~\ */ /* expected result \\vol1\dir1\~\ */
{ "\\\\vol1\\dir1\\~", true }, { "\\\\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 }, { "\\~\\", true },
/* expected result \\~\ */ /* expected result \\~\ */
{ "\\\\~\\", false }, { "\\\\~\\", false },

View File

@ -611,7 +611,7 @@ int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
} }
/* FIXME: linger is currently not supported by the kernel J1939 stack /* 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. * messages on a socket when the connection is lost.
*/ */
int isobusfs_cmn_set_linger(int sock) int isobusfs_cmn_set_linger(int sock)

View File

@ -23,7 +23,7 @@ int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable)
ret = access(path, mode); ret = access(path, mode);
if (ret == -1) { if (ret == -1) {
ret = -errno; 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)); writable ? "and write" : "", strerror(ret));
return ret; return ret;
} }

View File

@ -70,7 +70,7 @@ static int isobusfs_srv_rx_fs(struct isobusfs_srv_priv *priv,
cg); cg);
/* ISO 11783-13:2021 - Annex C.1.1 Overview: /* 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 * documentation, the file server shall respond with a
* NACK (ISO 11783-3:2018 Chapter 5.4.5) * NACK (ISO 11783-3:2018 Chapter 5.4.5)
*/ */
@ -279,7 +279,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
return ret; return ret;
/* keep address and name and overwrite PGN */ /* 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? * PGN?
*/ */
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
@ -720,7 +720,7 @@ static int isobusfs_srv_parse_args(struct isobusfs_srv_priv *priv, int argc,
} }
if (!local_name_set) 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); isobusfs_srv_generate_mfs_dir_name(priv);
pr_debug("Server configuration:"); pr_debug("Server configuration:");

View File

@ -662,8 +662,8 @@ static int isobusfs_srv_dh_ccd_res(struct isobusfs_srv_priv *priv,
int ret; int ret;
/* /*
* We assime, the relative path stored in res->name is not longer * We assume, the relative path stored in res->name is not longer
* than absolue path * than absolute path
*/ */
if (req->name_len > ISOBUSFS_SRV_MAX_PATH_LEN) { if (req->name_len > ISOBUSFS_SRV_MAX_PATH_LEN) {
pr_warn("path too long"); pr_warn("path too long");
@ -697,7 +697,7 @@ static int isobusfs_srv_dh_ccd_res(struct isobusfs_srv_priv *priv,
process_error: process_error:
if (ret < 0) { if (ret < 0) {
/* linux_error_to_isobusfs_error() can't distinguish between /* 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) if (ret == -EINVAL)
error_code = ISOBUSFS_ERR_INVALID_DST_NAME; error_code = ISOBUSFS_ERR_INVALID_DST_NAME;

View File

@ -686,7 +686,7 @@ send_response:
goto free_res; 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); error_code, isobusfs_error_to_str(error_code), readed_size);
free_res: free_res:

View File

@ -42,6 +42,7 @@
* *
*/ */
#include <fcntl.h>
#include <libgen.h> #include <libgen.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -78,12 +79,32 @@ void print_usage(char *prg)
fprintf(stderr, " -S (SF broadcast mode - for functional addressing)\n"); fprintf(stderr, " -S (SF broadcast mode - for functional addressing)\n");
fprintf(stderr, " -C (CF broadcast mode - no wait for flow controls)\n"); fprintf(stderr, " -C (CF broadcast mode - no wait for flow controls)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n"); fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -i <filename> (Read PDU data from binary file instead of STDIN)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n"); fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n"); fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
fprintf(stderr, "(*) = Use '-t %s' to set N_As to zero for Linux version 5.18+\n", ZERO_STRING); fprintf(stderr, "(*) = Use '-t %s' to set N_As to zero for Linux version 5.18+\n", ZERO_STRING);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
ssize_t read_binary_file(void *buffer, const size_t siz_buffer, const char *filename)
{
int fd = -1;
ssize_t num_read = -1;
if( buffer == NULL || siz_buffer < 1 || filename == NULL ) {
return 0;
}
if( (fd = open(filename, O_RDONLY)) == -1 ) {
return 0;
}
num_read = read(fd, buffer, siz_buffer);
close(fd);
return num_read > 0 ? num_read : 0;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int s; int s;
@ -102,7 +123,7 @@ int main(int argc, char **argv)
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) { while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:l:g:bSCL:i:?")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16); addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
@ -227,6 +248,10 @@ int main(int argc, char **argv)
} }
break; break;
case 'i':
buflen = read_binary_file(&buf[0], sizeof(buf), optarg);
break;
case '?': case '?':
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
@ -285,6 +310,7 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
if( buflen < 1 ) {
if (!datalen) { if (!datalen) {
while (buflen < BUFSIZE && scanf("%hhx", &buf[buflen]) == 1) while (buflen < BUFSIZE && scanf("%hhx", &buf[buflen]) == 1)
buflen++; buflen++;
@ -292,6 +318,7 @@ int main(int argc, char **argv)
for (buflen = 0; buflen < datalen; buflen++) for (buflen = 0; buflen < datalen; buflen++)
buf[buflen] = ((buflen % 0xFF) + 1) & 0xFF; buf[buflen] = ((buflen % 0xFF) + 1) & 0xFF;
} }
}
loop: loop:
if (usecs) if (usecs)
@ -313,7 +340,7 @@ loop:
goto loop; goto loop;
} }
/* /*
* due to a Kernel internal wait queue the PDU is sent completely * due to a Kernel internal wait queue the PDU is sent completely
* before close() returns. * before close() returns.
*/ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -253,6 +253,31 @@ int libj1939_bind_socket(int sock, struct sockaddr_can *addr)
return 0; 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 * libj1939_socket_prio - Set the priority of a J1939 socket
* @sock: The file descriptor of the socket * @sock: The file descriptor of the socket

View File

@ -43,6 +43,7 @@ void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
int libj1939_open_socket(void); int libj1939_open_socket(void);
int libj1939_bind_socket(int sock, struct sockaddr_can *addr); 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_socket_prio(int sock, int prio);
int libj1939_set_broadcast(int sock); int libj1939_set_broadcast(int sock);
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events); int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);

View File

@ -160,7 +160,7 @@ static int look_up_uart_speed(long int s)
return B3500000; return B3500000;
#endif #endif
#ifdef B3710000 #ifdef B3710000
case 3710000 case 3710000:
return B3710000; return B3710000;
#endif #endif
#ifdef B4000000 #ifdef B4000000

View File

@ -266,7 +266,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "- while (1)\n"); fprintf(stderr, "- while (1)\n");
while (todo_echo || todo_recv) { 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 * received packets
*/ */
if (verbose) if (verbose)