Compare commits

..

No commits in common. "master" and "v2025.01" have entirely different histories.

39 changed files with 928 additions and 4702 deletions

View File

@ -30,45 +30,7 @@ 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 \
@ -76,67 +38,52 @@ 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 -DENABLE_GPS=ON -B build-${cc} podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=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 -DENABLE_GPS=ON -B build-${cc} podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=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 -DENABLE_GPS=${gps} -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 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 -DENABLE_GPS=${gps} -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 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 -DENABLE_GPS=${gps} -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 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 -DENABLE_GPS=${gps} -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 mips-linux-gnu-gcc - name: Configure & Build with mips-linux-gnu-gcc
@ -146,20 +93,6 @@ 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: |

8
.gitignore vendored
View File

@ -1,12 +1,6 @@
*~ *~
*.a
*.so
*.so.*
*.o *.o
.ccls-cache .ccls-cache
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
compile_commands.json compile_commands.json
tags tags
/build /build
@ -16,7 +10,6 @@ tags
/can-calc-bit-timing /can-calc-bit-timing
/canbusload /canbusload
/candump /candump
/canerrsim
/canfdtest /canfdtest
/cangen /cangen
/cangw /cangw
@ -40,7 +33,6 @@ 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,46 +4,16 @@ 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)
# 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) if(ENABLE_WERROR)
add_compile_options(-Werror) add_compile_options(-Werror)
@ -62,116 +32,102 @@ 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)
# List of all programs to be built. set(PROGRAMS_CANLIB
# Each program is expected to have a corresponding source file with the same name. asc2log
set(PROGRAMS) canbusload
# List of programs to link against can. candump
set(PROGRAMS_CANLIB) cangen
# List of programs to link against j1939 and can. canplayer
set(PROGRAMS_J1939) cansend
cansequence
log2asc
log2long
slcanpty
)
if(ENABLE_BASIC_TOOLS) if(HAVE_FORK)
list(APPEND PROGRAMS cansniffer)
list(APPEND PROGRAMS_CANLIB
candump
canplayer
cansend
cangen
cansequence
)
endif()
if(ENABLE_IP_SERVER AND HAVE_FORK)
list(APPEND PROGRAMS bcmserver)
list(APPEND PROGRAMS_CANLIB canlogserver) list(APPEND PROGRAMS_CANLIB canlogserver)
endif() endif()
if(ENABLE_GATEWAY) set(PROGRAMS_J1939
list(APPEND PROGRAMS cangw) j1939acd
j1939cat
j1939spy
j1939sr
testj1939
)
set(PROGRAMS_J1939_TIMEDATE
j1939-timedate-srv
j1939-timedate-cli
)
set(PROGRAMS_ISOBUSFS
isobusfs-srv
isobusfs-cli
)
set(PROGRAMS
${PROGRAMS_CANLIB}
canfdtest
cangw
cansniffer
isotpdump
isotpperf
isotprecv
isotpsend
isotpsniffer
isotptun
slcan_attach
slcand
)
if(HAVE_FORK)
list(APPEND PROGRAMS bcmserver)
list(APPEND PROGRAMS isotpserver)
endif() endif()
if(ENABLE_MEASUREMENT) add_executable(can-calc-bit-timing
list(APPEND PROGRAMS calc-bit-timing/can-calc-bit-timing.c
canfdtest )
canerrsim
)
list(APPEND PROGRAMS_CANLIB canbusload)
add_executable(can-calc-bit-timing add_executable(mcp251xfd-dump
calc-bit-timing/can-calc-bit-timing.c mcp251xfd/mcp251xfd-dev-coredump.c
) mcp251xfd/mcp251xfd-dump.c
install(TARGETS can-calc-bit-timing DESTINATION ${CMAKE_INSTALL_BINDIR}) mcp251xfd/mcp251xfd-main.c
endif() mcp251xfd/mcp251xfd-regmap.c
)
if(ENABLE_ISOTP) if(NOT ANDROID)
list(APPEND PROGRAMS list(APPEND PROGRAMS ${PROGRAMS_J1939})
isotpdump
isotpperf add_library(j1939 STATIC
isotprecv libj1939.c
isotpsend
isotpsniffer
isotptun
) )
if(HAVE_FORK) target_link_libraries(j1939
list(APPEND PROGRAMS isotpserver) PRIVATE can
endif()
endif()
if(ENABLE_J1939)
list(APPEND PROGRAMS_J1939
j1939acd
j1939cat
j1939spy
j1939sr
testj1939
) )
add_executable(j1939-timedate-cli add_library(isobusfs SHARED
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.c
isobusfs/isobusfs_cmn_dh.c isobusfs/isobusfs_cmn_dh.c
) )
set(PUBLIC_HEADER_ISOBUSFS set(PUBLIC_HEADER_ISOBUSFS
isobusfs/isobusfs_cmn.h isobusfs/isobusfs_cmn.h
isobusfs/isobusfs_cmn_cm.h isobusfs/isobusfs_cmn_cm.h
) )
set_target_properties(isobusfs PROPERTIES set_target_properties(isobusfs PROPERTIES
PUBLIC_HEADER "${PUBLIC_HEADER_ISOBUSFS}" PUBLIC_HEADER "${PUBLIC_HEADER_ISOBUSFS}"
SOVERSION 0
) )
install(TARGETS isobusfs install(TARGETS isobusfs
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
@ -185,10 +141,10 @@ if(ENABLE_ISOBUSFS)
isobusfs/isobusfs_cli_selftests.c isobusfs/isobusfs_cli_selftests.c
isobusfs/isobusfs_cli_int.c isobusfs/isobusfs_cli_int.c
) )
target_link_libraries(isobusfs-cli target_link_libraries(isobusfs-cli
PRIVATE isobusfs can j1939 PRIVATE isobusfs can j1939
) )
install(TARGETS isobusfs-cli DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(isobusfs-srv add_executable(isobusfs-srv
isobusfs/isobusfs_srv.c isobusfs/isobusfs_srv.c
@ -199,55 +155,48 @@ if(ENABLE_ISOBUSFS)
isobusfs/isobusfs_srv_fh.c isobusfs/isobusfs_srv_fh.c
isobusfs/isobusfs_srv_vh.c isobusfs/isobusfs_srv_vh.c
) )
target_link_libraries(isobusfs-srv target_link_libraries(isobusfs-srv
PRIVATE isobusfs can j1939 PRIVATE isobusfs can j1939
) )
install(TARGETS isobusfs-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(ENABLE_LOG_FILE) install(TARGETS
list(APPEND PROGRAMS_CANLIB isobusfs-cli
asc2log isobusfs-srv
log2asc DESTINATION ${CMAKE_INSTALL_BINDIR})
log2long
set(PUBLIC_HEADER_j1939_TIMEDATE
j1939_timedate/j1939_timedate_cmn.h
) )
endif()
if(ENABLE_SLCAN) add_executable(j1939-timedate-cli
list(APPEND PROGRAMS j1939_timedate/j1939_timedate_cli.c
slcan_attach
slcand
) )
list(APPEND PROGRAMS_CANLIB slcanpty)
endif()
if(ENABLE_MCP251XFD) target_link_libraries(j1939-timedate-cli
add_executable(mcp251xfd-dump PRIVATE can j1939
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})
add_executable(j1939-timedate-srv
j1939_timedate/j1939_timedate_srv.c
)
target_link_libraries(j1939-timedate-srv
PRIVATE can j1939
)
install(TARGETS
j1939-timedate-cli
j1939-timedate-srv
DESTINATION ${CMAKE_INSTALL_BINDIR})
endif() endif()
list(APPEND PROGRAMS add_library(can STATIC
${PROGRAMS_CANLIB}
${PROGRAMS_J1939}
)
add_library(can STATIC EXCLUDE_FROM_ALL
lib.c lib.c
canframelen.c canframelen.c
) )
add_library(j1939 STATIC EXCLUDE_FROM_ALL
libj1939.c
)
target_link_libraries(j1939
PRIVATE can
)
foreach(name ${PROGRAMS}) foreach(name ${PROGRAMS})
add_executable(${name} ${name}.c) add_executable(${name} ${name}.c)
@ -264,6 +213,12 @@ foreach(name ${PROGRAMS})
install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR})
endforeach() endforeach()
install(TARGETS
can-calc-bit-timing
mcp251xfd-dump
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
add_custom_target(uninstall add_custom_target(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake" "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake"
COMMENT "Add uninstall target" COMMENT "Add uninstall target"

View File

@ -46,7 +46,6 @@ 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. \
@ -68,11 +67,6 @@ 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
@ -104,7 +98,6 @@ 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) \
@ -113,7 +106,6 @@ PROGRAMS := \
can-calc-bit-timing \ can-calc-bit-timing \
canbusload \ canbusload \
candump \ candump \
canerrsim \
canfdtest \ canfdtest \
cangen \ cangen \
cansequence \ cansequence \
@ -134,8 +126,7 @@ 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
@ -162,8 +153,6 @@ 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
@ -193,12 +182,6 @@ 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,7 +29,6 @@ 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
@ -50,10 +49,6 @@ subsystem (aka SocketCAN):
Follow the link to see examples on how this tools can be used: 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) [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 #### Log file converters
* asc2log : convert ASC logfile to compact CAN frame logfile * asc2log : convert ASC logfile to compact CAN frame logfile
* log2asc : convert compact CAN frame logfile to ASC logfile * log2asc : convert compact CAN frame logfile to ASC logfile
@ -80,4 +75,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)

View File

@ -584,7 +584,7 @@ static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
return; return;
if (!(flags & ASC_F_FDF)) if (!(flags & ASC_F_FDF))
return; return;
cf.flags = CANFD_FDF; cf.flags = CANFD_FDF;

View File

@ -1121,11 +1121,6 @@ static const unsigned int common_data_bitrates[] = {
4000000, 4000000,
2000000, 2000000,
1000000, 1000000,
800000,
500000,
250000,
125000,
100000,
0 0
}; };

127
candump.c
View File

@ -72,9 +72,6 @@
#ifndef SO_TIMESTAMPING #ifndef SO_TIMESTAMPING
#define SO_TIMESTAMPING 37 #define SO_TIMESTAMPING 37
#endif #endif
#ifndef SCM_TIMESTAMPING
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#endif
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */ #define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
@ -116,8 +113,7 @@ static const int canfx_on = 1;
#define MAXANI 4 #define MAXANI 4
static const char anichar[MAXANI] = { '|', '/', '-', '\\' }; static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
static const char extra_fd_info[4][4] = { "- -", "B -", "- E", "B E" }; static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
static const char extra_xl_info[4][4] = { "- -", "S -", "- R", "S R" };
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
@ -132,7 +128,6 @@ static void print_usage(void)
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\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, " -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, " -c (increment color mode level)\n");
fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n"); fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n");
fprintf(stderr, " -a (enable additional ASCII output)\n"); fprintf(stderr, " -a (enable additional ASCII output)\n");
@ -147,7 +142,7 @@ static void print_usage(void)
fprintf(stderr, " -d (monitor dropped CAN frames)\n"); fprintf(stderr, " -d (monitor dropped CAN frames)\n");
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\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, " -8 (display raw DLC values in {} for Classical CAN)\n");
fprintf(stderr, " -x (print extra message infos, rx/tx [brs esi|sec rrs])\n"); fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n");
fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n"); fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK); fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
@ -225,22 +220,16 @@ static int idx2dindex(int ifidx, int socket)
return i; return i;
} }
static int sprint_timestamp(char *ts_buffer, const char timestamp, const char use_ns, static int sprint_timestamp(char *ts_buffer, const char timestamp,
const struct timespec *ts, struct timespec *const last_ts) const struct timeval *tv, struct timeval *const last_tv)
{ {
int numchars = 0; int numchars = 0;
switch (timestamp) { switch (timestamp) {
case 'a': /* absolute with timestamp */ case 'a': /* absolute with timestamp */
if (use_ns) { numchars = sprintf(ts_buffer, "(%010llu.%06llu) ",
numchars = sprintf(ts_buffer, "(%010llu.%09llu) ", (unsigned long long)tv->tv_sec,
(unsigned long long)ts->tv_sec, (unsigned long long)tv->tv_usec);
(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; break;
case 'A': /* absolute with date */ case 'A': /* absolute with date */
@ -248,43 +237,32 @@ static int sprint_timestamp(char *ts_buffer, const char timestamp, const char us
struct tm tm; struct tm tm;
char timestring[25]; char timestring[25];
tm = *localtime(&ts->tv_sec); tm = *localtime(&tv->tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm); strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
if (use_ns) { numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
numchars = sprintf(ts_buffer, "(%s.%09llu) ", timestring, (unsigned long long)tv->tv_usec);
(unsigned long long)ts->tv_nsec);
} else {
numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring,
(unsigned long long)ts->tv_nsec / 1000);
}
} }
break; break;
case 'd': /* delta */ case 'd': /* delta */
case 'z': /* starting with zero */ case 'z': /* starting with zero */
{ {
struct timespec diff; struct timeval diff;
if (last_ts->tv_sec == 0) /* first init */ if (last_tv->tv_sec == 0) /* first init */
*last_ts = *ts; *last_tv = *tv;
diff.tv_sec = ts->tv_sec - last_ts->tv_sec; diff.tv_sec = tv->tv_sec - last_tv->tv_sec;
diff.tv_nsec = ts->tv_nsec - last_ts->tv_nsec; diff.tv_usec = tv->tv_usec - last_tv->tv_usec;
if (diff.tv_nsec < 0) if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_nsec += 1000000000; diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0) if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_nsec = 0; diff.tv_sec = diff.tv_usec = 0;
if (use_ns) { numchars = sprintf(ts_buffer, "(%03llu.%06llu) ",
numchars = sprintf(ts_buffer, "(%03llu.%09llu) ", (unsigned long long)diff.tv_sec,
(unsigned long long)diff.tv_sec, (unsigned long long)diff.tv_usec);
(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') if (timestamp == 'd')
*last_ts = *ts; /* update for delta calculation */ *last_tv = *tv; /* update for delta calculation */
} }
break; break;
@ -310,7 +288,6 @@ int main(int argc, char **argv)
unsigned char timestamp = 0; unsigned char timestamp = 0;
unsigned char logtimestamp = 'a'; unsigned char logtimestamp = 'a';
unsigned char hwtimestamp = 0; unsigned char hwtimestamp = 0;
unsigned char use_ns = 0;
unsigned char down_causes_exit = 1; unsigned char down_causes_exit = 1;
unsigned char dropmonitor = 0; unsigned char dropmonitor = 0;
unsigned char extra_msg_info = 0; unsigned char extra_msg_info = 0;
@ -345,7 +322,7 @@ int main(int argc, char **argv)
static cu_t cu; /* union for CAN CC/FD/XL frames */ static cu_t cu; /* union for CAN CC/FD/XL frames */
int nbytes, i; int nbytes, i;
struct ifreq ifr; struct ifreq ifr;
struct timespec ts, last_ts; struct timeval tv, last_tv;
int timeout_ms = -1; /* default to no timeout */ int timeout_ms = -1; /* default to no timeout */
FILE *logfile = NULL; FILE *logfile = NULL;
char fname[83]; /* suggested by -Wformat-overflow= */ char fname[83]; /* suggested by -Wformat-overflow= */
@ -357,12 +334,12 @@ int main(int argc, char **argv)
signal(SIGHUP, sigterm); signal(SIGHUP, sigterm);
signal(SIGINT, sigterm); signal(SIGINT, sigterm);
last_ts.tv_sec = 0; last_tv.tv_sec = 0;
last_ts.tv_nsec = 0; last_tv.tv_usec = 0;
progname = basename(argv[0]); progname = basename(argv[0]);
while ((opt = getopt(argc, argv, "t:HNciaSs:lf:Ln:r:Dde8xT:h?")) != -1) { while ((opt = getopt(argc, argv, "t:HciaSs:lf:Ln:r:Dde8xT:h?")) != -1) {
switch (opt) { switch (opt) {
case 't': case 't':
timestamp = optarg[0]; timestamp = optarg[0];
@ -382,10 +359,6 @@ int main(int argc, char **argv)
hwtimestamp = 1; hwtimestamp = 1;
break; break;
case 'N':
use_ns = 1;
break;
case 'c': case 'c':
color++; color++;
break; break;
@ -715,12 +688,12 @@ int main(int argc, char **argv)
localtime_r(&currtime, &now); localtime_r(&currtime, &now);
snprintf(fname, sizeof(fname), "candump-%04d-%02d-%02d_%02d%02d%02d.log", snprintf(fname, sizeof(fname), "candump-%04d-%02d-%02d_%02d%02d%02d.log",
now.tm_year + 1900, now.tm_year + 1900,
now.tm_mon + 1, now.tm_mon + 1,
now.tm_mday, now.tm_mday,
now.tm_hour, now.tm_hour,
now.tm_min, now.tm_min,
now.tm_sec); now.tm_sec);
logname = fname; logname = fname;
} }
@ -810,13 +783,9 @@ int main(int argc, char **argv)
for (cmsg = CMSG_FIRSTHDR(&msg); for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET); cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) { cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SCM_TIMESTAMP) { if (cmsg->cmsg_type == SO_TIMESTAMP) {
struct timeval tv;
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
ts.tv_sec = tv.tv_sec; } else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
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); struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/* /*
@ -826,7 +795,8 @@ int main(int argc, char **argv)
* See chapter 2.1.2 Receive timestamps in * See chapter 2.1.2 Receive timestamps in
* linux/Documentation/networking/timestamping.txt * linux/Documentation/networking/timestamping.txt
*/ */
ts = stamp[2]; tv.tv_sec = stamp[2].tv_sec;
tv.tv_usec = stamp[2].tv_nsec / 1000;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL) { } else if (cmsg->cmsg_type == SO_RXQ_OVFL) {
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32)); memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
} }
@ -861,9 +831,11 @@ int main(int argc, char **argv)
/* build common log format output */ /* build common log format output */
if ((log) || ((logfrmt) && (silent == SILENT_OFF))) { if ((log) || ((logfrmt) && (silent == SILENT_OFF))) {
alen = sprint_timestamp(afrbuf, logtimestamp, use_ns, &ts, &last_ts); alen = sprint_timestamp(afrbuf, logtimestamp,
&tv, &last_tv);
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); alen += snprintf_canframe(afrbuf + alen, sizeof(afrbuf) - alen, &cu, 0);
} }
@ -889,23 +861,18 @@ int main(int argc, char **argv)
/* print (colored) long CAN frame style to stdout */ /* print (colored) long CAN frame style to stdout */
alen = sprintf(afrbuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : ""); alen = sprintf(afrbuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : "");
alen += sprint_timestamp(afrbuf + alen, timestamp, use_ns, &ts, &last_ts); alen += sprint_timestamp(afrbuf + alen, timestamp, &tv, &last_tv);
alen += sprintf(afrbuf + alen, " %s%*s", alen += sprintf(afrbuf + alen, " %s%*s",
(color && (color < 3)) ? col_on[idx % MAXCOL] : "", (color && (color < 3)) ? col_on[idx % MAXCOL] : "",
max_devname_len, devname[idx]); max_devname_len, devname[idx]);
if (extra_msg_info) { if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE) if (msg.msg_flags & MSG_DONTROUTE)
alen += sprintf(afrbuf + alen, " TX"); alen += sprintf(afrbuf + alen, " TX %s",
extra_m_info[cu.fd.flags & 3]);
else else
alen += sprintf(afrbuf + alen, " RX"); alen += sprintf(afrbuf + alen, " RX %s",
extra_m_info[cu.fd.flags & 3]);
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 : ""); alen += sprintf(afrbuf + alen, "%s ", (color == 1) ? col_off : "");

View File

@ -1,564 +0,0 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// 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;
}

176
cangen.c
View File

@ -180,7 +180,7 @@ static void print_usage(char *prg)
fprintf(stderr, " -X (generate CAN XL CAN frames)\n"); fprintf(stderr, " -X (generate CAN XL CAN frames)\n");
fprintf(stderr, " -R (generate RTR 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, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
fprintf(stderr, " -m (mix CC [-e -R] FD [-f -b -E] XL [-X] on capable devices)\n"); fprintf(stderr, " -m (mix -e -f -b -E -R -X frames)\n");
fprintf(stderr, " -I <mode> (CAN ID generation mode - see below)\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, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n"); fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
@ -339,9 +339,10 @@ resend:
nbytes = sendmsg(fd, &msg, 0); nbytes = sendmsg(fd, &msg, 0);
if (nbytes < 0) { if (nbytes < 0) {
ret = -errno; ret = -errno;
if (ret != -ENOBUFS) if (ret != -ENOBUFS) {
perror("write");
return ret; return ret;
}
if (!ignore_enobufs && !timeout) { if (!ignore_enobufs && !timeout) {
perror("write"); perror("write");
return ret; return ret;
@ -454,9 +455,6 @@ int main(int argc, char **argv)
unsigned char extended = 0; unsigned char extended = 0;
unsigned char canfd = 0; unsigned char canfd = 0;
unsigned char canxl = 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 brs = 0;
unsigned char esi = 0; unsigned char esi = 0;
unsigned char mix = 0; unsigned char mix = 0;
@ -576,6 +574,7 @@ int main(int argc, char **argv)
case 'm': case 'm':
mix = 1; mix = 1;
canfd = 1; /* to switch the socket into CAN FD mode */
view |= CANLIB_VIEW_INDENT_SFF; view |= CANLIB_VIEW_INDENT_SFF;
break; break;
@ -778,58 +777,14 @@ int main(int argc, char **argv)
&loopback, sizeof(loopback)); &loopback, sizeof(loopback));
} }
/* get CAN netdevice MTU for frame type capabilities */
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
perror("SIOCGIFMTU");
return 1;
}
/* 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 || canxl) {
/* check if the frame fits into the CAN netdevice */
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
perror("SIOCGIFMTU");
return 1;
}
if (canfd) { if (canfd) {
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ /* 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)); cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len));
@ -838,6 +793,41 @@ int main(int argc, char **argv)
if (cu.fd.len > CANFD_MAX_DLEN) if (cu.fd.len > CANFD_MAX_DLEN)
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 { } else {
/* sanitize Classical CAN 2.0 frame length */ /* sanitize Classical CAN 2.0 frame length */
if (len8_dlc) { if (len8_dlc) {
@ -997,12 +987,12 @@ int main(int argc, char **argv)
rnd = random(); rnd = random();
if (xl_flags_mode == MODE_RANDOM) { if (xl_flags_mode == MODE_RANDOM) {
cu.xl.flags = rnd & (CANXL_SEC | CANXL_RRS); cu.xl.flags = rnd & CANXL_SEC;
} else if (xl_flags_mode == MODE_FIX) { } else if (xl_flags_mode == MODE_FIX) {
cu.xl.flags = xl_flags; cu.xl.flags = xl_flags;
} else if (xl_flags_mode == MODE_INCREMENT) { } else if (xl_flags_mode == MODE_INCREMENT) {
xl_flags++; xl_flags ^= CANXL_SEC;
cu.xl.flags = (xl_flags & (CANXL_SEC | CANXL_RRS)); cu.xl.flags = (xl_flags & CANXL_SEC);
} }
/* mark CAN XL frame */ /* mark CAN XL frame */
@ -1050,31 +1040,8 @@ int main(int argc, char **argv)
} }
ret = do_send_one(s, &cu, mtu, polltimeout); ret = do_send_one(s, &cu, mtu, polltimeout);
if ((ret == -EINVAL) && mix) { if (ret)
/* 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; return 1;
}
if (burst_sent_count >= burst_count) if (burst_sent_count >= burst_count)
burst_sent_count = 0; burst_sent_count = 0;
@ -1115,41 +1082,18 @@ int main(int argc, char **argv)
} }
if (mix) { if (mix) {
canfd = 0;
canxl = 0;
i = random(); i = random();
extended = i & 1; extended = i & 1;
if (mixfd) { canfd = i & 2;
canfd = i & 2; if (canfd) {
if (canfd) { brs = i & 4;
brs = i & 4; esi = i & 8;
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 */
} }
} }

View File

@ -317,8 +317,8 @@ int main(int argc, char **argv)
for (i=0; i<currmax; i++) { for (i=0; i<currmax; i++) {
pr_debug("open %d '%s' m%08X v%08X i%d e%d.\n", pr_debug("open %d '%s' m%08X v%08X i%d e%d.\n",
i, argv[optind+i], mask[i], value[i], i, argv[optind+i], mask[i], value[i],
inv_filter[i], err_mask[i]); inv_filter[i], err_mask[i]);
if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("socket"); perror("socket");

View File

@ -68,7 +68,7 @@
#endif #endif
#define DEVSZ 22 /* IFNAMSZ + 6 */ #define DEVSZ 22 /* IFNAMSZ + 6 */
#define TIMESZ sizeof("(1345212884.318850123) ") #define TIMESZ sizeof("(1345212884.318850) ")
#define BUFSZ (TIMESZ + DEVSZ + AFRSZ) #define BUFSZ (TIMESZ + DEVSZ + AFRSZ)
/* adapt sscanf() functions below on error */ /* adapt sscanf() functions below on error */
@ -452,20 +452,14 @@ int main(int argc, char **argv)
return 1; return 1;
} }
log_tv.tv_sec = sec; log_tv.tv_sec = sec;
log_tv.tv_usec = usec;
/* /*
* ensure the fractions of seconds are 6 or 9 decimal places long to catch * ensure the fractions of seconds are 6 decimal places long to catch
* 3rd party or handcrafted logfiles that treat the timestamp as float * 3rd party or handcrafted logfiles that treat the timestamp as float
*/ */
switch (strchr(buf, ')') - strchr(buf, '.')) { if (strchr(buf, ')') - strchr(buf, '.') != 7) {
case 7: //6 fprintf(stderr, "timestamp format in logfile requires 6 decimal places\n");
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; return 1;
} }
@ -547,25 +541,19 @@ int main(int argc, char **argv)
break; break;
} }
if (sscanf(buf, "(%llu.%llu) %21s %6299s", &sec, &usec, device, afrbuf) != 4) { if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, device, afrbuf) != 4) {
fprintf(stderr, "incorrect line format in logfile\n"); fprintf(stderr, "incorrect line format in logfile\n");
return 1; return 1;
} }
log_tv.tv_sec = sec; log_tv.tv_sec = sec;
log_tv.tv_usec = usec;
/* /*
* ensure the fractions of seconds are 6 or 9 decimal places long to catch * ensure the fractions of seconds are 6 decimal places long to catch
* 3rd party or handcrafted logfiles that treat the timestamp as float * 3rd party or handcrafted logfiles that treat the timestamp as float
*/ */
switch (strchr(buf, ')') - strchr(buf, '.')) { if (strchr(buf, ')') - strchr(buf, '.') != 7) {
case 7: //6 fprintf(stderr, "timestamp format in logfile requires 6 decimal places\n");
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; return 1;
} }

View File

@ -80,10 +80,7 @@ static void print_usage(char *prg)
"_{dlc}:\n" "_{dlc}:\n"
" an optional 9..F data length code value when payload length is 8\n" " an optional 9..F data length code value when payload length is 8\n"
"<flags>:\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" "\n"
"<vcid>:\n" "<vcid>:\n"
" 2 hex chars - virtual CAN network identifier (00 .. FF)\n" " 2 hex chars - virtual CAN network identifier (00 .. FF)\n"
@ -103,8 +100,7 @@ static void print_usage(char *prg)
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n" " 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n"
" 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n" " 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n"
"\n", "\n",
prg, prg, prg, prg);
CANFD_BRS, CANFD_ESI, CANFD_FDF);
} }
int main(int argc, char **argv) int main(int argc, char **argv)

View File

@ -161,15 +161,15 @@ void switchvdl(char *delim)
int comp(const void *elem1, const void *elem2) int comp(const void *elem1, const void *elem2)
{ {
unsigned long f = ((struct snif*)elem1)->current.can_id; unsigned long f = ((struct snif*)elem1)->current.can_id;
unsigned long s = ((struct snif*)elem2)->current.can_id; unsigned long s = ((struct snif*)elem2)->current.can_id;
if (f > s) if (f > s)
return 1; return 1;
if (f < s) if (f < s)
return -1; return -1;
return 0; return 0;
} }
void print_usage(char *prg) void print_usage(char *prg)
@ -741,10 +741,10 @@ int handle_timeo(long currcms)
do_clr(i, UPDATE); do_clr(i, UPDATE);
} }
else if ((sniftab[i].hold) && (sniftab[i].hold < currcms)) { else if ((sniftab[i].hold) && (sniftab[i].hold < currcms)) {
memset(&sniftab[i].marker.data, 0, max_dlen); memset(&sniftab[i].marker.data, 0, max_dlen);
print_snifline(i); print_snifline(i);
sniftab[i].hold = 0; /* disable update by hold */ sniftab[i].hold = 0; /* disable update by hold */
} }
else else
printf("%s", CSR_DOWN); /* skip my line */ printf("%s", CSR_DOWN); /* skip my line */

View File

@ -1077,7 +1077,7 @@ int isobusfs_cli_interactive(struct isobusfs_priv *priv)
} }
} }
pr_int("unknown command\n"); pr_int("unknown comand\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 specific dir */ /* expected result \\vol1\~\ not clear if it is manufacture speficic 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 won't to stop sending * but it would be nice to have it. Especially if we wont 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 access path %s, for read %s. %s", path, pr_err("failed to acces 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 within this * If a client sends a command, which is not defined withing 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 */
/* TODO: actually, this is PGN input filter. Should we use different /* TOOD: 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. Won't be able to generate proper manufacturer-specific directory name. Falling mack to MCMC0000"); pr_warn("local name is not set. Wont 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 assume, the relative path stored in res->name is not longer * We assime, the relative path stored in res->name is not longer
* than absolute path * than absolue 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 for SRC and DST, so we have to do it manually. * -EINVAL vor 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), read size: %d", pr_debug("> tx: Read File Response. Error code: %d (%s), readed 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

@ -426,112 +426,112 @@ int main(int argc, char **argv)
} }
} }
if (frame.can_id & CAN_EFF_FLAG) if (frame.can_id & CAN_EFF_FLAG)
printf(" %s %8X", argv[optind], frame.can_id & CAN_EFF_MASK); 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 (nbytes == CAN_MTU)
printf(" [%d] ", frame.len);
else
printf(" [%02d] ", frame.len);
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);
datidx = ext+1;
break;
case 0x30:
n_pci &= 0x0F;
printf("[FC] FC: %d ", n_pci);
if (n_pci > 3)
n_pci = 3;
printf("= %s # ", fc_info[n_pci]);
printf("BS: %d %s# ", frame.data[ext+1],
(frame.data[ext+1])? "":"= off ");
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 else
printf("reserved"); printf(" %s %3X", argv[optind], frame.can_id & CAN_SFF_MASK);
break;
default: if (ext)
printf("[??]"); printf("{%02X}", frame.data[0]);
}
if (datidx && frame.len > datidx) { if (nbytes == CAN_MTU)
printf(" "); printf(" [%d] ", frame.len);
for (i = datidx; i < frame.len; i++) { else
printf("%02X ", frame.data[i]); printf(" [%02d] ", frame.len);
}
if (asc) { datidx = 0;
printf("%*s", ((7-ext) - (frame.len-datidx))*3 + 5 , n_pci = frame.data[ext];
"- '");
for (i = datidx; i < frame.len; i++) { switch (n_pci & 0xF0) {
printf("%c",((frame.data[i] > 0x1F) && case 0x00:
(frame.data[i] < 0x7F))? is_ff = 1;
frame.data[i] : '.'); 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;
} }
printf("'"); break;
}
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) case 0x10:
printf("%s", ATTRESET); is_ff = 1;
printf("\n"); fflen = ((n_pci & 0x0F)<<8) + frame.data[ext+1];
fflush(stdout); 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);
datidx = ext+1;
break;
case 0x30:
n_pci &= 0x0F;
printf("[FC] FC: %d ", n_pci);
if (n_pci > 3)
n_pci = 3;
printf("= %s # ", fc_info[n_pci]);
printf("BS: %d %s# ", frame.data[ext+1],
(frame.data[ext+1])? "":"= off ");
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 (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;
}
}
if (color)
printf("%s", ATTRESET);
printf("\n");
fflush(stdout);
} }
close(s); close(s);

View File

@ -243,177 +243,177 @@ int main(int argc, char **argv)
continue; 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 */ /* check extended address if provided */
if (rx_ext && frame.data[0] != rx_extaddr) if (ext && extaddr != frame.data[0])
continue; continue;
n_pci = frame.data[rx_ext]; /* only get flow control information from dst CAN ID */
/* check flow control PCI only */ if (frame.can_id == dst) {
if ((n_pci & 0xF0) != 0x30) /* check extended address if provided */
continue; if (rx_ext && frame.data[0] != rx_extaddr)
continue;
bs = frame.data[rx_ext + 1]; n_pci = frame.data[rx_ext];
stmin = frame.data[rx_ext + 2]; /* check flow control PCI only */
} if ((n_pci & 0xF0) != 0x30)
continue;
/* data content starts and index datidx */ bs = frame.data[rx_ext + 1];
datidx = 0; stmin = frame.data[rx_ext + 2];
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 */ /* data content starts and index datidx */
if (frame.len < rcvlen + datidx) datidx = 0;
fflen = rcvlen = 0;
/* get number of digits for printing */ n_pci = frame.data[ext];
fflen_digits = getdigits(fflen); switch (n_pci & 0xF0) {
/* get CAN FD bitrate & LL_DL setting information */ case 0x00:
brs = frame.flags & CANFD_BRS; /* SF */
ll_dl = frame.len; if (n_pci & 0xF) {
if (ll_dl < 8) fflen = rcvlen = n_pci & 0xF;
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; datidx = ext+1;
rcvlen += frame.len - datidx; } else {
fflen = rcvlen = frame.data[ext + 1];
datidx = ext+2;
} }
}
break;
default: /* ignore incorrect SF PDUs */
break; if (frame.len < rcvlen + datidx)
} fflen = rcvlen = 0;
/* PDU reception in process */ /* get number of digits for printing */
if (rcvlen) { fflen_digits = getdigits(fflen);
if (rcvlen > fflen)
rcvlen = fflen;
percent = (rcvlen * 100 / fflen); /* get CAN FD bitrate & LL_DL setting information */
printf("\r %3lu%% ", percent); brs = frame.flags & CANFD_BRS;
ll_dl = frame.len;
if (ll_dl < 8)
ll_dl = 8;
printf("|"); ioctl(s, SIOCGSTAMP, &start_tv);
if (percent > 100) /* determine CAN frame mode for this PDU */
percent = 100; if (nbytes == CAN_MTU)
canfd_on = 0;
for (i=0; i < NUMBAR; i++){
if (i < (int)(percent/PERCENTRES))
printf("X");
else else
printf("."); 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;
} }
printf("| %*lu/%lu ", fflen_digits, rcvlen, fflen);
}
/* PDU complete */ /* PDU reception in process */
if (rcvlen && rcvlen >= fflen) { if (rcvlen) {
if (rcvlen > fflen)
rcvlen = fflen;
printf("\r%s %02d%c (BS:%2hhu # ", canfd_on?"CAN-FD":"CAN2.0", ll_dl, brs?'*':' ', bs); percent = (rcvlen * 100 / fflen);
if (stmin < 0x80) printf("\r %3lu%% ", percent);
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); printf("|");
/* calculate time */ if (percent > 100)
ioctl(s, SIOCGSTAMP, &end_tv); percent = 100;
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 */ for (i=0; i < NUMBAR; i++){
if (diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000){ if (i < (int)(percent/PERCENTRES))
printf("%llu.%06llus ", (unsigned long long)diff_tv.tv_sec, (unsigned long long)diff_tv.tv_usec); printf("X");
printf("=> %lu byte/s", (fflen * 1000) / else
(unsigned long)(diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000)); printf(".");
} else }
printf("(no time available) "); printf("| %*lu/%lu ", fflen_digits, rcvlen, fflen);
}
printf("\n"); /* PDU complete */
/* wait for next PDU */ if (rcvlen && rcvlen >= fflen) {
fflen = rcvlen = 0;
} printf("\r%s %02d%c (BS:%2hhu # ", canfd_on?"CAN-FD":"CAN2.0", ll_dl, brs?'*':' ', bs);
fflush(stdout); 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); close(s);

View File

@ -82,183 +82,183 @@ void print_usage(char *prg)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int s; int s;
struct sockaddr_can addr; struct sockaddr_can addr;
static struct can_isotp_options opts; static struct can_isotp_options opts;
static struct can_isotp_fc_options fcopts; static struct can_isotp_fc_options fcopts;
static struct can_isotp_ll_options llopts; static struct can_isotp_ll_options llopts;
int opt, i; int opt, i;
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
__u32 force_rx_stmin = 0; __u32 force_rx_stmin = 0;
int loop = 0; int loop = 0;
unsigned char msg[BUFSIZE]; unsigned char msg[BUFSIZE];
int nbytes; 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) { while ((opt = getopt(argc, argv, "s:d:x:p:P:b:m:w:f:lFL:?")) != -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);
if (strlen(optarg) > 7) if (strlen(optarg) > 7)
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG; addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
break; break;
case 'd': case 'd':
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16); addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
if (strlen(optarg) > 7) if (strlen(optarg) > 7)
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG; addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
break; break;
case 'x': case 'x':
{ {
int elements = sscanf(optarg, "%hhx:%hhx", int elements = sscanf(optarg, "%hhx:%hhx",
&opts.ext_address, &opts.ext_address,
&opts.rx_ext_address); &opts.rx_ext_address);
if (elements == 1) if (elements == 1)
opts.flags |= CAN_ISOTP_EXTEND_ADDR; opts.flags |= CAN_ISOTP_EXTEND_ADDR;
else if (elements == 2) else if (elements == 2)
opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR); opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
else { else {
printf("incorrect extended addr values '%s'.\n", optarg); printf("incorrect extended addr values '%s'.\n", optarg);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
} }
case 'p': case 'p':
{ {
int elements = sscanf(optarg, "%hhx:%hhx", int elements = sscanf(optarg, "%hhx:%hhx",
&opts.txpad_content, &opts.txpad_content,
&opts.rxpad_content); &opts.rxpad_content);
if (elements == 1) if (elements == 1)
opts.flags |= CAN_ISOTP_TX_PADDING; opts.flags |= CAN_ISOTP_TX_PADDING;
else if (elements == 2) else if (elements == 2)
opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING); opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1) else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
opts.flags |= CAN_ISOTP_RX_PADDING; opts.flags |= CAN_ISOTP_RX_PADDING;
else { else {
printf("incorrect padding values '%s'.\n", optarg); printf("incorrect padding values '%s'.\n", optarg);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
} }
case 'P': case 'P':
if (optarg[0] == 'l') if (optarg[0] == 'l')
opts.flags |= CAN_ISOTP_CHK_PAD_LEN; opts.flags |= CAN_ISOTP_CHK_PAD_LEN;
else if (optarg[0] == 'c') else if (optarg[0] == 'c')
opts.flags |= CAN_ISOTP_CHK_PAD_DATA; opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
else if (optarg[0] == 'a') else if (optarg[0] == 'a')
opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA); opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
else { else {
printf("unknown padding check option '%c'.\n", optarg[0]); printf("unknown padding check option '%c'.\n", optarg[0]);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
case 'b': case 'b':
fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF; fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF;
break; break;
case 'm': case 'm':
fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF; fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF;
break; break;
case 'w': case 'w':
fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF; fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF;
break; break;
case 'f': case 'f':
opts.flags |= CAN_ISOTP_FORCE_RXSTMIN; opts.flags |= CAN_ISOTP_FORCE_RXSTMIN;
force_rx_stmin = strtoul(optarg, NULL, 10); force_rx_stmin = strtoul(optarg, NULL, 10);
break; break;
case 'l': case 'l':
loop = 1; loop = 1;
break; break;
case 'F': case 'F':
opts.flags |= CAN_ISOTP_DYN_FC_PARMS; opts.flags |= CAN_ISOTP_DYN_FC_PARMS;
break; break;
case 'L': case 'L':
if (sscanf(optarg, "%hhu:%hhu:%hhu", if (sscanf(optarg, "%hhu:%hhu:%hhu",
&llopts.mtu, &llopts.mtu,
&llopts.tx_dl, &llopts.tx_dl,
&llopts.tx_flags) != 3) { &llopts.tx_flags) != 3) {
printf("unknown link layer options '%s'.\n", optarg); printf("unknown link layer options '%s'.\n", optarg);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
case '?': case '?':
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
break; break;
default: default:
fprintf(stderr, "Unknown option %c\n", opt); fprintf(stderr, "Unknown option %c\n", opt);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(1); exit(1);
break; break;
} }
} }
if ((argc - optind != 1) || if ((argc - optind != 1) ||
(addr.can_addr.tp.tx_id == NO_CAN_ID) || (addr.can_addr.tp.tx_id == NO_CAN_ID) ||
(addr.can_addr.tp.rx_id == NO_CAN_ID)) { (addr.can_addr.tp.rx_id == NO_CAN_ID)) {
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(1); exit(1);
} }
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) { if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
perror("socket"); perror("socket");
exit(1); 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);
} }
}
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)); if (opts.flags & CAN_ISOTP_FORCE_RXSTMIN)
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)); setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &force_rx_stmin, sizeof(force_rx_stmin));
if (llopts.tx_dl) { addr.can_family = AF_CAN;
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) { addr.can_ifindex = if_nametoindex(argv[optind]);
perror("link layer sockopt"); if (!addr.can_ifindex) {
exit(1); perror("if_nametoindex");
} 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); close(s);
exit(1);
}
return 0; 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;
} }

View File

@ -86,238 +86,238 @@ void print_usage(char *prg)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int s; int s;
struct sockaddr_can addr; struct sockaddr_can addr;
static struct can_isotp_options opts; static struct can_isotp_options opts;
static struct can_isotp_ll_options llopts; static struct can_isotp_ll_options llopts;
int opt; int opt;
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
unsigned int loops = 1; /* one (== no) loop by default */ unsigned int loops = 1; /* one (== no) loop by default */
useconds_t usecs = 0; /* wait before sending the PDU */ useconds_t usecs = 0; /* wait before sending the PDU */
__u32 force_tx_stmin = 0; __u32 force_tx_stmin = 0;
unsigned char buf[BUFSIZE]; unsigned char buf[BUFSIZE];
int buflen = 0; int buflen = 0;
int datalen = 0; int datalen = 0;
int retval = 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) { while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:l:g:bSCL:?")) != -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);
if (strlen(optarg) > 7) if (strlen(optarg) > 7)
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG; addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
break; break;
case 'd': case 'd':
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16); addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
if (strlen(optarg) > 7) if (strlen(optarg) > 7)
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG; addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
break; break;
case 'x': case 'x':
{ {
int elements = sscanf(optarg, "%hhx:%hhx", int elements = sscanf(optarg, "%hhx:%hhx",
&opts.ext_address, &opts.ext_address,
&opts.rx_ext_address); &opts.rx_ext_address);
if (elements == 1) if (elements == 1)
opts.flags |= CAN_ISOTP_EXTEND_ADDR; opts.flags |= CAN_ISOTP_EXTEND_ADDR;
else if (elements == 2) else if (elements == 2)
opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR); opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
else { else {
printf("incorrect extended addr values '%s'.\n", optarg); printf("incorrect extended addr values '%s'.\n", optarg);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
} }
case 'p': case 'p':
{ {
int elements = sscanf(optarg, "%hhx:%hhx", int elements = sscanf(optarg, "%hhx:%hhx",
&opts.txpad_content, &opts.txpad_content,
&opts.rxpad_content); &opts.rxpad_content);
if (elements == 1) if (elements == 1)
opts.flags |= CAN_ISOTP_TX_PADDING; opts.flags |= CAN_ISOTP_TX_PADDING;
else if (elements == 2) else if (elements == 2)
opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING); opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1) else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
opts.flags |= CAN_ISOTP_RX_PADDING; opts.flags |= CAN_ISOTP_RX_PADDING;
else { else {
printf("incorrect padding values '%s'.\n", optarg); printf("incorrect padding values '%s'.\n", optarg);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
} }
case 'P': case 'P':
if (optarg[0] == 'l') if (optarg[0] == 'l')
opts.flags |= CAN_ISOTP_CHK_PAD_LEN; opts.flags |= CAN_ISOTP_CHK_PAD_LEN;
else if (optarg[0] == 'c') else if (optarg[0] == 'c')
opts.flags |= CAN_ISOTP_CHK_PAD_DATA; opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
else if (optarg[0] == 'a') else if (optarg[0] == 'a')
opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA); opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
else { else {
printf("unknown padding check option '%c'.\n", optarg[0]); printf("unknown padding check option '%c'.\n", optarg[0]);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
case 't': case 't':
if (!strncmp(optarg, ZERO_STRING, strlen(ZERO_STRING))) if (!strncmp(optarg, ZERO_STRING, strlen(ZERO_STRING)))
opts.frame_txtime = CAN_ISOTP_FRAME_TXTIME_ZERO; opts.frame_txtime = CAN_ISOTP_FRAME_TXTIME_ZERO;
else else
opts.frame_txtime = strtoul(optarg, NULL, 10); opts.frame_txtime = strtoul(optarg, NULL, 10);
break; break;
case 'f': case 'f':
opts.flags |= CAN_ISOTP_FORCE_TXSTMIN; opts.flags |= CAN_ISOTP_FORCE_TXSTMIN;
force_tx_stmin = strtoul(optarg, NULL, 10); force_tx_stmin = strtoul(optarg, NULL, 10);
break; break;
case 'D': case 'D':
datalen = strtoul(optarg, NULL, 10); datalen = strtoul(optarg, NULL, 10);
if (!datalen || datalen >= BUFSIZE) { if (!datalen || datalen >= BUFSIZE) {
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
case 'l': case 'l':
if (optarg[0] == 'i') { if (optarg[0] == 'i') {
loops = 0; /* infinite loop */ loops = 0; /* infinite loop */
} else { } else {
loops = strtoul(optarg, NULL, 10); loops = strtoul(optarg, NULL, 10);
if (!loops) { if (!loops) {
fprintf(stderr, "Invalid argument for option -l!\n"); fprintf(stderr, "Invalid argument for option -l!\n");
return 1; return 1;
} }
} }
break; break;
case 'g': case 'g':
usecs = strtoul(optarg, NULL, 10); usecs = strtoul(optarg, NULL, 10);
break; break;
case 'b': case 'b':
opts.flags |= CAN_ISOTP_WAIT_TX_DONE; opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
break; break;
case 'S': case 'S':
opts.flags |= CAN_ISOTP_SF_BROADCAST; opts.flags |= CAN_ISOTP_SF_BROADCAST;
break; break;
case 'C': case 'C':
opts.flags |= CAN_ISOTP_CF_BROADCAST; opts.flags |= CAN_ISOTP_CF_BROADCAST;
break; break;
case 'L': case 'L':
if (sscanf(optarg, "%hhu:%hhu:%hhu", if (sscanf(optarg, "%hhu:%hhu:%hhu",
&llopts.mtu, &llopts.mtu,
&llopts.tx_dl, &llopts.tx_dl,
&llopts.tx_flags) != 3) { &llopts.tx_flags) != 3) {
printf("unknown link layer options '%s'.\n", optarg); printf("unknown link layer options '%s'.\n", optarg);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
} }
break; break;
case '?': case '?':
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(0); exit(0);
break; break;
default: default:
fprintf(stderr, "Unknown option %c\n", opt); fprintf(stderr, "Unknown option %c\n", opt);
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(1); exit(1);
break; break;
} }
} }
#define BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST) #define BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST)
if ((argc - optind != 1) || if ((argc - optind != 1) ||
(addr.can_addr.tp.tx_id == NO_CAN_ID) || (addr.can_addr.tp.tx_id == NO_CAN_ID) ||
((opts.flags & BC_FLAGS) == BC_FLAGS) || ((opts.flags & BC_FLAGS) == BC_FLAGS) ||
((addr.can_addr.tp.rx_id == NO_CAN_ID) && ((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
(!(opts.flags & BC_FLAGS)))) { (!(opts.flags & BC_FLAGS)))) {
print_usage(basename(argv[0])); print_usage(basename(argv[0]));
exit(1); 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 ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) { if (opts.flags & CAN_ISOTP_FORCE_TXSTMIN)
perror("socket"); setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &force_tx_stmin, sizeof(force_tx_stmin));
exit(1);
}
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) { addr.can_family = AF_CAN;
perror("sockopt"); addr.can_ifindex = if_nametoindex(argv[optind]);
exit(1); 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 (llopts.tx_dl) { if (!datalen) {
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) { while (buflen < BUFSIZE && scanf("%hhx", &buf[buflen]) == 1)
perror("link layer sockopt"); buflen++;
exit(1); } else {
} for (buflen = 0; buflen < datalen; buflen++)
} buf[buflen] = ((buflen % 0xFF) + 1) & 0xFF;
}
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: loop:
if (usecs) if (usecs)
usleep(usecs); usleep(usecs);
retval = write(s, buf, buflen); retval = write(s, buf, buflen);
if (retval < 0) { if (retval < 0) {
perror("write"); perror("write");
return retval; return retval;
} }
if (retval != buflen) if (retval != buflen)
fprintf(stderr, "wrote only %d from %d byte\n", retval, buflen); fprintf(stderr, "wrote only %d from %d byte\n", retval, buflen);
if (loops) { if (loops) {
if (--loops) if (--loops)
goto loop; goto loop;
} else { } else {
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.
*/ */
close(s); close(s);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -112,10 +112,10 @@ static struct {
int sig_alrm; int sig_alrm;
int sig_usr1; int sig_usr1;
int state; int state;
#define STATE_INITIAL 0 #define STATE_INITIAL 0
#define STATE_REQ_SENT 1 #define STATE_REQ_SENT 1
#define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */ #define STATE_REQ_PENDING 2 /* wait 1250 msec for first claim */
#define STATE_OPERATIONAL 3 #define STATE_OPERATIONAL 3
} s = { } s = {
.intf = default_intf, .intf = default_intf,
.ranges = default_range, .ranges = default_range,
@ -126,8 +126,8 @@ static struct {
struct { struct {
uint64_t name; uint64_t name;
int flags; int flags;
#define F_USE 0x01 #define F_USE 0x01
#define F_SEEN 0x02 #define F_SEEN 0x02
} addr[J1939_IDLE_ADDR /* =254 */]; } addr[J1939_IDLE_ADDR /* =254 */];
/* lookup by name */ /* lookup by name */
@ -209,7 +209,7 @@ static int open_socket(const char *device, uint64_t name)
if (s.verbose) if (s.verbose)
fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_FILTER, <filter>, %zd);\n", sizeof(filt)); fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_FILTER, <filter>, %zd);\n", sizeof(filt));
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER,
&filt, sizeof(filt)); &filt, sizeof(filt));
if (ret < 0) if (ret < 0)
err(1, "setsockopt filter"); err(1, "setsockopt filter");
@ -217,7 +217,7 @@ static int open_socket(const char *device, uint64_t name)
if (s.verbose) if (s.verbose)
fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BROADCAST, %d, %zd);\n", value, sizeof(value)); fprintf(stderr, "- setsockopt(, SOL_SOCKET, SO_BROADCAST, %d, %zd);\n", value, sizeof(value));
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
&value, sizeof(value)); &value, sizeof(value));
if (ret < 0) if (ret < 0)
err(1, "setsockopt set broadcast"); err(1, "setsockopt set broadcast");

View File

@ -31,11 +31,11 @@
* strict type-checking.. See the * strict type-checking.. See the
* "unnecessary" pointer comparison. * "unnecessary" pointer comparison.
*/ */
#define min(x, y) ({ \ #define min(x, y) ({ \
typeof(x) _min1 = (x); \ typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \ typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \ (void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; }) _min1 < _min2 ? _min1 : _min2; })
struct j1939cat_stats { struct j1939cat_stats {
@ -98,7 +98,7 @@ static const char help_msg[] =
static const char optstring[] = "?hi:vs:rp:P:R:B"; static const char optstring[] = "?hi:vs:rp:P:R:B";
static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd, 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; ssize_t num_sent;
int flags = 0; int flags = 0;
@ -132,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, static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *name,
struct timespec *cur) struct timespec *cur)
{ {
struct j1939cat_stats *stats = &priv->stats; struct j1939cat_stats *stats = &priv->stats;
@ -140,8 +140,8 @@ static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *nam
return; return;
fprintf(stderr, " %s: %llu s %llu us (seq=%03u, send=%07u)", 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, name, (unsigned long long)cur->tv_sec, (unsigned long long)cur->tv_nsec / 1000,
stats->tskey, stats->send); stats->tskey, stats->send);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
@ -226,7 +226,7 @@ static int j1939cat_extract_serr(struct j1939cat_priv *priv)
stats->tskey = serr->ee_data; stats->tskey = serr->ee_data;
j1939cat_print_timestamp(priv, j1939cat_tstype_to_str(serr->ee_info), j1939cat_print_timestamp(priv, j1939cat_tstype_to_str(serr->ee_info),
&tss->ts[0]); &tss->ts[0]);
if (serr->ee_info == SCM_TSTAMP_SCHED) if (serr->ee_info == SCM_TSTAMP_SCHED)
return -EINTR; return -EINTR;
@ -338,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, 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; struct j1939cat_stats *stats = &priv->stats;
ssize_t count; ssize_t count;
@ -411,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, 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; int ret = EXIT_SUCCESS;
off_t orig = 0; off_t orig = 0;
@ -617,7 +617,7 @@ static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
if (priv->todo_prio >= 0) { if (priv->todo_prio >= 0) {
ret = setsockopt(priv->sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, 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) { if (ret < 0) {
warn("set priority %i", priv->todo_prio); warn("set priority %i", priv->todo_prio);
return EXIT_FAILURE; return EXIT_FAILURE;
@ -633,11 +633,11 @@ static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
} }
sock_opt = SOF_TIMESTAMPING_SOFTWARE | sock_opt = SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_OPT_CMSG | SOF_TIMESTAMPING_OPT_CMSG |
SOF_TIMESTAMPING_TX_ACK | SOF_TIMESTAMPING_TX_ACK |
SOF_TIMESTAMPING_TX_SCHED | SOF_TIMESTAMPING_TX_SCHED |
SOF_TIMESTAMPING_OPT_STATS | SOF_TIMESTAMPING_OPT_TSONLY | SOF_TIMESTAMPING_OPT_STATS | SOF_TIMESTAMPING_OPT_TSONLY |
SOF_TIMESTAMPING_OPT_ID | SOF_TIMESTAMPING_RX_SOFTWARE; SOF_TIMESTAMPING_OPT_ID | SOF_TIMESTAMPING_RX_SOFTWARE;
if (setsockopt(priv->sock, SOL_SOCKET, SO_TIMESTAMPING, if (setsockopt(priv->sock, SOL_SOCKET, SO_TIMESTAMPING,
(char *) &sock_opt, sizeof(sock_opt))) (char *) &sock_opt, sizeof(sock_opt)))

View File

@ -76,7 +76,7 @@ static struct {
static const int ival_1 = 1; static const int ival_1 = 1;
static char ctrlmsg[ static char ctrlmsg[
CMSG_SPACE(sizeof(struct timeval)) CMSG_SPACE(sizeof(struct timeval))
+ CMSG_SPACE(sizeof(uint8_t)) /* dest addr */ + CMSG_SPACE(sizeof(uint8_t)) /* dest addr */
+ CMSG_SPACE(sizeof(uint64_t)) /* dest name */ + CMSG_SPACE(sizeof(uint64_t)) /* dest name */
+ CMSG_SPACE(sizeof(uint8_t)) /* priority */ + CMSG_SPACE(sizeof(uint8_t)) /* priority */
@ -264,9 +264,9 @@ abs_time:
struct tm tm; struct tm tm;
tm = *localtime(&tdut.tv_sec); tm = *localtime(&tdut.tv_sec);
printf("(%04u%02u%02uT%02u%02u%02u.%04llu)", printf("(%04u%02u%02uT%02u%02u%02u.%04llu)",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_hour, tm.tm_min, tm.tm_sec,
(unsigned long long)tdut.tv_usec/100); (unsigned long long)tdut.tv_usec/100);
} }
} }
printf(" %s ", libj1939_addr2str(&src)); printf(" %s ", libj1939_addr2str(&src));

View File

@ -68,9 +68,9 @@ static struct {
int pkt_len; int pkt_len;
int priority; int priority;
int defined; int defined;
#define DEF_SRC 1 #define DEF_SRC 1
#define DEF_DST 2 #define DEF_DST 2
#define DEF_PRIO 4 #define DEF_PRIO 4
struct sockaddr_can src, dst; struct sockaddr_can src, dst;
} s = { } s = {
.priority = 6, .priority = 6,

39
lib.c
View File

@ -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 */ /* CAN DLC to real data length conversion helpers */
static const unsigned char dlc2len[] = { static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64}; 8, 12, 16, 20, 24, 32, 48, 64};
/* get data length from raw data length code (DLC) */ /* get data length from raw data length code (DLC) */
unsigned char can_fd_dlc2len(unsigned char dlc) unsigned char can_fd_dlc2len(unsigned char dlc)
@ -92,17 +92,16 @@ unsigned char can_fd_dlc2len(unsigned char dlc)
return dlc2len[dlc & 0x0F]; return dlc2len[dlc & 0x0F];
} }
static const unsigned char len2dlc[] = { static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ 9, 9, 9, 9, /* 9 - 12 */
9, 9, 9, 9, /* 9 - 12 */ 10, 10, 10, 10, /* 13 - 16 */
10, 10, 10, 10, /* 13 - 16 */ 11, 11, 11, 11, /* 17 - 20 */
11, 11, 11, 11, /* 17 - 20 */ 12, 12, 12, 12, /* 21 - 24 */
12, 12, 12, 12, /* 21 - 24 */ 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
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, /* 33 - 40 */ 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
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, /* 49 - 56 */ 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
/* map the sanitized data length to an appropriate data length code */ /* map the sanitized data length to an appropriate data length code */
unsigned char can_fd_len2dlc(unsigned char len) unsigned char can_fd_len2dlc(unsigned char len)
@ -778,8 +777,8 @@ static int snprintf_error_ctrl(char *buf, size_t len, const struct canfd_frame *
n += snprintf(buf + n, len - n, "{"); n += snprintf(buf + n, len - n, "{");
n += snprintf_error_data(buf + n, len - n, cf->data[1], n += snprintf_error_data(buf + n, len - n, cf->data[1],
controller_problems, controller_problems,
ARRAY_SIZE(controller_problems)); ARRAY_SIZE(controller_problems));
n += snprintf(buf + n, len - n, "}"); n += snprintf(buf + n, len - n, "}");
return n; return n;
@ -794,8 +793,8 @@ static int snprintf_error_prot(char *buf, size_t len, const struct canfd_frame *
n += snprintf(buf + n, len - n, "{{"); n += snprintf(buf + n, len - n, "{{");
n += snprintf_error_data(buf + n, len - n, cf->data[2], n += snprintf_error_data(buf + n, len - n, cf->data[2],
protocol_violation_types, protocol_violation_types,
ARRAY_SIZE(protocol_violation_types)); ARRAY_SIZE(protocol_violation_types));
n += snprintf(buf + n, len - n, "}{"); n += snprintf(buf + n, len - n, "}{");
if (cf->data[3] > 0 && if (cf->data[3] > 0 &&
cf->data[3] < ARRAY_SIZE(protocol_violation_locations)) cf->data[3] < ARRAY_SIZE(protocol_violation_locations))
@ -820,7 +819,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, 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; canid_t class, mask;
int i, n = 0, classes = 0; int i, n = 0, classes = 0;
@ -859,7 +858,7 @@ int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf
n += tmp_n; n += tmp_n;
if (mask == CAN_ERR_LOSTARB) if (mask == CAN_ERR_LOSTARB)
n += snprintf_error_lostarb(buf + n, len - n, n += snprintf_error_lostarb(buf + n, len - n,
cf); cf);
if (mask == CAN_ERR_CRTL) if (mask == CAN_ERR_CRTL)
n += snprintf_error_ctrl(buf + n, len - n, cf); n += snprintf_error_ctrl(buf + n, len - n, cf);
if (mask == CAN_ERR_PROT) if (mask == CAN_ERR_PROT)
@ -879,7 +878,7 @@ int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf
} }
int64_t timespec_diff_ms(struct timespec *ts1, int64_t timespec_diff_ms(struct timespec *ts1,
struct timespec *ts2) struct timespec *ts2)
{ {
int64_t diff = (ts1->tv_sec - ts2->tv_sec) * 1000; int64_t diff = (ts1->tv_sec - ts2->tv_sec) * 1000;

2
lib.h
View File

@ -49,8 +49,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <linux/can.h>
#ifdef DEBUG #ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args) #define pr_debug(fmt, args...) printf(fmt, ##args)
#else #else

View File

@ -253,31 +253,6 @@ 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

@ -17,7 +17,6 @@
#include <linux/can/j1939.h> #include <linux/can/j1939.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <time.h>
#include <sys/socket.h> #include <sys/socket.h>
#ifndef J1939_LIB_H #ifndef J1939_LIB_H
@ -43,7 +42,6 @@ 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

@ -296,7 +296,7 @@ static void canxl_asc(cu_t *cu, int devno, int mtu,
#define DEVSZ 22 #define DEVSZ 22
#define EXTRASZ 20 #define EXTRASZ 20
#define TIMESZ sizeof("(1345212884.318850123) ") #define TIMESZ sizeof("(1345212884.318850) ")
#define BUFSZ (DEVSZ + AFRSZ + EXTRASZ + TIMESZ) #define BUFSZ (DEVSZ + AFRSZ + EXTRASZ + TIMESZ)
/* adapt sscanf() functions below on error */ /* adapt sscanf() functions below on error */
@ -407,22 +407,7 @@ int main(int argc, char **argv)
} }
} }
tv.tv_sec = sec; 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 */ if (print_banner) { /* print banner */
print_banner = 0; print_banner = 0;

View File

@ -51,7 +51,7 @@
#include "lib.h" #include "lib.h"
#define DEVSZ 22 #define DEVSZ 22
#define TIMESZ 25 /* sizeof("(1345212884.318850123) ") */ #define TIMESZ 22 /* sizeof("(1345212884.318850) ") */
#define BUFSZ (DEVSZ + AFRSZ + TIMESZ) #define BUFSZ (DEVSZ + AFRSZ + TIMESZ)
/* adapt sscanf() functions below on error */ /* adapt sscanf() functions below on error */
@ -61,7 +61,7 @@
#if (DEVSZ != 22) #if (DEVSZ != 22)
#error "DEVSZ value does not fit sscanf restrictions!" #error "DEVSZ value does not fit sscanf restrictions!"
#endif #endif
#if (TIMESZ != 25) #if (TIMESZ != 22)
#error "TIMESZ value does not fit sscanf restrictions!" #error "TIMESZ value does not fit sscanf restrictions!"
#endif #endif
@ -78,7 +78,7 @@ int main(void)
return 1; return 1;
} }
if (sscanf(buf, "%24s %21s %6299s", timestamp, device, afrbuf) != 3) if (sscanf(buf, "%21s %21s %6299s", timestamp, device, afrbuf) != 3)
return 1; return 1;
mtu = parse_canframe(afrbuf, &cu); mtu = parse_canframe(afrbuf, &cu);

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
@ -370,13 +370,8 @@ int main(int argc, char *argv[])
/* retrieve the name of the created CAN netdevice */ /* retrieve the name of the created CAN netdevice */
if (ioctl(fd, SIOCGIFNAME, ifr.ifr_name) < 0) { if (ioctl(fd, SIOCGIFNAME, ifr.ifr_name) < 0) {
if (name) { perror("ioctl SIOCGIFNAME");
perror("ioctl SIOCGIFNAME"); exit(EXIT_FAILURE);
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); syslogger(LOG_NOTICE, "attached TTY %s to netdevice %s\n", ttypath, ifr.ifr_name);

View File

@ -197,7 +197,7 @@ int main(int argc, char *argv[])
if (verbose) if (verbose)
fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &%i);\n", todo_prio); fprintf(stderr, "- setsockopt(, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &%i);\n", todo_prio);
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&todo_prio, sizeof(todo_prio)); &todo_prio, sizeof(todo_prio));
if (ret < 0) if (ret < 0)
err(1, "set priority %i", todo_prio); err(1, "set priority %i", todo_prio);
} }
@ -246,7 +246,7 @@ int main(int argc, char *argv[])
if (verbose) if (verbose)
fprintf(stderr, "- sendto(, <dat>, %i, 0, %s, %zi);\n", todo_send, libj1939_addr2str(&peername), sizeof(peername)); fprintf(stderr, "- sendto(, <dat>, %i, 0, %s, %zi);\n", todo_send, libj1939_addr2str(&peername), sizeof(peername));
ret = sendto(sock, dat, todo_send, 0, ret = sendto(sock, dat, todo_send, 0,
(void *)&peername, sizeof(peername)); (void *)&peername, sizeof(peername));
} else { } else {
/* /*
* we may do sendto(sock, dat, todo_send, 0, NULL, 0) * 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"); fprintf(stderr, "- while (1)\n");
while (todo_echo || todo_recv) { while (todo_echo || todo_recv) {
/* /*
* reuse peername for storing the sender's peername of * re-use peername for storing the sender's peername of
* received packets * received packets
*/ */
if (verbose) if (verbose)
fprintf(stderr, "- recvfrom(, <dat>, %zi, 0, &<peername>, %zi);\n", sizeof(peername), sizeof(peername)); fprintf(stderr, "- recvfrom(, <dat>, %zi, 0, &<peername>, %zi);\n", sizeof(peername), sizeof(peername));
peernamelen = sizeof(peername); peernamelen = sizeof(peername);
ret = recvfrom(sock, dat, sizeof(dat), 0, ret = recvfrom(sock, dat, sizeof(dat), 0,
(void *)&peername, &peernamelen); (void *)&peername, &peernamelen);
if (ret < 0) { if (ret < 0) {
if (EINTR == errno) { if (EINTR == errno) {
if (verbose) if (verbose)
@ -287,7 +287,7 @@ int main(int argc, char *argv[])
if (verbose) if (verbose)
fprintf(stderr, "- sendto(, <dat>, %i, 0, %s, %i);\n", ret, libj1939_addr2str(&peername), peernamelen); fprintf(stderr, "- sendto(, <dat>, %i, 0, %s, %i);\n", ret, libj1939_addr2str(&peername), peernamelen);
ret = sendto(sock, dat, ret, 0, ret = sendto(sock, dat, ret, 0,
(void *)&peername, peernamelen); (void *)&peername, peernamelen);
if (ret < 0) if (ret < 0)
err(1, "sendto"); err(1, "sendto");
} }
@ -297,7 +297,7 @@ int main(int argc, char *argv[])
if (todo_names && peername.can_addr.j1939.name) if (todo_names && peername.can_addr.j1939.name)
printf("%016llx ", peername.can_addr.j1939.name); printf("%016llx ", peername.can_addr.j1939.name);
printf("%02x %05x:", peername.can_addr.j1939.addr, 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++) { for (i = 0, j = 0; i < ret; ++i, j++) {
if (j == 8) { if (j == 8) {
printf("\n%05x ", i); printf("\n%05x ", i);