7 Commits
55 changed files with 1657 additions and 6837 deletions
+3 -3
View File
@@ -42,7 +42,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v1
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v3 uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell. # ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@@ -67,4 +67,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v1
+13 -75
View File
@@ -17,140 +17,78 @@ jobs:
- "debian:stable-slim" - "debian:stable-slim"
- "debian:testing-slim" - "debian:testing-slim"
- "debian:unstable-slim" - "debian:unstable-slim"
- "debian:experimental"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Prepare ${{ matrix.release }} container - name: Prepare ${{ matrix.release }} container
env:
release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }}
run: | run: |
podman version podman version
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 \ podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy \
lsb-release
podman exec -i -u root stable \
test -e /etc/apt/sources.list &&
podman exec -i -u root stable \
sed -i -e 's|\(http.*:\)|[arch=amd64] \1|g' /etc/apt/sources.list
podman exec -i -u root stable \
test -e /etc/apt/sources.list.d/ubuntu.sources &&
podman exec -i -u root stable \
sed -i -e '/^Components:/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources
echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs) main restricted universe multiverse" | \
podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list
echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs)-updates main restricted universe multiverse" | \
podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list
echo "deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports/ $(podman exec -i stable lsb_release -cs)-backports main restricted universe multiverse" | \
podman exec -i -u root stable tee -a /etc/apt/sources.list.d/cross.list
- name: Add Architecture
if:
matrix.release != 'ubuntu:20.04'
run: |
podman exec -i -u root stable dpkg --add-architecture arm64
podman exec -i -u root stable dpkg --add-architecture armhf
- name: Install Development Packages
env:
release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }}
run: |
podman exec -i -u root stable apt update
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt upgrade -o APT::Install-Suggests=false -qy
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \
clang \ clang \
cmake \ cmake \
gcc \ gcc \
gcc-aarch64-linux-gnu \ gcc-aarch64-linux-gnu \
gcc-arm-linux-gnueabihf \ gcc-arm-linux-gnueabihf \
libgps-dev \ gcc-mips-linux-gnu \
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 gcc (Makefile) - name: Configure & Build with mips-linux-gnu-gcc
env: env:
cc: gcc toolchain: mips-linux-gnu-gcc
run: | run: |
podman exec -i stable make CC=${cc} 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 make clean podman exec -i stable cmake --build build-${toolchain}
- 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() }}
-10
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
@@ -38,9 +31,6 @@ tags
/j1939cat /j1939cat
/j1939spy /j1939spy
/j1939sr /j1939sr
/j1939-timedate-cli
/j1939-timedate-srv
/j1939-vehicle-position-srv
/log2asc /log2asc
/log2long /log2long
/mcp251xfd-dump /mcp251xfd-dump
+87 -166
View File
@@ -1,49 +1,19 @@
cmake_minimum_required(VERSION 3.5...3.10) cmake_minimum_required(VERSION 3.5)
project(can-utils LANGUAGES C) 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)
@@ -51,7 +21,7 @@ endif()
add_definitions(-D_GNU_SOURCE) add_definitions(-D_GNU_SOURCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses -Wsign-compare") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_RXQ_OVFL=40") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_RXQ_OVFL=40")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29")
@@ -62,116 +32,94 @@ 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_ISOBUSFS
isobusfs-srv
isobusfs-cli
)
set(PROGRAMS
${PROGRAMS_CANLIB}
canerrsim
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) add_library(isobusfs SHARED
list(APPEND PROGRAMS isotpserver)
endif()
endif()
if(ENABLE_J1939)
list(APPEND PROGRAMS_J1939
j1939acd
j1939cat
j1939spy
j1939sr
testj1939
)
add_executable(j1939-timedate-cli
j1939_timedate/j1939_timedate_cli.c
)
target_link_libraries(j1939-timedate-cli
PRIVATE can j1939
)
install(TARGETS j1939-timedate-cli DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(j1939-timedate-srv
j1939_timedate/j1939_timedate_srv.c
)
target_link_libraries(j1939-timedate-srv
PRIVATE can j1939
)
install(TARGETS j1939-timedate-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(ENABLE_J1939 AND ENABLE_GPS)
add_executable(j1939-vehicle-position-srv
j1939_vehicle_position/j1939_vehicle_position_srv.c
)
target_link_libraries(j1939-vehicle-position-srv
PRIVATE can j1939 ${GPS_LIBRARIES}
)
install(TARGETS j1939-vehicle-position-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if(ENABLE_ISOBUSFS)
add_library(isobusfs EXCLUDE_FROM_ALL
isobusfs/isobusfs_cmn.c isobusfs/isobusfs_cmn.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 +133,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
) )
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,61 +147,28 @@ 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
) )
install(TARGETS isobusfs-srv DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS
isobusfs-cli
isobusfs-srv
DESTINATION ${CMAKE_INSTALL_BINDIR})
endif() endif()
if(ENABLE_LOG_FILE) add_library(can STATIC
list(APPEND PROGRAMS_CANLIB
asc2log
log2asc
log2long
)
endif()
if(ENABLE_SLCAN)
list(APPEND PROGRAMS
slcan_attach
slcand
)
list(APPEND PROGRAMS_CANLIB slcanpty)
endif()
if(ENABLE_MCP251XFD)
add_executable(mcp251xfd-dump
mcp251xfd/mcp251xfd-dev-coredump.c
mcp251xfd/mcp251xfd-dump.c
mcp251xfd/mcp251xfd-main.c
mcp251xfd/mcp251xfd-regmap.c
)
install(TARGETS mcp251xfd-dump DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
list(APPEND PROGRAMS
${PROGRAMS_CANLIB}
${PROGRAMS_J1939}
)
add_library(can STATIC EXCLUDE_FROM_ALL
lib.c 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)
if("${name}" IN_LIST PROGRAMS_J1939) if("${name}" IN_LIST PROGRAMS_J1939)
target_link_libraries(${name} target_link_libraries(${name}
PRIVATE j1939 can PRIVATE j1939
) )
elseif("${name}" IN_LIST PROGRAMS_CANLIB) elseif("${name}" IN_LIST PROGRAMS_CANLIB)
target_link_libraries(${name} target_link_libraries(${name}
@@ -264,6 +179,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"
+13 -49
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. \
@@ -64,15 +63,6 @@ CPPFLAGS += \
PROGRAMS_CANGW := \ PROGRAMS_CANGW := \
cangw cangw
PROGRAMS_J1939_TIMEDATE := \
j1939-timedate-srv \
j1939-timedate-cli
ifeq ($(HAVE_LIBGPS),1)
PROGRAMS_J1939_VEHICLE_POSITION := \
j1939-vehicle-position-srv
endif
PROGRAMS_ISOBUSFS := \ PROGRAMS_ISOBUSFS := \
isobusfs-srv \ isobusfs-srv \
isobusfs-cli isobusfs-cli
@@ -103,8 +93,6 @@ PROGRAMS_SLCAN := \
PROGRAMS := \ PROGRAMS := \
$(PROGRAMS_CANGW) \ $(PROGRAMS_CANGW) \
$(PROGRAMS_J1939_TIMEDATE) \
$(PROGRAMS_J1939_VEHICLE_POSITION) \
$(PROGRAMS_ISOBUSFS) \ $(PROGRAMS_ISOBUSFS) \
$(PROGRAMS_ISOTP) \ $(PROGRAMS_ISOTP) \
$(PROGRAMS_J1939) \ $(PROGRAMS_J1939) \
@@ -113,7 +101,6 @@ PROGRAMS := \
can-calc-bit-timing \ can-calc-bit-timing \
canbusload \ canbusload \
candump \ candump \
canerrsim \
canfdtest \ canfdtest \
cangen \ cangen \
cansequence \ cansequence \
@@ -134,8 +121,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_vehicle_position/*.o
install: install:
mkdir -p $(DESTDIR)$(PREFIX)/bin mkdir -p $(DESTDIR)$(PREFIX)/bin
@@ -153,17 +139,13 @@ cansend.o: lib.h
log2asc.o: lib.h log2asc.o: lib.h
log2long.o: lib.h log2long.o: lib.h
slcanpty.o: lib.h slcanpty.o: lib.h
j1939acd.o: lib.h libj1939.h j1939acd.o: libj1939.h
j1939cat.o: lib.h libj1939.h j1939cat.o: libj1939.h
j1939spy.o: lib.h libj1939.h j1939spy.o: libj1939.h
j1939sr.o: lib.h libj1939.h j1939sr.o: libj1939.h
testj1939.o: lib.h libj1939.h testj1939.o: libj1939.h
isobusfs_srv.o: lib.h libj1939.h isobusfs_srv.o: lib.h
isobusfs_c.o: lib.h libj1939.h isobusfs_c.o: lib.h
j1939_timedate_srv.o: lib.h libj1939.h
j1939_timedate_cli.o: lib.h libj1939.h
j1939_vehicle_position_srv.o: lib.h libj1939.h
canframelen.o: canframelen.h canframelen.o: canframelen.h
asc2log: asc2log.o lib.o asc2log: asc2log.o lib.o
@@ -177,30 +159,13 @@ cansequence: cansequence.o lib.o
log2asc: log2asc.o lib.o log2asc: log2asc.o lib.o
log2long: log2long.o lib.o log2long: log2long.o lib.o
slcanpty: slcanpty.o lib.o slcanpty: slcanpty.o lib.o
j1939acd: j1939acd.o lib.o libj1939.o j1939acd: j1939acd.o libj1939.o
j1939cat: j1939cat.o lib.o libj1939.o j1939cat: j1939cat.o libj1939.o
j1939spy: j1939spy.o lib.o libj1939.o j1939spy: j1939spy.o libj1939.o
j1939sr: j1939sr.o lib.o libj1939.o j1939sr: j1939sr.o libj1939.o
testj1939: testj1939.o lib.o libj1939.o testj1939: testj1939.o libj1939.o
j1939-timedate-srv: lib.o \
libj1939.o \
j1939_timedate/j1939_timedate_srv.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
j1939-timedate-cli: lib.o \
libj1939.o \
j1939_timedate/j1939_timedate_cli.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
j1939-vehicle-position-srv: \
lib.o \
libj1939.o \
j1939_vehicle_position/j1939_vehicle_position_srv.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) $(shell pkg-config --libs libgps) -o $@
isobusfs-srv: lib.o \ isobusfs-srv: lib.o \
libj1939.o \
isobusfs/isobusfs_cmn.o \ isobusfs/isobusfs_cmn.o \
isobusfs/isobusfs_srv.o \ isobusfs/isobusfs_srv.o \
isobusfs/isobusfs_srv_cm.o \ isobusfs/isobusfs_srv_cm.o \
@@ -213,7 +178,6 @@ isobusfs-srv: lib.o \
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
isobusfs-cli: lib.o \ isobusfs-cli: lib.o \
libj1939.o \
isobusfs/isobusfs_cmn.o \ isobusfs/isobusfs_cmn.o \
isobusfs/isobusfs_cli.o \ isobusfs/isobusfs_cli.o \
isobusfs/isobusfs_cli_cm.o \ isobusfs/isobusfs_cli_cm.o \
+2 -7
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
@@ -77,7 +72,7 @@ Follow the link to see examples on how this tools can be used:
### Additional Information: ### Additional Information:
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/html/latest/networking/can.html) * [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/Documentation/networking/can.txt)
* [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)
+82 -491
View File
@@ -58,17 +58,7 @@
#include "lib.h" #include "lib.h"
#define BUFLEN 6500 /* CAN XL mode lines can be pretty long */ #define BUFLEN 400 /* CAN FD mode lines can be pretty long */
#define NO_DIR '.'
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
#define ASC_F_XLF 0x00400000
#define ASC_F_RES 0x00800000
#define ASC_F_SEC 0x01000000
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
@@ -79,12 +69,10 @@ static void print_usage(char *prg)
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, "\t-I <infile>\t(default stdin)\n"); fprintf(stderr, "\t-I <infile>\t(default stdin)\n");
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n"); fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
fprintf(stderr, "\t-d (disable direction information R/T)\n");
fprintf(stderr, "\t-v (verbose)\n");
} }
static void prframe(FILE *file, struct timeval *tv, int dev, static void prframe(FILE *file, struct timeval *tv, int dev,
union cfu *cf, char dir) struct canfd_frame *cf, char *extra_info)
{ {
static char abuf[BUFLEN]; static char abuf[BUFLEN];
@@ -95,23 +83,19 @@ static void prframe(FILE *file, struct timeval *tv, int dev,
else else
fprintf(file, "canX "); fprintf(file, "canX ");
snprintf_canframe(abuf, sizeof(abuf), cf, 0); snprintf_canframe(abuf, sizeof(abuf), (cu_t *)cf, 0);
fprintf(file, "%s%s", abuf, extra_info);
if (dir == NO_DIR)
fprintf(file, "%s\n", abuf);
else
fprintf(file, "%s %c\n", abuf, dir);
} }
static void get_can_id(canid_t *can_id, char *idstring, int base) static void get_can_id(struct canfd_frame *cf, char *idstring, int base)
{ {
if (idstring[strlen(idstring)-1] == 'x') { if (idstring[strlen(idstring)-1] == 'x') {
*can_id = CAN_EFF_FLAG; cf->can_id = CAN_EFF_FLAG;
idstring[strlen(idstring)-1] = 0; idstring[strlen(idstring)-1] = 0;
} else } else
*can_id = 0; cf->can_id = 0;
*can_id |= strtoul(idstring, NULL, base); cf->can_id |= strtoul(idstring, NULL, base);
} }
static void calc_tv(struct timeval *tv, struct timeval *read_tv, static void calc_tv(struct timeval *tv, struct timeval *read_tv,
@@ -147,7 +131,7 @@ static void calc_tv(struct timeval *tv, struct timeval *read_tv,
} }
static void eval_can(char* buf, struct timeval *date_tvp, char timestamps, static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
char base, int dplace, int disable_dir, FILE *outfile) char base, int dplace, FILE *outfile)
{ {
int interface; int interface;
static struct timeval tv; /* current frame timestamp */ static struct timeval tv; /* current frame timestamp */
@@ -158,26 +142,27 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
int dlc = 0; int dlc = 0;
int len = 0; int len = 0;
int data[8]; int data[8];
char idstr[21]; char tmp1[BUFLEN];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
char *extra_info;
int i, items; int i, items;
unsigned long long sec, usec; unsigned long long sec, usec;
/* check for ErrorFrames */ /* check for ErrorFrames */
if (sscanf(buf, "%llu.%llu %d %20s", if (sscanf(buf, "%llu.%llu %d %s",
&sec, &usec, &sec, &usec,
&interface, idstr) == 4) { &interface, tmp1) == 4) {
read_tv.tv_sec = sec; read_tv.tv_sec = sec;
read_tv.tv_usec = usec; read_tv.tv_usec = usec;
if (!strncmp(idstr, "ErrorFrame", strlen("ErrorFrame"))) { if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
/* do not know more than 'Error' */ /* do not know more than 'Error' */
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR); cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
cf.len = CAN_ERR_DLC; cf.len = CAN_ERR_DLC;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (union cfu *)&cf, NO_DIR); prframe(outfile, &tv, interface, &cf, "\n");
fflush(outfile); fflush(outfile);
return; return;
} }
@@ -187,15 +172,15 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
/* check for CAN frames with (hexa)decimal values */ /* check for CAN frames with (hexa)decimal values */
if (base == 'h') if (base == 'h')
items = sscanf(buf, "%llu.%llu %d %20s %4s %c %x %x %x %x %x %x %x %x %x", items = sscanf(buf, "%llu.%llu %d %s %2s %c %x %x %x %x %x %x %x %x %x",
&sec, &usec, &interface, &sec, &usec, &interface,
idstr, dir, &rtr, &dlc, tmp1, dir, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3], &data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]); &data[4], &data[5], &data[6], &data[7]);
else else
items = sscanf(buf, "%llu.%llu %d %20s %4s %c %x %d %d %d %d %d %d %d %d", items = sscanf(buf, "%llu.%llu %d %s %2s %c %x %d %d %d %d %d %d %d %d",
&sec, &usec, &interface, &sec, &usec, &interface,
idstr, dir, &rtr, &dlc, tmp1, dir, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3], &data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]); &data[4], &data[5], &data[6], &data[7]);
@@ -220,9 +205,9 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
/* check for CAN ID with (hexa)decimal value */ /* check for CAN ID with (hexa)decimal value */
if (base == 'h') if (base == 'h')
get_can_id(&cf.can_id, idstr, 16); get_can_id(&cf, tmp1, 16);
else else
get_can_id(&cf.can_id, idstr, 10); get_can_id(&cf, tmp1, 10);
/* dlc > 8 => len == CAN_MAX_DLEN => fill len8_dlc value */ /* dlc > 8 => len == CAN_MAX_DLEN => fill len8_dlc value */
if (dlc > CAN_MAX_DLC) if (dlc > CAN_MAX_DLC)
@@ -231,9 +216,6 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
if (strlen(dir) != 2) /* "Rx" or "Tx" */ if (strlen(dir) != 2) /* "Rx" or "Tx" */
return; return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */ /* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100) if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return; return;
@@ -241,6 +223,11 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10) if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return; return;
if (dir[0] == 'R')
extra_info = " R\n";
else
extra_info = " T\n";
cf.len = len; cf.len = len;
if (rtr == 'r') if (rtr == 'r')
cf.can_id |= CAN_RTR_FLAG; cf.can_id |= CAN_RTR_FLAG;
@@ -249,13 +236,13 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
cf.data[i] = data[i] & 0xFFU; cf.data[i] = data[i] & 0xFFU;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]); prframe(outfile, &tv, interface, &cf, extra_info);
fflush(outfile); fflush(outfile);
} }
} }
static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile) int dplace, FILE *outfile)
{ {
int interface; int interface;
static struct timeval tv; /* current frame timestamp */ static struct timeval tv; /* current frame timestamp */
@@ -264,33 +251,29 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
unsigned char brs, esi, ctmp; unsigned char brs, esi, ctmp;
unsigned int flags; unsigned int flags;
int dlc, dlen = 0; int dlc, dlen = 0;
char idstr[21]; char tmp1[BUFLEN];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
char *extra_info;
char *ptr; char *ptr;
int i; int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec; unsigned long long sec, usec;
/* /* The CANFD format is mainly in hex representation but <DataLength>
* The CANFD format is mainly in hex representation but <DataLength> and probably some content we skip anyway. Don't trust the docs! */
* and probably some content we skip anyway. Don't trust the docs!
*/
/* /* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \
* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \ 100000 214 223040 80000000 46500250 460a0250 20011736 20010205 */
* 100000 214 223040 80000000 46500250 460a0250 20011736 20010205
*/
/* check for valid line without symbolic name */ /* check for valid line without symbolic name */
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %hhx %hhx %x %d %n", if (sscanf(buf, "%llu.%llu %*s %d %2s %s %hhx %hhx %x %d ",
&sec, &usec, &interface, &sec, &usec, &interface,
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) { dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
/* check for valid line with a symbolic name */ /* check for valid line with a symbolic name */
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %*s %hhx %hhx %x %d %n", if (sscanf(buf, "%llu.%llu %*s %d %2s %s %*s %hhx %hhx %x %d ",
&sec, &usec, &interface, &sec, &usec, &interface,
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) { dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
/* no valid CANFD format pattern */ /* no valid CANFD format pattern */
return; return;
@@ -307,9 +290,6 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
if (strlen(dir) != 2) /* "Rx" or "Tx" */ if (strlen(dir) != 2) /* "Rx" or "Tx" */
return; return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */ /* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100) if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return; return;
@@ -318,13 +298,26 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10) if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return; return;
if (dir[0] == 'R')
extra_info = " R\n";
else
extra_info = " T\n";
/* don't trust ASCII content - sanitize data length */ /* don't trust ASCII content - sanitize data length */
if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen))) if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen)))
return; return;
get_can_id(&cf.can_id, idstr, 16); get_can_id(&cf, tmp1, 16);
ptr = buf + n; /* start of ASCII hex frame data */ /* now search for the beginning of the data[] content */
sprintf(tmp1, " %x %x %x %2d ", brs, esi, dlc, dlen);
/* search for the pattern generated by real data */
ptr = strcasestr(buf, tmp1);
if (ptr == NULL)
return;
ptr += strlen(tmp1); /* start of ASCII hex frame data */
cf.len = dlen; cf.len = dlen;
@@ -348,6 +341,12 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
if (sscanf(ptr, " %*x %*x %x ", &flags) != 1) if (sscanf(ptr, " %*x %*x %x ", &flags) != 1)
return; return;
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
if (flags & ASC_F_FDF) { if (flags & ASC_F_FDF) {
cf.flags = CANFD_FDF; cf.flags = CANFD_FDF;
if (flags & ASC_F_BRS) if (flags & ASC_F_BRS)
@@ -374,414 +373,18 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
} }
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]); prframe(outfile, &tv, interface, &cf, extra_info);
fflush(outfile); fflush(outfile);
/* No support for really strange CANFD ErrorFrames format m( */ /* No support for really strange CANFD ErrorFrames format m( */
} }
static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct can_frame cf = { 0 };
unsigned char ctmp;
unsigned int flags;
int dlc, dlen = 0;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/*
* 59.171614 CANXL 2 Rx CBFF 243215 176 432 msgCanCCTest1 \
* f 8 e1 89 e8 c2 b9 6d 5a f1 174 00000000 00000000 \
* 000000050005000e 0000000000a00010 0000000a000a001d \
* 0000000000a00002 000000100010000f 000000000a00001
*/
/* check for valid line without symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%x %d %n", /* DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* check for valid line with a symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %x %d %n", /* sym name, DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* no valid CAN CC format pattern */
return;
}
}
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
/* check for allowed (unsigned) value ranges */
if ((dlen > CAN_MAX_DLEN) || (dlc > CAN_MAX_RAW_DLC))
return;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
/* check for signed integer overflow */
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
get_can_id(&cf.can_id, idstr, 16);
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip FCRC to get Flags value */
if (sscanf(ptr, "%*x %x ", &flags) != 1)
return;
if (flags & ASC_F_RTR) {
cf.can_id |= CAN_RTR_FLAG;
/* dlen is always 0 for classic CAN RTR frames
but the DLC value is valid in RTR cases */
cf.len = dlc;
/* sanitize payload length value */
if (dlc > CAN_MAX_DLEN)
cf.len = CAN_MAX_DLEN;
}
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((cf.len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC))
cf.len8_dlc = dlc;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
fflush(outfile);
}
static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct canfd_frame cf = { 0 };
unsigned char ctmp;
unsigned int flags;
int dlc, dlen = 0;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/*
* 59.171614 CANXL 2 Rx FBFF 243215 176 432 msgCanFDTest2 \
* 9 12 e1 89 e8 c2 b9 6d 5a f1 11 22 33 44 a 12345 00001240 00000000 \
* 000000050005000e 0000000000a00010 0000000a000a001d \
* 0000000000a00002 000000100010000f 000000000a00001
*/
/* check for valid line without symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%x %d %n", /* DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* check for valid line with a symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %x %d %n", /* sym name, DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* no valid CAN CC format pattern */
return;
}
}
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
/* check for allowed (unsigned) value ranges */
if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC))
return;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
/* check for signed integer overflow */
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
get_can_id(&cf.can_id, idstr, 16);
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip stuff field and FCRC to get Flags value */
if (sscanf(ptr, "%*s %*s %x ", &flags) != 1)
return;
if (!(flags & ASC_F_FDF))
return;
cf.flags = CANFD_FDF;
if (flags & ASC_F_BRS)
cf.flags |= CANFD_BRS;
if (flags & ASC_F_ESI)
cf.flags |= CANFD_ESI;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
fflush(outfile);
}
static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct canxl_frame cf = { 0 };
unsigned char sdt, vcid, secbit, ctmp;
unsigned int af, flags;
int dlc, dlen = 0;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/*
* 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \
* e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \
* ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \
* 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \
* 000000000a00001
*/
/* check for valid line without symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%hhx %hhx %x %d " /* SDT, SEC, DLC, Datalen */
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
&sec, &usec, &interface, dir,
idstr,
&sdt, &secbit, &dlc, &dlen,
&vcid, &af, &n) != 11) {
/* check for valid line with a symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %hhx %hhx %x %d " /* sym name, SDT, SEC, DLC, Datalen */
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
&sec, &usec, &interface, dir,
idstr,
&sdt, &secbit, &dlc, &dlen,
&vcid, &af, &n) != 11) {
/* no valid CANXL format pattern */
return;
}
}
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
/* check for allowed (unsigned) value ranges */
if ((dlen > CANXL_MAX_DLEN) || (dlc > CANXL_MAX_DLC) || (secbit > 1))
return;
cf.sdt = sdt;
cf.af = af;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
/* check for signed integer overflow */
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
/* don't trust ASCII content - sanitize data length */
if (dlen != dlc + 1)
return;
get_can_id(&cf.prio, idstr, 16);
if ((cf.prio & CANXL_PRIO_MASK) != cf.prio)
return;
if (vcid)
cf.prio |= (vcid << CANXL_VCID_OFFSET);
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip FCRC to get Flags value */
if (sscanf(ptr, "%*x %x ", &flags) != 1)
return;
/* mandatory for CAN XL frames */
if (!(flags & ASC_F_XLF))
return;
/* mark as CAN XL */
cf.flags = CANXL_XLF;
if (flags & ASC_F_SEC)
cf.flags |= CANXL_SEC;
if (flags & ASC_F_RES)
cf.flags |= CANXL_RRS;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (union cfu *)&cf, dir[0]);
fflush(outfile);
/* No support for CAN XL ErrorFrames */
}
static void eval_canxl(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char frfo[5]; /* frame format 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' plus terminating zero */
unsigned long long sec, usec;
/*
* The CANXL format is mainly in hex representation but <DataLength>
* and probably some content we skip anyway. Check out the new spec:
* CAN, Log & Trigger ASC Logging Format Spec V 1.4.17 of 2024-05-21
*/
/*
* This is a CAN XL ("XLFF") example for the CANXL Message Event:
*
* 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \
* e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \
* ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \
* 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \
* 000000000a00001
*/
/* check for valid line until frame format tag */
if (sscanf(buf, "%llu.%llu %*s %d %4s %4s ",
&sec, &usec, &interface, dir, frfo) != 5)
return; /* no valid CANXL format pattern */
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (strlen(frfo) != 4) /* 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' */
return;
if (!strncmp(frfo, "XLFF", 4))
eval_canxl_xl(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "FBFF", 4))
eval_canxl_fd(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "FEFF", 4))
eval_canxl_fd(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "CBFF", 4))
eval_canxl_cc(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "CEFF", 4))
eval_canxl_cc(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
}
static int get_date(struct timeval *tv, char *date) static int get_date(struct timeval *tv, char *date)
{ {
struct tm tms; struct tm tms;
unsigned int msecs = 0; unsigned int msecs = 0;
if ((strcasestr(date, " am ") != NULL) || (strcasestr(date, " pm ") != NULL)) { if (strcasestr(date, " pm ") != NULL) {
/* assume EN/US date due to existing am/pm field */ /* assume EN/US date due to existing am/pm field */
if (!setlocale(LC_TIME, "en_US")) { if (!setlocale(LC_TIME, "en_US")) {
@@ -790,11 +393,9 @@ static int get_date(struct timeval *tv, char *date)
} }
if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) { if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) {
/* /* The string might contain a milliseconds value which strptime()
* The string might contain a milliseconds value which strptime() does not support. So we read the ms value into the year variable
* does not support. So we read the ms value into the year variable before parsing the real year value (hack) */
* before parsing the real year value (hack)
*/
if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms)) if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms))
return 1; return 1;
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs); sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
@@ -809,11 +410,9 @@ static int get_date(struct timeval *tv, char *date)
} }
if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) { if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) {
/* /* The string might contain a milliseconds value which strptime()
* The string might contain a milliseconds value which strptime() does not support. So we read the ms value into the year variable
* does not support. So we read the ms value into the year variable before parsing the real year value (hack) */
* before parsing the real year value (hack)
*/
if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms)) if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms))
return 1; return 1;
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs); sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
@@ -835,11 +434,11 @@ static int get_date(struct timeval *tv, char *date)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char buf[BUFLEN], tmp1[10], tmp2[10]; char buf[BUFLEN], tmp1[BUFLEN], tmp2[BUFLEN];
FILE *infile = stdin; FILE *infile = stdin;
FILE *outfile = stdout; FILE *outfile = stdout;
static int verbose, disable_dir; static int verbose;
static struct timeval date_tv; /* date of the ASC file */ static struct timeval date_tv; /* date of the ASC file */
static int dplace; /* decimal place 4, 5 or 6 or uninitialized */ static int dplace; /* decimal place 4, 5 or 6 or uninitialized */
static char base; /* 'd'ec or 'h'ex */ static char base; /* 'd'ec or 'h'ex */
@@ -847,7 +446,7 @@ int main(int argc, char **argv)
int opt; int opt;
unsigned long long sec, usec; unsigned long long sec, usec;
while ((opt = getopt(argc, argv, "I:O:dv?")) != -1) { while ((opt = getopt(argc, argv, "I:O:v?")) != -1) {
switch (opt) { switch (opt) {
case 'I': case 'I':
infile = fopen(optarg, "r"); infile = fopen(optarg, "r");
@@ -865,10 +464,6 @@ int main(int argc, char **argv)
} }
break; break;
case 'd':
disable_dir = 1;
break;
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
@@ -893,7 +488,7 @@ int main(int argc, char **argv)
/* check for base and timestamp entries in the header */ /* check for base and timestamp entries in the header */
if ((!base) && if ((!base) &&
(sscanf(buf, "base %9s timestamps %9s", tmp1, tmp2) == 2)) { (sscanf(buf, "base %s timestamps %s", tmp1, tmp2) == 2)) {
base = tmp1[0]; base = tmp1[0];
timestamps = tmp2[0]; timestamps = tmp2[0];
if (verbose) if (verbose)
@@ -927,7 +522,7 @@ int main(int argc, char **argv)
} }
/* check for decimal places length in valid CAN frames */ /* check for decimal places length in valid CAN frames */
if (sscanf(buf, "%llu.%9s %9s ", &sec, tmp2, if (sscanf(buf, "%llu.%s %s ", &sec, tmp2,
tmp1) != 3) tmp1) != 3)
continue; /* dplace remains zero until first found CAN frame */ continue; /* dplace remains zero until first found CAN frame */
@@ -942,19 +537,15 @@ int main(int argc, char **argv)
} }
} }
/* /* the representation of a valid CAN frame is known here */
* The representation of a valid CAN frame is known here. /* so try to get CAN frames and ErrorFrames and convert them */
* So try to get CAN frames and ErrorFrames and convert them.
*/
/* check classic CAN format or the CANFD/CANXL tag which can take different types */ /* check classic CAN format or the CANFD tag which can take both types */
if (sscanf(buf, "%llu.%llu %9s ", &sec, &usec, tmp1) == 3) { if (sscanf(buf, "%llu.%llu %s ", &sec, &usec, tmp1) == 3){
if (!strncmp(tmp1, "CANXL", 5)) if (!strncmp(tmp1, "CANFD", 5))
eval_canxl(buf, &date_tv, timestamps, dplace, disable_dir, outfile); eval_canfd(buf, &date_tv, timestamps, dplace, outfile);
else if (!strncmp(tmp1, "CANFD", 5))
eval_canfd(buf, &date_tv, timestamps, dplace, disable_dir, outfile);
else else
eval_can(buf, &date_tv, timestamps, base, dplace, disable_dir, outfile); eval_can(buf, &date_tv, timestamps, base, dplace, outfile);
} }
} }
fclose(outfile); fclose(outfile);
+9 -29
View File
@@ -153,7 +153,7 @@ int main(void)
char buf[MAXLEN]; char buf[MAXLEN];
char format[FORMATSZ]; char format[FORMATSZ];
char rxmsg[64]; char rxmsg[50];
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wpragmas"
@@ -234,7 +234,7 @@ int main(void)
} }
while (1) { while (1) {
again:
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(sc, &readfds); FD_SET(sc, &readfds);
FD_SET(sa, &readfds); FD_SET(sa, &readfds);
@@ -242,8 +242,6 @@ again:
select((sc > sa)?sc+1:sa+1, &readfds, NULL, NULL, NULL); select((sc > sa)?sc+1:sa+1, &readfds, NULL, NULL, NULL);
if (FD_ISSET(sc, &readfds)) { if (FD_ISSET(sc, &readfds)) {
size_t size = sizeof(rxmsg);
int len = 0, res;
recvfrom(sc, &msg, sizeof(msg), 0, recvfrom(sc, &msg, sizeof(msg), 0,
(struct sockaddr*)&caddr, &caddrlen); (struct sockaddr*)&caddr, &caddrlen);
@@ -251,35 +249,17 @@ again:
ifr.ifr_ifindex = caddr.can_ifindex; ifr.ifr_ifindex = caddr.can_ifindex;
ioctl(sc, SIOCGIFNAME, &ifr); ioctl(sc, SIOCGIFNAME, &ifr);
res = snprintf(rxmsg, size, "< %s %03X %d ", ifr.ifr_name, sprintf(rxmsg, "< %s %03X %d ", ifr.ifr_name,
msg.msg_head.can_id, msg.frame.can_dlc); msg.msg_head.can_id, msg.frame.can_dlc);
if (res < 0 || (size_t)res >= size) {
printf("Error: rxmsg buffer (size %zu) too small for data.\n", size);
continue;
}
len += res; for ( i = 0; i < msg.frame.can_dlc; i++)
sprintf(rxmsg + strlen(rxmsg), "%02X ",
for (i = 0; i < msg.frame.can_dlc; i++) { msg.frame.data[i]);
res = snprintf(rxmsg + len, size - len, "%02X ", msg.frame.data[i]);
if (res < 0 || (size_t)res >= (size - len)) {
printf("Error: rxmsg buffer (size %zu) too small for data.\n", size);
goto again;
}
len += res;
}
/* delimiter '\0' for Adobe(TM) Flash(TM) XML sockets */ /* delimiter '\0' for Adobe(TM) Flash(TM) XML sockets */
res = snprintf(rxmsg + len, size - len, ">"); strcat(rxmsg, ">\0");
if (res < 0 || (size_t)res >= (size - len)) {
printf("Error: rxmsg buffer (size %zu) too small for data.\n", size);
continue;
}
len += res; send(sa, rxmsg, strlen(rxmsg) + 1, 0);
send(sa, rxmsg, len + 1, 0);
} }
-5
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
}; };
+180 -180
View File
@@ -1,180 +1,180 @@
# can-j1939 kernel module installation # # can-j1939 kernel module installation #
### Problem ### Problem
You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this: You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this:
```bash ```bash
avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939 avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939
modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64 modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64
``` ```
and also this: and also this:
```bash ```bash
avra@vm-debian:~/can/can-utils$ testj1939 avra@vm-debian:~/can/can-utils$ testj1939
testj1939: socket(j1939): Protocol not supported testj1939: socket(j1939): Protocol not supported
``` ```
### Solution ### Solution
Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine. Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine.
#### 1. Download kernel source #### #### 1. Download kernel source ####
We will download Debian patched kernel 5.8. First update your sources We will download Debian patched kernel 5.8. First update your sources
``` ```
avra@vm-debian:~$ sudo apt update avra@vm-debian:~$ sudo apt update
``` ```
and then look at available Debian patched kernel source packages and then look at available Debian patched kernel source packages
``` ```
avra@vm-debian:~$ apt-cache search linux-source avra@vm-debian:~$ apt-cache search linux-source
linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches
linux-source - Linux kernel source (meta-package) linux-source - Linux kernel source (meta-package)
linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches
linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches
linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches
linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches
linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches
``` ```
If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this
``` ```
echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list
``` ```
Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours) Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours)
``` ```
deb http://security.debian.org/debian-security buster/updates main contrib deb http://security.debian.org/debian-security buster/updates main contrib
deb-src http://security.debian.org/debian-security buster/updates main contrib deb-src http://security.debian.org/debian-security buster/updates main contrib
deb http://deb.debian.org/debian/ buster main contrib non-free deb http://deb.debian.org/debian/ buster main contrib non-free
deb-src http://deb.debian.org/debian/ buster main contrib non-free deb-src http://deb.debian.org/debian/ buster main contrib non-free
deb http://deb.debian.org/debian buster-backports main contrib deb http://deb.debian.org/debian buster-backports main contrib
``` ```
After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package
``` ```
sudo apt install linux-source-5.8 sudo apt install linux-source-5.8
``` ```
and unpack it and unpack it
``` ```
avra@vm-debian:~$ cd /usr/src avra@vm-debian:~$ cd /usr/src
avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz
avra@vm-debian:/usr/src$ cd linux-source-5.8 avra@vm-debian:/usr/src$ cd linux-source-5.8
``` ```
#### 2. Add can-j1939 module to kernel #### #### 2. Add can-j1939 module to kernel ####
First we need some packages for **menuconfig** First we need some packages for **menuconfig**
``` ```
sudo apt-get install libncurses5 libncurses5-dev sudo apt-get install libncurses5 libncurses5-dev
``` ```
copy and use our old configuration to run **menuconfig** copy and use our old configuration to run **menuconfig**
``` ```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig
``` ```
where we enable SAE J1939 kernel module as shown where we enable SAE J1939 kernel module as shown
``` ```
- Networking Support - Networking Support
- Can bus subsystem support - Can bus subsystem support
- <M> SAE J1939 - <M> SAE J1939
``` ```
Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following
``` ```
CONFIG_SYSTEM_TRUSTED_KEYS="" CONFIG_SYSTEM_TRUSTED_KEYS=""
``` ```
and save the file. and save the file.
#### 3. Compile and install kernel and modules #### 3. Compile and install kernel and modules
We will have to download necessary packages We will have to download necessary packages
``` ```
sudo apt install build-essential libssl-dev libelf-dev bison flex sudo apt install build-essential libssl-dev libelf-dev bison flex
``` ```
compile kernel (using threads to make it faster) compile kernel (using threads to make it faster)
``` ```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc) avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc)
``` ```
install install
``` ```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install
``` ```
and update grub and update grub
``` ```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub
avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot
``` ```
Check if installation is correct with Check if installation is correct with
``` ```
sudo modprobe can-j1939 sudo modprobe can-j1939
``` ```
and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works: and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works:
``` ```
sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko
``` ```
If it does then all you need to do is If it does then all you need to do is
``` ```
sudo depmod -av sudo depmod -av
``` ```
reboot once, and **modprobe** command from the above should finally work. reboot once, and **modprobe** command from the above should finally work.
#### 4. Install headers if needed #### 4. Install headers if needed
You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with
``` ```
nano /usr/include/linux/can.h nano /usr/include/linux/can.h
``` ```
If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually
``` ```
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/ sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/
``` ```
That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy! That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy!
+81 -306
View File
@@ -45,17 +45,14 @@
#include <ctype.h> #include <ctype.h>
#include <libgen.h> #include <libgen.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <net/if.h> #include <net/if.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
@@ -68,69 +65,34 @@
#include "terminal.h" #include "terminal.h"
#include "canframelen.h" #include "canframelen.h"
#define ANYDEV "any" /* name of interface to receive from any CAN interface */ #define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
#define MAXDEVS 20 /* max. number of CAN interfaces given on the cmdline */
#define PERCENTRES 5 /* resolution in percent for bargraph */ #define PERCENTRES 5 /* resolution in percent for bargraph */
#define NUMBAR (100 / PERCENTRES) /* number of bargraph elements */ #define NUMBAR (100 / PERCENTRES) /* number of bargraph elements */
#define BRSTRLEN 20
#define VISUAL_WINDOW 90 /* window width for visualization */
/*
* Inspired from
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/
* include/linux/sched/loadavg.h
*
* Following are the fixed-point math constants and the exponential-damping
* factors for:
* - 1 samples/s in 1 minute
* - 1 samples/s in 5 minutes
* - 1 samples/s in 15 minutes
* in fixed-point representation.
*/
#define FP_SHIFT 12 /* bits of precision */
#define FP_ONE (1 << FP_SHIFT) /* 1.0 fixed-point representation */
#define EXP_1 4028 /* (1 / e ^ (1 / 60)) * FP_ONE */
#define EXP_5 4082 /* (1 / e ^ (1 / 300)) * FP_ONE */
#define EXP_15 4091 /* (1 / e ^ (1 / 900)) * FP_ONE */
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
static struct { static struct {
char devname[IFNAMSIZ + 1]; char devname[IFNAMSIZ + 1];
char bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */
char recv_direction;
int ifindex;
unsigned int bitrate; unsigned int bitrate;
unsigned int dbitrate; unsigned int dbitrate;
unsigned int recv_frames; unsigned int recv_frames;
unsigned int recv_bits_total; unsigned int recv_bits_total;
unsigned int recv_bits_payload; unsigned int recv_bits_payload;
unsigned int recv_bits_dbitrate; unsigned int recv_bits_dbitrate;
unsigned int load_min; } stat[MAXSOCK + 1];
unsigned int load_max;
unsigned int load_1m;
unsigned int load_5m;
unsigned int load_15m;
unsigned int loads[VISUAL_WINDOW];
unsigned int index;
} stat[MAXDEVS + 1];
static volatile int running = 1; static volatile int running = 1;
static volatile sig_atomic_t signal_num; static volatile sig_atomic_t signal_num;
static int max_devname_len; /* to prevent frazzled device name output */ static int max_devname_len; /* to prevent frazzled device name output */
static int max_bitratestr_len; static int max_bitrate_len;
static unsigned int currmax; static int currmax;
static unsigned char redraw; static unsigned char redraw;
static unsigned char timestamp; static unsigned char timestamp;
static unsigned char color; static unsigned char color;
static unsigned char bargraph; static unsigned char bargraph;
static bool statistic;
static bool reset;
static bool visualize;
static enum cfl_mode mode = CFL_WORSTCASE; static enum cfl_mode mode = CFL_WORSTCASE;
static char *prg; static char *prg;
static struct termios old;
static void print_usage(char *prg) static void print_usage(char *prg)
{ {
@@ -144,23 +106,21 @@ static void print_usage(char *prg)
fprintf(stderr, " -r (redraw the terminal - similar to top)\n"); fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n"); fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
fprintf(stderr, " -e (exact calculation of stuffed bits)\n"); fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
fprintf(stderr, " -s (show statistics, press 'r' to reset)\n");
fprintf(stderr, " -v (show busload visualization)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXDEVS); fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXSOCK);
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>[,<dbitrate>]\n"); fprintf(stderr, "commandline in the form: <ifname>@<bitrate>[,<dbitrate>]\n\n");
fprintf(stderr, "The interface name 'any' enables an auto detection with the given bitrate[s]\n\n");
fprintf(stderr, "The bitrate is mandatory as it is needed to know the CAN bus bitrate to\n"); fprintf(stderr, "The bitrate is mandatory as it is needed to know the CAN bus bitrate to\n");
fprintf(stderr, "calculate the bus load percentage based on the received CAN frames.\n"); fprintf(stderr, "calculate the bus load percentage based on the received CAN frames.\n");
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n"); fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
fprintf(stderr, "For each given interface the data is presented in one line which contains:\n\n"); fprintf(stderr, "For each given interface the data is presented in one line which contains:\n\n");
fprintf(stderr, "(interface) (received CAN frames) (bits total) (bits payload) (bits payload brs)\n"); fprintf(stderr, "(interface) (received CAN frames) (used bits total) (used bits for payload)\n");
fprintf(stderr, "\nExamples:\n"); fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000,2000000 can2@500000 -r -t -b -c\n\n"); fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000 can2@500000 can3@500000 -r -t -b -c\n\n");
fprintf(stderr, "%s 2024-08-08 16:30:05 (worst case bitstuffing)\n", prg); fprintf(stderr, "%s 2014-02-01 21:13:16 (worst case bitstuffing)\n", prg);
fprintf(stderr, " can0@100k 192 21980 9136 0 21%% |TTTT................|\n"); fprintf(stderr, " can0@100000 805 74491 36656 74%% |XXXXXXXXXXXXXX......|\n");
fprintf(stderr, " can1@500k/2M 2651 475500 234448 131825 74%% |XXXXXXXXXXXXXX......|\n"); fprintf(stderr, " can1@500000 796 75140 37728 15%% |XXX.................|\n");
fprintf(stderr, " can2@500k 855 136777 62968 35219 27%% |RRRRR...............|\n"); fprintf(stderr, " can2@500000 0 0 0 0%% |....................|\n");
fprintf(stderr, " can3@500000 47 4633 2424 0%% |....................|\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
@@ -170,45 +130,9 @@ static void sigterm(int signo)
signal_num = signo; signal_num = signo;
} }
static int add_bitrate(char *brstr, unsigned int bitrate)
{
if (bitrate % 1000000 == 0)
return sprintf(brstr, "%dM", bitrate / 1000000);
if (bitrate % 1000 == 0)
return sprintf(brstr, "%dk", bitrate / 1000);
return sprintf(brstr, "%d", bitrate);
}
static void create_bitrate_string(int stat_idx, int *max_bitratestr_len)
{
int ptr;
ptr = add_bitrate(&stat[stat_idx].bitratestr[0], stat[stat_idx].bitrate);
if (stat[stat_idx].bitrate != stat[stat_idx].dbitrate) {
ptr += sprintf(&stat[stat_idx].bitratestr[ptr], "/");
ptr += add_bitrate(&stat[stat_idx].bitratestr[ptr], stat[stat_idx].dbitrate);
}
if (ptr > *max_bitratestr_len)
*max_bitratestr_len = ptr;
}
static unsigned int calc_load(unsigned int load_fp,
unsigned int exp_fp,
unsigned int sample)
{
unsigned int sample_fp = sample << FP_SHIFT;
unsigned int damped_sum = (load_fp * exp_fp) +
(sample_fp * (FP_ONE - exp_fp));
return damped_sum >> FP_SHIFT;
}
static void printstats(int signo) static void printstats(int signo)
{ {
unsigned int i, j, k, percent, index; int i, j, percent;
if (redraw) if (redraw)
printf("%s", CSR_HOME); printf("%s", CSR_HOME);
@@ -270,39 +194,15 @@ static void printstats(int signo)
else else
percent = 0; percent = 0;
printf(" %*s@%-*s %5d %7d %7d %7d %3d%%", printf(" %*s@%-*d %5d %7d %6d %6d %3d%%",
max_devname_len, stat[i].devname, max_devname_len, stat[i].devname,
max_bitratestr_len, stat[i].bitratestr, max_bitrate_len, stat[i].bitrate,
stat[i].recv_frames, stat[i].recv_frames,
stat[i].recv_bits_total, stat[i].recv_bits_total,
stat[i].recv_bits_payload, stat[i].recv_bits_payload,
stat[i].recv_bits_dbitrate, stat[i].recv_bits_dbitrate,
percent); percent);
if (statistic) {
if (reset) {
stat[i].load_min = UINT_MAX;
stat[i].load_max = 0;
stat[i].load_1m = 0;
stat[i].load_5m = 0;
stat[i].load_15m = 0;
}
stat[i].load_min = MIN(stat[i].load_min, percent);
stat[i].load_max = MAX(stat[i].load_max, percent);
stat[i].load_1m = calc_load(stat[i].load_1m, EXP_1, percent);
stat[i].load_5m = calc_load(stat[i].load_5m, EXP_5, percent);
stat[i].load_15m = calc_load(stat[i].load_15m, EXP_15, percent);
printf(" min:%3d%%, max:%3d%%, load:%3d%% %3d%% %3d%%",
stat[i].load_min,
stat[i].load_max,
(stat[i].load_1m + (FP_ONE >> 1)) >> FP_SHIFT,
(stat[i].load_5m + (FP_ONE >> 1)) >> FP_SHIFT,
(stat[i].load_15m + (FP_ONE >> 1)) >> FP_SHIFT);
}
if (bargraph) { if (bargraph) {
printf(" |"); printf(" |");
@@ -312,7 +212,7 @@ static void printstats(int signo)
for (j = 0; j < NUMBAR; j++) { for (j = 0; j < NUMBAR; j++) {
if (j < percent / PERCENTRES) if (j < percent / PERCENTRES)
printf("%c", stat[i].recv_direction); printf("X");
else else
printf("."); printf(".");
} }
@@ -320,28 +220,6 @@ static void printstats(int signo)
printf("|"); printf("|");
} }
if (visualize) {
stat[i].loads[stat[i].index] = percent;
stat[i].index = (stat[i].index + 1) % VISUAL_WINDOW;
printf("\n");
for (j = 0; j < NUMBAR; j++) {
printf("%3d%%|", (NUMBAR - j) * PERCENTRES);
index = stat[i].index;
for (k = 0; k < VISUAL_WINDOW; k++) {
percent = stat[i].loads[index];
if ((percent / PERCENTRES) >= (NUMBAR - j))
printf("X");
else
printf(".");
index = (index + 1) % VISUAL_WINDOW;
}
printf("\n");
}
}
if (color) if (color)
printf("%s", ATTRESET); printf("%s", ATTRESET);
@@ -352,11 +230,8 @@ static void printstats(int signo)
stat[i].recv_bits_total = 0; stat[i].recv_bits_total = 0;
stat[i].recv_bits_dbitrate = 0; stat[i].recv_bits_dbitrate = 0;
stat[i].recv_bits_payload = 0; stat[i].recv_bits_payload = 0;
stat[i].recv_direction = '.';
} }
reset = false;
if (!redraw) if (!redraw)
printf("\n"); printf("\n");
@@ -365,35 +240,17 @@ static void printstats(int signo)
alarm(1); alarm(1);
} }
void cleanup()
{
tcsetattr(STDIN_FILENO, TCSANOW, &old);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
fd_set rdfs; fd_set rdfs;
int s; int s[MAXSOCK];
int opt; int opt;
char *ptr, *nptr; char *ptr, *nptr;
struct sockaddr_can addr; struct sockaddr_can addr;
struct canfd_frame frame; struct canfd_frame frame;
struct iovec iov; int nbytes, i;
struct msghdr msg; struct ifreq ifr;
unsigned int i;
int nbytes;
int have_anydev = 0;
unsigned int anydev_bitrate = 0;
unsigned int anydev_dbitrate = 0;
char anydev_bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */
struct termios temp;
tcgetattr(STDIN_FILENO, &old);
atexit(cleanup);
temp = old;
temp.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &temp);
signal(SIGTERM, sigterm); signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm); signal(SIGHUP, sigterm);
@@ -403,7 +260,7 @@ int main(int argc, char **argv)
prg = basename(argv[0]); prg = basename(argv[0]);
while ((opt = getopt(argc, argv, "rtbciesvh?")) != -1) { while ((opt = getopt(argc, argv, "rtbcieh?")) != -1) {
switch (opt) { switch (opt) {
case 'r': case 'r':
redraw = 1; redraw = 1;
@@ -429,15 +286,6 @@ int main(int argc, char **argv)
mode = CFL_EXACT; mode = CFL_EXACT;
break; break;
case 's':
statistic = true;
reset = true;
break;
case 'v':
visualize = true;
break;
default: default:
print_usage(prg); print_usage(prg);
exit(1); exit(1);
@@ -452,22 +300,27 @@ int main(int argc, char **argv)
currmax = argc - optind; /* find real number of CAN devices */ currmax = argc - optind; /* find real number of CAN devices */
if (currmax > MAXDEVS) { if (currmax > MAXSOCK) {
printf("More than %d CAN devices given on commandline!\n", MAXDEVS); printf("More than %d CAN devices given on commandline!\n", MAXSOCK);
return 1; return 1;
} }
/* prefill stat[] array with given interface assignments */
for (i = 0; i < currmax; i++) { for (i = 0; i < currmax; i++) {
ptr = argv[optind + i + have_anydev]; ptr = argv[optind + i];
nbytes = strlen(ptr); nbytes = strlen(ptr);
if (nbytes >= (int)(IFNAMSIZ + sizeof("@1000000,2000000") + 1)) { if (nbytes >= (int)(IFNAMSIZ + sizeof("@1000000") + 1)) {
printf("name of CAN device '%s' is too long!\n", ptr); printf("name of CAN device '%s' is too long!\n", ptr);
return 1; return 1;
} }
pr_debug("handle %d '%s'.\n", i, ptr); pr_debug("open %d '%s'.\n", i, ptr);
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s[i] < 0) {
perror("socket");
return 1;
}
nptr = strchr(ptr, '@'); nptr = strchr(ptr, '@');
@@ -477,76 +330,55 @@ int main(int argc, char **argv)
return 1; return 1;
} }
/* interface name length */
nbytes = nptr - ptr; /* interface name is up the first '@' */ nbytes = nptr - ptr; /* interface name is up the first '@' */
if (nbytes >= (int)IFNAMSIZ) { if (nbytes >= (int)IFNAMSIZ) {
printf("name of CAN device '%s' is too long!\n", ptr); printf("name of CAN device '%s' is too long!\n", ptr);
return 1; return 1;
} }
/* copy interface name to stat[] entry */
strncpy(stat[i].devname, ptr, nbytes); strncpy(stat[i].devname, ptr, nbytes);
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, ptr, nbytes);
if (nbytes > max_devname_len) if (nbytes > max_devname_len)
max_devname_len = nbytes; /* for nice printing */ max_devname_len = nbytes; /* for nice printing */
char *endp; char *endp;
/* bitrate is placed behind the '@' */ stat[i].bitrate = strtol(nptr + 1, &endp, 0); /* bitrate is placed behind the '@' */
stat[i].bitrate = strtol(nptr + 1, &endp, 0);
/* check for CAN FD additional data bitrate */
if (*endp == ',') if (*endp == ',')
/* data bitrate is placed behind the ',' */ /* data bitrate is placed behind the ',' */
stat[i].dbitrate = strtol(endp + 1, &endp, 0); stat[i].dbitrate = strtol(endp + 1, &endp, 0);
else else
stat[i].dbitrate = stat[i].bitrate; stat[i].dbitrate = stat[i].bitrate;
if (!stat[i].bitrate || stat[i].bitrate > 1000000 || if (!stat[i].bitrate || stat[i].bitrate > 1000000) {
!stat[i].dbitrate || stat[i].dbitrate > 8000000) {
printf("invalid bitrate for CAN device '%s'!\n", ptr); printf("invalid bitrate for CAN device '%s'!\n", ptr);
return 1; return 1;
} }
/* prepare bitrate string for hot path */ nbytes = strlen(nptr + 1);
create_bitrate_string(i, &max_bitratestr_len); if (nbytes > max_bitrate_len)
max_bitrate_len = nbytes; /* for nice printing */
stat[i].recv_direction = '.'; pr_debug("using interface name '%s'.\n", ifr.ifr_name);
/* handling for 'any' device */ /* try to switch the socket into CAN FD mode */
if (have_anydev == 0 && strcmp(ANYDEV, stat[i].devname) == 0) { const int canfd_on = 1;
anydev_bitrate = stat[i].bitrate; setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
anydev_dbitrate = stat[i].dbitrate;
memcpy(anydev_bitratestr, stat[i].bitratestr, BRSTRLEN); if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
/* no real interface: remove this command line entry */ perror("SIOCGIFINDEX");
have_anydev = 1; exit(1);
currmax--;
i--;
} else {
stat[i].ifindex = if_nametoindex(stat[i].devname);
if (!stat[i].ifindex) {
printf("invalid CAN device '%s'!\n", stat[i].devname);
return 1;
}
pr_debug("using interface name '%s'.\n", stat[i].devname);
} }
}
s = socket(PF_CAN, SOCK_RAW, CAN_RAW); addr.can_family = AF_CAN;
if (s < 0) { addr.can_ifindex = ifr.ifr_ifindex;
perror("socket");
return 1;
}
/* try to switch the socket into CAN FD mode */ if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
const int canfd_on = 1; perror("bind");
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); return 1;
}
addr.can_family = AF_CAN;
addr.can_ifindex = 0; /* any CAN device */
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
} }
alarm(1); alarm(1);
@@ -554,100 +386,43 @@ int main(int argc, char **argv)
if (redraw) if (redraw)
printf("%s", CLR_SCREEN); printf("%s", CLR_SCREEN);
/* these settings are static and can be held out of the hot path */
iov.iov_base = &frame;
msg.msg_name = &addr;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
while (running) { while (running) {
FD_ZERO(&rdfs); FD_ZERO(&rdfs);
FD_SET(s, &rdfs); for (i = 0; i < currmax; i++)
FD_SET(STDIN_FILENO, &rdfs); FD_SET(s[i], &rdfs);
if (select(s + 1, &rdfs, NULL, NULL, NULL) < 0) { if (select(s[currmax - 1] + 1, &rdfs, NULL, NULL, NULL) < 0) {
//perror("pselect"); //perror("pselect");
continue; continue;
} }
if (FD_ISSET(STDIN_FILENO, &rdfs)) { for (i = 0; i < currmax; i++) { /* check all CAN RAW sockets */
if (getchar() == 'r') {
reset = true; if (FD_ISSET(s[i], &rdfs)) {
nbytes = read(s[i], &frame, sizeof(frame));
if (nbytes < 0) {
perror("read");
return 1;
}
if (nbytes < (int)sizeof(struct can_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
stat[i].recv_frames++;
stat[i].recv_bits_payload += frame.len * 8;
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
&frame, mode, sizeof(frame));
stat[i].recv_bits_total += can_frame_length(&frame,
mode, nbytes);
} }
} }
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = 0;
msg.msg_flags = 0;
nbytes = recvmsg(s, &msg, 0);
if (nbytes < 0) {
perror("read");
return 1;
}
if (nbytes != (int)sizeof(struct can_frame) &&
nbytes != (int)sizeof(struct canfd_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
/* find received ifindex in stat[] array */
for (i = 0; i < currmax; i++) {
if (stat[i].ifindex == addr.can_ifindex)
break;
}
/* not found? check for unknown interface */
if (i >= currmax) {
/* drop unwanted traffic */
if (have_anydev == 0)
continue;
/* can we add another interface? */
if (currmax >= MAXDEVS)
continue;
/* add an new entry */
stat[i].ifindex = addr.can_ifindex;
stat[i].bitrate = anydev_bitrate;
stat[i].dbitrate = anydev_dbitrate;
memcpy(stat[i].bitratestr, anydev_bitratestr, BRSTRLEN);
stat[i].recv_direction = '.';
if_indextoname(addr.can_ifindex, stat[i].devname);
nbytes = strlen(stat[i].devname);
if (nbytes > max_devname_len)
max_devname_len = nbytes; /* for nice printing */
currmax++;
}
if (msg.msg_flags & MSG_DONTROUTE) {
/* TX direction */
if (stat[i].recv_direction == '.')
stat[i].recv_direction = 'T';
else if (stat[i].recv_direction == 'R')
stat[i].recv_direction = 'X';
} else {
/* RX direction */
if (stat[i].recv_direction == '.')
stat[i].recv_direction = 'R';
else if (stat[i].recv_direction == 'T')
stat[i].recv_direction = 'X';
}
stat[i].recv_frames++;
stat[i].recv_bits_payload += frame.len * 8;
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
&frame, mode, sizeof(frame));
stat[i].recv_bits_total += can_frame_length(&frame,
mode, nbytes);
} }
close(s); for (i = 0; i < currmax; i++)
close(s[i]);
if (signal_num) if (signal_num)
return 128 + signal_num; return 128 + signal_num;
+48 -81
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;
@@ -342,10 +319,10 @@ int main(int argc, char **argv)
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
struct can_filter *rfilter; struct can_filter *rfilter;
can_err_mask_t err_mask; can_err_mask_t err_mask;
static union cfu 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 : "");
+29 -26
View File
@@ -21,19 +21,20 @@
// // // //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
#include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdint.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/error.h>
#define can_interface_name argv[1]
#define STR_EQUAL 0 #define STR_EQUAL 0
void show_help_and_exit() void show_help_and_exit()
@@ -123,25 +124,27 @@ void show_help_and_exit()
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
void __attribute__((format (printf, 1, 2))) err_exit(const char *format, ...) void err_exit(const char *msg)
{ {
va_list ap; printf("%s", msg);
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
exit(EXIT_FAILURE); 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) void show_invalid_option(const char *option)
{ {
err_exit("Error: Invalid option %s\n", option); show_custom_format_and_exit(option, "Error: Invalid option %s\n");
} }
void show_err_and_exit(const char *err_type) void show_err_and_exit(const char *err_type)
{ {
err_exit("Error: You can only have one %s parameter!\n", err_type); show_custom_format_and_exit(err_type, "Error: You can only have one %s parameter!\n");
} }
void show_loc_err_and_exit() void show_loc_err_and_exit()
@@ -175,6 +178,7 @@ int main(int argc, char *argv[])
struct ifreq ifr; struct ifreq ifr;
struct can_frame frame; struct can_frame frame;
bool show_bits = false, location_processed = false, transceiver_processed = false, arbitration_processed = false; bool show_bits = false, location_processed = false, transceiver_processed = false, arbitration_processed = false;
char tmp_str[256];
printf("CAN Sockets Error Messages Simulator\n"); printf("CAN Sockets Error Messages Simulator\n");
if (argc < 3) if (argc < 3)
@@ -535,25 +539,24 @@ int main(int argc, char *argv[])
// create socket // create socket
if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
err_exit("Error while opening socket\n"); err_exit("Error while opening socket");
// set interface name // set interface name
if (strlen(argv[1]) >= IFNAMSIZ) strcpy(ifr.ifr_name, can_interface_name); // can0, vcan0...
err_exit("Name of CAN device '%s' is too long!\n\n", argv[1]); if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
sprintf(tmp_str, "Error setting CAN interface name %s", can_interface_name);
strcpy(ifr.ifr_name, argv[1]); // can0, vcan0... err_exit(tmp_str);
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) }
err_exit("Error setting CAN interface name %s\n", argv[1]);
// bind socket to the CAN interface // bind socket to the CAN interface
addr.can_family = AF_CAN; addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex; addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
err_exit("Error in socket bind\n"); err_exit("Error in socket bind");
// Send CAN error frame // Send CAN error frame
if (write(sock, &frame, sizeof(frame)) < 0) if (write(sock, &frame, sizeof(frame)) < 0)
err_exit("Error writing to socket\n"); err_exit("Error writing to socket");
else else
printf("CAN error frame sent\n"); printf("CAN error frame sent\n");
+1 -1
View File
@@ -157,7 +157,7 @@ static int compare_frame(const struct canfd_frame *exp, const struct canfd_frame
} else { } else {
for (i = 0; i < rec->len; i++) { for (i = 0; i < rec->len; i++) {
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) { if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
printf("Databyte 0x%x mismatch!\n", i); printf("Databyte %x mismatch!\n", i);
print_compare(expected_can_id, exp->data, exp->len, print_compare(expected_can_id, exp->data, exp->len,
rec->can_id, rec->data, rec->len, inc); rec->can_id, rec->data, rec->len, inc);
running = 0; running = 0;
+63 -139
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");
@@ -189,7 +189,6 @@ static void print_usage(char *prg)
fprintf(stderr, " -A <mode> (CAN XL AF generation mode - see below, no e/o mode)\n"); fprintf(stderr, " -A <mode> (CAN XL AF generation mode - see below, no e/o mode)\n");
fprintf(stderr, " -V <mode> (CAN XL VCID generation mode - see below, no e/o mode)\n"); fprintf(stderr, " -V <mode> (CAN XL VCID generation mode - see below, no e/o mode)\n");
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n"); fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
fprintf(stderr, " -P <priority> (set socket priority using SO_PRIORITY)\n");
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n"); fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n"); fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n"); fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n");
@@ -299,7 +298,7 @@ static int setsockopt_txtime(int fd)
return 0; return 0;
} }
static int do_send_one(int fd, union cfu *cu, size_t len, int timeout) static int do_send_one(int fd, cu_t *cu, size_t len, int timeout)
{ {
uint8_t control[CMSG_SPACE(sizeof(uint64_t))] = { 0 }; uint8_t control[CMSG_SPACE(sizeof(uint64_t))] = { 0 };
struct iovec iov = { struct iovec iov = {
@@ -339,9 +338,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 +454,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;
@@ -482,7 +479,6 @@ int main(int argc, char **argv)
uint64_t incdata = 0; uint64_t incdata = 0;
__u8 *data; /* base pointer for CC/FD or XL data */ __u8 *data; /* base pointer for CC/FD or XL data */
int incdlc = 0; int incdlc = 0;
int priority = -1;
unsigned long rnd; unsigned long rnd;
unsigned char fixdata[CANFD_MAX_DLEN]; unsigned char fixdata[CANFD_MAX_DLEN];
unsigned char rand_position[CANFD_MAX_DLEN] = { 0 }; unsigned char rand_position[CANFD_MAX_DLEN] = { 0 };
@@ -494,7 +490,7 @@ int main(int argc, char **argv)
struct can_raw_vcid_options vcid_opts = { struct can_raw_vcid_options vcid_opts = {
.flags = CAN_RAW_XL_VCID_TX_PASS, .flags = CAN_RAW_XL_VCID_TX_PASS,
}; };
static union cfu cu; static cu_t cu;
int i; int i;
struct ifreq ifr = { 0 }; struct ifreq ifr = { 0 };
const int enable_canfx = 1; const int enable_canfx = 1;
@@ -516,7 +512,7 @@ int main(int argc, char **argv)
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 },
}; };
while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:P:n:ixc:vh?", long_options, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:n:ixc:vh?", long_options, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'g': case 'g':
gap = strtod(optarg, NULL); gap = strtod(optarg, NULL);
@@ -576,6 +572,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;
@@ -685,14 +682,6 @@ int main(int argc, char **argv)
} }
break; break;
case 'P':
priority = atoi(optarg);
if (priority < 0) {
printf("socket priority has to be >= 0\n");
exit(1);
}
break;
case 'i': case 'i':
ignore_enobufs = true; ignore_enobufs = true;
break; break;
@@ -761,16 +750,6 @@ int main(int argc, char **argv)
*/ */
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/*
* user can use tc to configure the queuing discipline (e.g. mqprio),
* together with SO_PRIORITY option to specify the message send from
* this socket should go to which queue.
*/
if (priority >= 0 &&
setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority))) {
printf("error setting SO_PRIORITY\n");
}
if (loopback_disable) { if (loopback_disable) {
const int loopback = 0; const int loopback = 0;
@@ -778,58 +757,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 +773,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 +967,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 +1020,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 +1062,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 */
} }
} }
+6 -28
View File
@@ -177,8 +177,7 @@ int main(int argc, char **argv)
sigset_t sigset; sigset_t sigset;
fd_set rdfs; fd_set rdfs;
int s[MAXDEV]; int s[MAXDEV];
int socki; int socki, accsocket;
int accsocket = -1;
canid_t mask[MAXDEV] = {0}; canid_t mask[MAXDEV] = {0};
canid_t value[MAXDEV] = {0}; canid_t value[MAXDEV] = {0};
int inv_filter[MAXDEV] = {0}; int inv_filter[MAXDEV] = {0};
@@ -192,7 +191,7 @@ int main(int argc, char **argv)
.rx_vcid_mask = 0, .rx_vcid_mask = 0,
}; };
struct can_filter rfilter; struct can_filter rfilter;
static union cfu cu; /* union for CAN CC/FD/XL frames */ static cu_t cu; /* union for CAN CC/FD/XL frames */
const int canfx_on = 1; const int canfx_on = 1;
int nbytes, i, j; int nbytes, i, j;
struct ifreq ifr; struct ifreq ifr;
@@ -287,7 +286,7 @@ int main(int argc, char **argv)
inaddr.sin_addr.s_addr = htonl(INADDR_ANY); inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
inaddr.sin_port = htons(port); inaddr.sin_port = htons(port);
while(running && bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) { while(bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) {
struct timespec f = { struct timespec f = {
.tv_nsec = 100 * 1000 * 1000, .tv_nsec = 100 * 1000 * 1000,
}; };
@@ -296,28 +295,18 @@ int main(int argc, char **argv)
nanosleep(&f, NULL); nanosleep(&f, NULL);
} }
/*
* Check if loop exited due to signal (during nanosleep) rather than
* successful bind.
*/
if (!running) {
close(socki);
return 128 + signal_num;
}
if (listen(socki, 3) != 0) { if (listen(socki, 3) != 0) {
perror("listen"); perror("listen");
exit(1); exit(1);
} }
while(running) { while(1) {
accsocket = accept(socki, (struct sockaddr*)&clientaddr, &sin_size); accsocket = accept(socki, (struct sockaddr*)&clientaddr, &sin_size);
if (accsocket > 0) { if (accsocket > 0) {
//printf("accepted\n"); //printf("accepted\n");
if (!fork()) if (!fork())
break; break;
close(accsocket); close(accsocket);
accsocket = -1;
} }
else if (errno != EINTR) { else if (errno != EINTR) {
perror("accept"); perror("accept");
@@ -325,22 +314,11 @@ int main(int argc, char **argv)
} }
} }
/*
* Check if loop exited due to signal (accept returned EINTR) rather
* than successful fork
*/
if (!running) {
if (accsocket > 0)
close(accsocket);
close(socki);
return 128 + signal_num;
}
for (i=0; i<currmax; i++) { 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");
+11 -23
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 */
@@ -261,7 +261,7 @@ int main(int argc, char **argv)
struct can_raw_vcid_options vcid_opts = { struct can_raw_vcid_options vcid_opts = {
.flags = CAN_RAW_XL_VCID_TX_PASS, .flags = CAN_RAW_XL_VCID_TX_PASS,
}; };
static union cfu cu; static cu_t cu;
static struct timeval today_tv, log_tv, last_log_tv, diff_tv; static struct timeval today_tv, log_tv, last_log_tv, diff_tv;
struct timespec sleep_ts; struct timespec sleep_ts;
int s; /* CAN_RAW socket */ int s; /* CAN_RAW socket */
@@ -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;
} }
+3 -7
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)
@@ -117,7 +113,7 @@ int main(int argc, char **argv)
struct can_raw_vcid_options vcid_opts = { struct can_raw_vcid_options vcid_opts = {
.flags = CAN_RAW_XL_VCID_TX_PASS, .flags = CAN_RAW_XL_VCID_TX_PASS,
}; };
static union cfu cu; static cu_t cu;
struct ifreq ifr; struct ifreq ifr;
/* check command line options */ /* check command line options */
+11 -11
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 */
+1 -2
View File
@@ -182,7 +182,7 @@ struct canfd_frame {
/* /*
* defined bits for canxl_frame.flags * defined bits for canxl_frame.flags
* *
* The canxl_frame.flags element contains three bits CANXL_[XLF|SEC|RRS] * The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
* and shares the relative position of the struct can[fd]_frame.len element. * and shares the relative position of the struct can[fd]_frame.len element.
* The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame. * The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
* As a side effect setting this bit intentionally breaks the length checks * As a side effect setting this bit intentionally breaks the length checks
@@ -192,7 +192,6 @@ struct canfd_frame {
*/ */
#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */ #define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */ #define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
#define CANXL_RRS 0x02 /* Remote Request Substitution */
/* the 8-bit VCID is optionally placed in the canxl_frame.prio element */ /* the 8-bit VCID is optionally placed in the canxl_frame.prio element */
#define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */ #define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */
-2
View File
@@ -22,8 +22,6 @@ struct regmap {
}; };
#define pr_info(...) fprintf(stdout, ## __VA_ARGS__) #define pr_info(...) fprintf(stdout, ## __VA_ARGS__)
#define pr_err(...) fprintf(stderr, ## __VA_ARGS__)
#define pr_warn(...) fprintf(stderr, ## __VA_ARGS__)
#define pr_cont(...) fprintf(stdout, ## __VA_ARGS__) #define pr_cont(...) fprintf(stdout, ## __VA_ARGS__)
#define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__) #define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__)
#define BUILD_BUG_ON(...) #define BUILD_BUG_ON(...)
+21 -21
View File
@@ -336,7 +336,7 @@ int isobusfs_cli_process_events_and_tasks(struct isobusfs_priv *priv)
if (priv->state == ISOBUSFS_CLI_STATE_SELFTEST) if (priv->state == ISOBUSFS_CLI_STATE_SELFTEST)
dont_wait = true; dont_wait = true;
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, dont_wait); ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, dont_wait);
if (ret) if (ret)
return ret; return ret;
@@ -354,7 +354,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname; struct sockaddr_can addr = priv->sockname;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -362,7 +362,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
/* TODO: this is TX only socket */ /* TODO: this is TX only socket */
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL;
ret = libj1939_bind_socket(priv->sock_main, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_main, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -370,7 +370,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT); ret = isobusfs_cmn_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -378,7 +378,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_main, EPOLLIN); priv->sock_main, EPOLLIN);
} }
@@ -398,7 +398,7 @@ static int isobusfs_cli_sock_int_prepare(struct isobusfs_priv *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
STDIN_FILENO, EPOLLIN); STDIN_FILENO, EPOLLIN);
} }
@@ -407,7 +407,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname; struct sockaddr_can addr = priv->sockname;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -419,7 +419,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
/* TODO: this is TX only socket */ /* TODO: this is TX only socket */
addr.can_addr.j1939.pgn = J1939_NO_PGN; addr.can_addr.j1939.pgn = J1939_NO_PGN;
ret = libj1939_bind_socket(priv->sock_ccm, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_ccm, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -427,7 +427,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT); ret = isobusfs_cmn_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -436,7 +436,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
return ret; return ret;
/* poll for errors to get confirmation if our packets are send */ /* poll for errors to get confirmation if our packets are send */
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm,
EPOLLERR); EPOLLERR);
} }
@@ -445,23 +445,23 @@ static int isobusfs_cli_sock_nack_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname; struct sockaddr_can addr = priv->sockname;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
priv->sock_nack = ret; priv->sock_nack = ret;
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK; addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
ret = libj1939_bind_socket(priv->sock_nack, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK); ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* poll for errors to get confirmation if our packets are send */ /* poll for errors to get confirmation if our packets are send */
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN); priv->sock_nack, EPOLLIN);
} }
@@ -471,7 +471,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname; struct sockaddr_can addr = priv->sockname;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -481,11 +481,11 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
addr.can_addr.j1939.name = J1939_NO_NAME; addr.can_addr.j1939.name = J1939_NO_NAME;
addr.can_addr.j1939.addr = J1939_NO_ADDR; addr.can_addr.j1939.addr = J1939_NO_ADDR;
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL;
ret = libj1939_bind_socket(priv->sock_bcast_rx, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_bcast_rx, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_set_broadcast(priv->sock_bcast_rx); ret = isobusfs_cmn_set_broadcast(priv->sock_bcast_rx);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -493,7 +493,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx,
EPOLLIN); EPOLLIN);
} }
@@ -501,7 +501,7 @@ static int isobusfs_cli_sock_prepare(struct isobusfs_priv *priv)
{ {
int ret; int ret;
ret = libj1939_create_epoll(); ret = isobusfs_cmn_create_epoll();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -647,8 +647,8 @@ int main(int argc, char *argv[])
bzero(priv, sizeof(*priv)); bzero(priv, sizeof(*priv));
libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN); isobusfs_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
libj1939_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS); isobusfs_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS);
ret = isobusfs_cli_parse_args(priv, argc, argv); ret = isobusfs_cli_parse_args(priv, argc, argv);
if (ret) if (ret)
+1 -1
View File
@@ -103,7 +103,7 @@ struct isobusfs_priv {
struct isobusfs_buf_log tx_buf_log; struct isobusfs_buf_log tx_buf_log;
enum isobusfs_cli_state state; enum isobusfs_cli_state state;
struct libj1939_cmn cmn; struct isobusfs_cmn cmn;
uint8_t handle; uint8_t handle;
uint32_t read_offset; uint32_t read_offset;
+1 -1
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)
+1 -1
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 },
+186 -1
View File
@@ -125,6 +125,29 @@ void isobusfs_log_level_set(log_level_t level)
log_level = level; log_level = level;
} }
int isobusfs_get_timeout_ms(struct timespec *ts)
{
struct timespec curr_time;
int64_t time_diff;
int timeout_ms;
clock_gettime(CLOCK_MONOTONIC, &curr_time);
time_diff = timespec_diff_ms(ts, &curr_time);
if (time_diff < 0) {
/* Too late to send next message. Send it now */
timeout_ms = 0;
} else {
if (time_diff > INT_MAX) {
warn("timeout too long: %" PRId64 " ms", time_diff);
time_diff = INT_MAX;
}
timeout_ms = time_diff;
}
return timeout_ms;
}
const char *isobusfs_error_to_str(enum isobusfs_error err) const char *isobusfs_error_to_str(enum isobusfs_error err)
{ {
switch (err) { switch (err) {
@@ -215,6 +238,15 @@ enum isobusfs_error linux_error_to_isobusfs_error(int linux_err)
} }
} }
void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = pgn;
}
static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg, static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg,
const char *name, struct timespec *cur) const char *name, struct timespec *cur)
{ {
@@ -488,6 +520,28 @@ int isobusfs_send(int sock, const void *data, size_t len,
return 0; return 0;
} }
/**
* isobusfs_cmn_open_socket - Open a CAN J1939 socket
*
* This function opens a CAN J1939 socket and returns the file descriptor
* on success. In case of an error, the function returns the negative
* error code.
*/
int isobusfs_cmn_open_socket(void)
{
int ret;
/* Create a new CAN J1939 socket */
ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (ret < 0) {
/* Get the error code and print an error message */
ret = -errno;
pr_err("socket(j1939): %d (%s)", ret, strerror(ret));
return ret;
}
return ret;
}
/** /**
* isobusfs_cmn_configure_socket_filter - Configure a J1939 socket filter * isobusfs_cmn_configure_socket_filter - Configure a J1939 socket filter
* @sock: Socket file descriptor * @sock: Socket file descriptor
@@ -596,6 +650,47 @@ int isobusfs_cmn_configure_error_queue(int sock)
return 0; return 0;
} }
/**
* isobusfs_cmn_bind_socket - Bind a J1939 socket to a given address
* @sock: socket file descriptor
* @addr: pointer to a sockaddr_can structure containing the address
* information to bind the socket to
*
* This function binds a J1939 socket to the specified address. It returns
* 0 on successful binding or a negative error code on failure.
*
* Return: 0 on success, or a negative error code on failure.
*/
int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr)
{
int ret;
ret = bind(sock, (void *)addr, sizeof(*addr));
if (ret < 0) {
ret = -errno;
pr_err("failed to bind: %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
int isobusfs_cmn_socket_prio(int sock, int prio)
{
int ret;
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&prio, sizeof(prio));
if (ret < 0) {
ret = -errno;
pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret,
strerror(ret));
return ret;
}
return 0;
}
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr) int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
{ {
int ret; int ret;
@@ -610,8 +705,34 @@ int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
return 0; return 0;
} }
/**
* isobusfs_cmn_set_broadcast - Enable broadcast option for a socket
* @sock: socket file descriptor
*
* This function enables the SO_BROADCAST option for the given socket,
* allowing it to send and receive broadcast messages. It returns 0 on success
* or a negative error code on failure.
*
* Return: 0 on success, or a negative error code on failure.
*/
int isobusfs_cmn_set_broadcast(int sock)
{
int broadcast = true;
int ret;
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast));
if (ret < 0) {
ret = -errno;
pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/* FIXME: linger is currently not supported by the kernel J1939 stack /* 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)
@@ -632,6 +753,70 @@ int isobusfs_cmn_set_linger(int sock)
return 0; return 0;
} }
int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events)
{
struct epoll_event ev = {0};
int ret;
ev.events = events;
ev.data.fd = sock;
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
if (ret < 0) {
ret = errno;
pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
int isobusfs_cmn_create_epoll(void)
{
int ret, epoll_fd;
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
ret = -errno;
pr_err("epoll_create1: %d (%s)", ret, strerror(ret));
return ret;
}
return epoll_fd;
}
int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds,
bool dont_wait)
{
int ret, timeout_ms;
if (dont_wait)
timeout_ms = 0;
else
timeout_ms = isobusfs_get_timeout_ms(&cmn->next_send_time);
ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events,
cmn->epoll_events_size, timeout_ms);
if (ret < 0) {
ret = -errno;
if (ret != -EINTR) {
*nfds = 0;
return ret;
}
}
*nfds = ret;
ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time);
if (ret < 0) {
ret = -errno;
pr_err("failed to get time: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size, void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
size_t x) size_t x)
{ {
+19
View File
@@ -257,6 +257,15 @@ struct isobusfs_err_msg {
struct isobusfs_stats *stats; struct isobusfs_stats *stats;
}; };
struct isobusfs_cmn {
int epoll_fd;
struct epoll_event *epoll_events;
size_t epoll_events_size;
struct timespec next_send_time;
struct timespec last_time;
};
void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
int isobusfs_recv_err(int sock, struct isobusfs_err_msg *emsg); int isobusfs_recv_err(int sock, struct isobusfs_err_msg *emsg);
/* /*
@@ -291,6 +300,7 @@ static inline uint8_t isobusfs_cg_function_to_buf(enum isobusfs_cg cg,
const char *isobusfs_error_to_str(enum isobusfs_error err); const char *isobusfs_error_to_str(enum isobusfs_error err);
enum isobusfs_error linux_error_to_isobusfs_error(int linux_err); enum isobusfs_error linux_error_to_isobusfs_error(int linux_err);
int isobusfs_get_timeout_ms(struct timespec *ts);
void isobusfs_send_nack(int sock, struct isobusfs_msg *msg); void isobusfs_send_nack(int sock, struct isobusfs_msg *msg);
void isobufs_store_tx_data(struct isobusfs_buf_log *buffer, uint8_t *data); void isobufs_store_tx_data(struct isobusfs_buf_log *buffer, uint8_t *data);
void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer); void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer);
@@ -303,11 +313,20 @@ int isobusfs_send(int sock, const void *data, size_t len,
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size, void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
size_t x); size_t x);
int isobusfs_cmn_open_socket(void);
int isobusfs_cmn_configure_socket_filter(int sock, pgn_t pgn); int isobusfs_cmn_configure_socket_filter(int sock, pgn_t pgn);
int isobusfs_cmn_configure_error_queue(int sock); int isobusfs_cmn_configure_error_queue(int sock);
int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr);
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr); int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr);
int isobusfs_cmn_set_broadcast(int sock);
int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);
int isobusfs_cmn_create_epoll(void);
int isobusfs_cmn_socket_prio(int sock, int prio);
int isobusfs_cmn_set_linger(int sock); int isobusfs_cmn_set_linger(int sock);
int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds,
bool dont_wait);
/* ============ directory handling ============ */ /* ============ directory handling ============ */
int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable); int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable);
+1 -1
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;
} }
+20 -20
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)
*/ */
@@ -250,7 +250,7 @@ static int isobusfs_srv_process_events_and_tasks(struct isobusfs_srv_priv *priv)
{ {
int ret, nfds; int ret, nfds;
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false); ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, false);
if (ret) if (ret)
return ret; return ret;
@@ -268,7 +268,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
struct sockaddr_can addr = priv->addr; struct sockaddr_can addr = priv->addr;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -279,15 +279,15 @@ 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;
ret = libj1939_bind_socket(priv->sock_fss, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_fss, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_set_broadcast(priv->sock_fss); ret = isobusfs_cmn_set_broadcast(priv->sock_fss);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -295,7 +295,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS); ret = isobusfs_cmn_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -308,7 +308,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
return ret; return ret;
/* poll for errors to get confirmation if our packets are send */ /* poll for errors to get confirmation if our packets are send */
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss,
EPOLLERR); EPOLLERR);
} }
@@ -317,7 +317,7 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv)
struct sockaddr_can addr = priv->addr; struct sockaddr_can addr = priv->addr;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -325,12 +325,12 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv)
/* keep address and name and overwrite PGN */ /* keep address and name and overwrite PGN */
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
ret = libj1939_bind_socket(priv->sock_in, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_in, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in,
EPOLLIN); EPOLLIN);
} }
static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv) static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv)
@@ -338,24 +338,24 @@ static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv)
struct sockaddr_can addr = priv->addr; struct sockaddr_can addr = priv->addr;
int ret; int ret;
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
priv->sock_nack = ret; priv->sock_nack = ret;
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK; addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
ret = libj1939_bind_socket(priv->sock_nack, &addr); ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK); ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* poll for errors to get confirmation if our packets are send */ /* poll for errors to get confirmation if our packets are send */
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN); priv->sock_nack, EPOLLIN);
} }
/** /**
@@ -370,7 +370,7 @@ static int isobusfs_srv_sock_prepare(struct isobusfs_srv_priv *priv)
{ {
int ret; int ret;
ret = libj1939_create_epoll(); ret = isobusfs_cmn_create_epoll();
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -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:");
@@ -762,7 +762,7 @@ int main(int argc, char *argv[])
memset(priv, 0, sizeof(*priv)); memset(priv, 0, sizeof(*priv));
/* Initialize sockaddr_can with a non-configurable PGN */ /* Initialize sockaddr_can with a non-configurable PGN */
libj1939_init_sockaddr_can(&priv->addr, J1939_NO_PGN); isobusfs_init_sockaddr_can(&priv->addr, J1939_NO_PGN);
priv->server_version = ISOBUSFS_SRV_VERSION; priv->server_version = ISOBUSFS_SRV_VERSION;
/* Parse command line arguments */ /* Parse command line arguments */
+1 -1
View File
@@ -103,7 +103,7 @@ struct isobusfs_srv_priv {
int clients_count; int clients_count;
struct isobusfs_buf_log tx_buf_log; struct isobusfs_buf_log tx_buf_log;
struct libj1939_cmn cmn; struct isobusfs_cmn cmn;
struct isobusfs_srv_volume volumes[ISOBUSFS_SRV_MAX_VOLUMES]; struct isobusfs_srv_volume volumes[ISOBUSFS_SRV_MAX_VOLUMES];
int volume_count; int volume_count;
+3 -3
View File
@@ -213,14 +213,14 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv,
return -EINVAL; return -EINVAL;
} }
ret = libj1939_open_socket(); ret = isobusfs_cmn_open_socket();
if (ret < 0) if (ret < 0)
return ret; return ret;
client->sock = ret; client->sock = ret;
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
ret = libj1939_bind_socket(client->sock, &addr); ret = isobusfs_cmn_bind_socket(client->sock, &addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -243,7 +243,7 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv,
goto close_socket; goto close_socket;
} }
ret = libj1939_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT); ret = isobusfs_cmn_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT);
if (ret < 0) if (ret < 0)
return ret; return ret;
+3 -3
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;
+1 -1
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:
+105 -130
View File
@@ -72,7 +72,6 @@ void print_usage(char *prg)
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n"); fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n"); fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -b <can_id> (broadcast can_id, Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n"); fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n"); fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
fprintf(stderr, " -c (color mode)\n"); fprintf(stderr, " -c (color mode)\n");
@@ -198,12 +197,11 @@ int main(int argc, char **argv)
{ {
int s; int s;
struct sockaddr_can addr; struct sockaddr_can addr;
struct can_filter rfilter[3]; struct can_filter rfilter[2];
struct canfd_frame frame; struct canfd_frame frame;
int nbytes, i; int nbytes, i;
canid_t src = NO_CAN_ID; canid_t src = NO_CAN_ID;
canid_t dst = NO_CAN_ID; canid_t dst = NO_CAN_ID;
canid_t bst = NO_CAN_ID;
int ext = 0; int ext = 0;
int extaddr = 0; int extaddr = 0;
int extany = 0; int extany = 0;
@@ -224,7 +222,7 @@ int main(int argc, char **argv)
last_tv.tv_sec = 0; last_tv.tv_sec = 0;
last_tv.tv_usec = 0; last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "s:d:b:ax:X:ct:u?")) != -1) { while ((opt = getopt(argc, argv, "s:d:ax:X:ct:u?")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
src = strtoul(optarg, NULL, 16); src = strtoul(optarg, NULL, 16);
@@ -238,12 +236,6 @@ int main(int argc, char **argv)
dst |= CAN_EFF_FLAG; dst |= CAN_EFF_FLAG;
break; break;
case 'b':
bst = strtoul(optarg, NULL, 16);
if (strlen(optarg) > 7)
bst |= CAN_EFF_FLAG;
break;
case 'c': case 'c':
color = 1; color = 1;
break; break;
@@ -329,18 +321,7 @@ int main(int argc, char **argv)
rfilter[1].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG); rfilter[1].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
} }
if (bst & CAN_EFF_FLAG) { setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
rfilter[2].can_id = bst & (CAN_EFF_MASK | CAN_EFF_FLAG);
rfilter[2].can_mask = (CAN_EFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
} else {
rfilter[2].can_id = bst & CAN_SFF_MASK;
rfilter[2].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
}
if (bst != NO_CAN_ID)
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
else
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter) - sizeof(rfilter[0]));
addr.can_family = AF_CAN; addr.can_family = AF_CAN;
addr.can_ifindex = if_nametoindex(argv[optind]); addr.can_ifindex = if_nametoindex(argv[optind]);
@@ -372,14 +353,8 @@ int main(int argc, char **argv)
rx_extaddr != frame.data[0]) rx_extaddr != frame.data[0])
continue; continue;
if (color) { if (color)
if (frame.can_id == src) printf("%s", (frame.can_id == src) ? FGRED : FGBLUE);
printf("%s", FGRED);
else if (frame.can_id == dst)
printf("%s", FGBLUE);
else if (frame.can_id == bst)
printf("%s", FGGREEN);
}
if (timestamp) { if (timestamp) {
ioctl(s, SIOCGSTAMP, &tv); ioctl(s, SIOCGSTAMP, &tv);
@@ -426,112 +401,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);
+147 -147
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);
+153 -153
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;
} }
+200 -200
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;
} }
-500
View File
@@ -1,500 +0,0 @@
// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/kernel.h>
#include <net/if.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "j1939_timedate_cmn.h"
#define J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS 10
struct j1939_timedate_cli_priv {
int sock_nack;
int sock_main;
struct sockaddr_can sockname;
struct sockaddr_can peername;
struct j1939_timedate_stats stats;
struct libj1939_cmn cmn;
struct timespec wait_until_time;
bool utc;
bool broadcast;
bool done;
};
static void print_time_date_packet(struct j1939_timedate_cli_priv *priv,
const struct j1939_timedate_msg *msg)
{
const struct j1939_time_date_packet *tdp =
(const struct j1939_time_date_packet *)msg->buf;
char timezone_offset[] = "+00:00 (Local Time)";
char time_buffer[64];
int actual_hour, actual_minute;
int actual_year, actual_month;
double actual_seconds;
double actual_day;
if (msg->len < (int)sizeof(*tdp)) {
pr_warn("received too short time and date packet: %zi",
msg->len);
return;
}
actual_year = 1985 + tdp->year;
actual_month = tdp->month;
actual_day = tdp->day * 0.25;
actual_hour = tdp->hours;
actual_minute = tdp->minutes;
actual_seconds = tdp->seconds * 0.25;
if (tdp->local_hour_offset == 125) {
snprintf(timezone_offset, sizeof(timezone_offset),
"+00:00 (Local Time)");
} else if (!priv->utc) {
actual_hour += tdp->local_hour_offset;
actual_minute += tdp->local_minute_offset;
/* Wraparound for hours and minutes if needed */
if (actual_minute >= 60) {
actual_minute -= 60;
actual_hour++;
} else if (actual_minute < 0) {
actual_minute += 60;
actual_hour--;
}
if (actual_hour >= 24) {
actual_hour -= 24;
actual_day++;
} else if (actual_hour < 0) {
actual_hour += 24;
actual_day--;
}
snprintf(timezone_offset, sizeof(timezone_offset), "%+03d:%02d",
tdp->local_hour_offset, abs(tdp->local_minute_offset));
} else {
snprintf(timezone_offset, sizeof(timezone_offset),
"+00:00 (UTC)");
}
snprintf(time_buffer, sizeof(time_buffer),
"%d-%02d-%02.0f %02d:%02d:%05.2f%.20s",
actual_year, actual_month, actual_day, actual_hour,
actual_minute, actual_seconds, timezone_offset);
printf("SA: 0x%02X, NAME: 0x%016llX, Time: %s\n",
msg->peername.can_addr.j1939.addr,
msg->peername.can_addr.j1939.name, time_buffer);
if (!priv->broadcast)
priv->done = true;
}
static int j1939_timedate_cli_rx_buf(struct j1939_timedate_cli_priv *priv,
struct j1939_timedate_msg *msg)
{
pgn_t pgn = msg->peername.can_addr.j1939.pgn;
int ret = 0;
switch (pgn) {
case J1939_PGN_TD:
print_time_date_packet(priv, msg);
break;
default:
pr_warn("%s: unsupported PGN: %x", __func__, pgn);
/* Not a critical error */
break;
}
return ret;
}
static int j1939_timedate_cli_rx_one(struct j1939_timedate_cli_priv *priv,
int sock)
{
struct j1939_timedate_msg *msg;
int flags = 0;
int ret;
msg = malloc(sizeof(*msg));
if (!msg) {
pr_err("can't allocate rx msg struct\n");
return -ENOMEM;
}
msg->buf_size = J1939_TIMEDATE_MAX_TRANSFER_LENGH;
msg->peer_addr_len = sizeof(msg->peername);
msg->sock = sock;
ret = recvfrom(sock, &msg->buf[0], msg->buf_size, flags,
(struct sockaddr *)&msg->peername, &msg->peer_addr_len);
if (ret < 0) {
ret = -errno;
pr_warn("recvfrom() failed: %i %s", ret, strerror(-ret));
return ret;
}
if (ret < 3) {
pr_warn("received too short message: %i", ret);
return -EINVAL;
}
msg->len = ret;
ret = j1939_timedate_cli_rx_buf(priv, msg);
if (ret < 0) {
pr_warn("failed to process rx buf: %i (%s)\n", ret,
strerror(ret));
return ret;
}
return 0;
}
static int j1939_timedate_cli_handle_events(struct j1939_timedate_cli_priv *priv,
unsigned int nfds)
{
int ret;
unsigned int n;
for (n = 0; n < nfds && n < priv->cmn.epoll_events_size; ++n) {
struct epoll_event *ev = &priv->cmn.epoll_events[n];
if (!ev->events) {
warn("no events");
continue;
}
if (ev->events & POLLIN) {
ret = j1939_timedate_cli_rx_one(priv, ev->data.fd);
if (ret) {
warn("recv one");
return ret;
}
}
}
return 0;
}
static int j1939_timedate_cli_process_events_and_tasks(struct j1939_timedate_cli_priv *priv)
{
int ret, nfds;
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
if (ret)
return ret;
if (nfds > 0) {
ret = j1939_timedate_cli_handle_events(priv, nfds);
if (ret)
return ret;
}
return 0;
}
static int j1939_timedate_cli_send_req(struct j1939_timedate_cli_priv *priv)
{
struct sockaddr_can addr = priv->peername;
uint8_t data[3] = {0};
int ret;
addr.can_addr.j1939.pgn = J1939_PGN_REQUEST_PGN;
data[0] = J1939_PGN_TD & 0xff;
data[1] = (J1939_PGN_TD >> 8) & 0xff;
data[2] = (J1939_PGN_TD >> 16) & 0xff;
ret = sendto(priv->sock_main, data, sizeof(data), 0,
(struct sockaddr *)&addr, sizeof(addr));
if (ret == -1) {
ret = -errno;
pr_warn("failed to send data: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
static int j1939_timedate_cli_sock_main_prepare(struct j1939_timedate_cli_priv *priv)
{
struct sockaddr_can addr = priv->sockname;
int ret;
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_main = ret;
ret = libj1939_bind_socket(priv->sock_main, &addr);
if (ret < 0)
return ret;
ret = libj1939_socket_prio(priv->sock_main,
J1939_TIMEDATE_PRIO_DEFAULT);
if (ret < 0)
return ret;
ret = libj1939_set_broadcast(priv->sock_main);
if (ret < 0)
return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_main, EPOLLIN);
}
static int j1939_timedate_cli_sock_nack_prepare(struct j1939_timedate_cli_priv *priv)
{
struct sockaddr_can addr = priv->sockname;
int ret;
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_nack = ret;
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
ret = libj1939_bind_socket(priv->sock_nack, &addr);
if (ret < 0)
return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN);
}
static int j1939_timedate_cli_sock_prepare(struct j1939_timedate_cli_priv *priv)
{
int ret;
ret = libj1939_create_epoll();
if (ret < 0)
return ret;
priv->cmn.epoll_fd = ret;
priv->cmn.epoll_events = calloc(J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS,
sizeof(struct epoll_event));
if (!priv->cmn.epoll_events)
return -ENOMEM;
priv->cmn.epoll_events_size = J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS;
ret = j1939_timedate_cli_sock_main_prepare(priv);
if (ret < 0)
return ret;
return j1939_timedate_cli_sock_nack_prepare(priv);
}
static void j1939_timedate_cli_print_help(void)
{
printf("Usage: j1939_timedate-cli [options]\n");
printf("Options:\n");
printf(" --interface <interface_name> or -i <interface_name>\n");
printf(" Specifies the CAN interface to use (mandatory).\n");
printf(" --local-address <local_address_hex> or -a <local_address_hex>\n");
printf(" Specifies the local address in hexadecimal (mandatory if local name is not provided).\n");
printf(" --local-name <local_name_hex> or -n <local_name_hex>\n");
printf(" Specifies the local NAME in hexadecimal (mandatory if local address is not provided).\n");
printf(" --remote-address <remote_address_hex> or -r <remote_address_hex>\n");
printf(" Specifies the remote address in hexadecimal (optional).\n");
printf(" --remote-name <remote_name_hex> or -m <remote_name_hex>\n");
printf(" Specifies the remote NAME in hexadecimal (optional).\n");
printf(" --utc or -u\n");
printf(" Outputs the time in UTC format.\n");
printf("\n");
printf("Note:\n");
printf(" Local address and local name are mutually exclusive and one must be provided.\n");
printf(" Remote address and remote name are mutually exclusive. \n");
printf(" If no remote property is provided, the broadcast address will be used.\n");
printf("\n");
printf("Behavior:\n");
printf(" In unicast mode (remote address or remote name provided),\n");
printf(" the client will send a request and wait for the first response, then exit.\n");
printf(" In broadcast mode (no remote address or remote name provided),\n");
printf(" the program will wait 1000 milliseconds to collect responses, then exit.\n");
printf("\n");
printf("Time Output Formats:\n");
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 (Local Time) - when no time zone information is received.\n");
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 (UTC) - when the --utc option is used.\n");
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 - default response with time zone offset automatically calculated.\n");
printf("\n");
printf("Complete Message Format:\n");
printf(" The message will include the Source Address (SA) and J1939 NAME, formatted as follows:\n");
printf(" SA: 0x60, NAME: 0x0000000000000000, Time: 2024-05-16 20:23:40.00+02:00\n");
printf(" If the NAME is known, it will have a non-zero value.\n");
printf("\n");
printf("Usage Examples:\n");
printf(" j1939acd -r 64-95 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0 &\n");
printf("\n");
printf(" Broadcast mode:\n");
printf(" j1939-timedate-cli -i vcan0 -a 0x80\n");
printf("\n");
printf(" Unicast mode:\n");
printf(" j1939-timedate-cli -i vcan0 -a 0x80 -r 0x90\n");
printf("\n");
printf(" Using NAMEs instead of addresses:\n");
printf(" j1939acd -r 64-95 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0 &\n");
printf(" j1939-timedate-cli -i vcan0 -n 0x1122334455667788\n");
}
static int j1939_timedate_cli_parse_args(struct j1939_timedate_cli_priv *priv, int argc, char *argv[])
{
struct sockaddr_can *remote = &priv->peername;
struct sockaddr_can *local = &priv->sockname;
bool local_address_set = false;
bool local_name_set = false;
bool remote_address_set = false;
bool remote_name_set = false;
bool interface_set = false;
int long_index = 0;
int opt;
static struct option long_options[] = {
{"interface", required_argument, 0, 'i'},
{"local-address", required_argument, 0, 'a'},
{"local-name", required_argument, 0, 'n'},
{"remote-address", required_argument, 0, 'r'},
{"remote-name", required_argument, 0, 'm'},
{"utc", no_argument, 0, 'u'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "a:n:r:m:i:u", long_options, &long_index)) != -1) {
switch (opt) {
case 'a':
local->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
local_address_set = true;
break;
case 'n':
local->can_addr.j1939.name = strtoull(optarg, NULL, 16);
local_name_set = true;
break;
case 'r':
remote->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
remote_address_set = true;
break;
case 'm':
remote->can_addr.j1939.name = strtoull(optarg, NULL, 16);
remote_name_set = true;
break;
case 'i':
local->can_ifindex = if_nametoindex(optarg);
if (!local->can_ifindex) {
pr_err("Interface %s not found. Error: %d (%s)\n",
optarg, errno, strerror(errno));
return -EINVAL;
}
remote->can_ifindex = local->can_ifindex;
interface_set = true;
break;
case 'u':
priv->utc = true;
break;
default:
j1939_timedate_cli_print_help();
return -EINVAL;
}
}
if (!interface_set) {
pr_err("interface not specified");
j1939_timedate_cli_print_help();
return -EINVAL;
}
if ((local_address_set && local_name_set) ||
(remote_address_set && remote_name_set)) {
pr_err("Local address and local name or remote address and remote name are mutually exclusive\n");
j1939_timedate_cli_print_help();
return -EINVAL;
}
if (!local_address_set && !local_name_set) {
pr_err("Local address and local name not specified. One of them is required\n");
j1939_timedate_cli_print_help();
return -EINVAL;
}
/* If no remote address is set, set it to broadcast */
if (!remote_address_set && !remote_name_set) {
remote->can_addr.j1939.addr = J1939_NO_ADDR;
priv->broadcast = true;
}
return 0;
}
int main(int argc, char *argv[])
{
struct j1939_timedate_cli_priv *priv;
struct timespec ts;
int64_t time_diff;
int ret;
priv = malloc(sizeof(*priv));
if (!priv)
err(EXIT_FAILURE, "can't allocate priv");
bzero(priv, sizeof(*priv));
libj1939_init_sockaddr_can(&priv->sockname, J1939_PGN_TD);
libj1939_init_sockaddr_can(&priv->peername, J1939_PGN_REQUEST_PGN);
ret = j1939_timedate_cli_parse_args(priv, argc, argv);
if (ret)
return ret;
ret = j1939_timedate_cli_sock_prepare(priv);
if (ret)
return ret;
clock_gettime(CLOCK_MONOTONIC, &ts);
priv->cmn.next_send_time = ts;
priv->wait_until_time = priv->cmn.next_send_time;
/* Wait one second to collect all responses by default */
timespec_add_ms(&priv->wait_until_time, 1000);
ret = j1939_timedate_cli_send_req(priv);
if (ret)
return ret;
while (1) {
ret = j1939_timedate_cli_process_events_and_tasks(priv);
if (ret)
break;
if (priv->done)
break;
clock_gettime(CLOCK_MONOTONIC, &ts);
time_diff = timespec_diff_ms(&priv->wait_until_time, &ts);
if (time_diff < 0)
break;
}
close(priv->cmn.epoll_fd);
free(priv->cmn.epoll_events);
close(priv->sock_main);
close(priv->sock_nack);
return ret;
}
-84
View File
@@ -1,84 +0,0 @@
// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
#ifndef _J1939_TIMEDATE_H_
#define _J1939_TIMEDATE_H_
#include <stdint.h>
#include <endian.h>
#include <stdbool.h>
#include <sys/epoll.h>
#include <linux/can.h>
#include <linux/kernel.h>
#include "../libj1939.h"
#include "../lib.h"
/* SAE J1939-71:2002 - 5.3 pgn54528 - Time/Date Adjust - TDA - */
#define J1939_PGN_TDA 0x0d500 /* 54528 */
/* SAE J1939-71:2002 - 5.3 pgn65254 - Time/Date - TD - */
#define J1939_PGN_TD 0x0fee6 /* 65254 */
#define J1939_PGN_REQUEST_PGN 0x0ea00 /* 59904 */
/* ISO 11783-3:2018 - 5.4.5 Acknowledgment */
#define ISOBUS_PGN_ACK 0x0e800 /* 59392 */
#define J1939_TIMEDATE_PRIO_DEFAULT 6
#define J1939_TIMEDATE_MAX_TRANSFER_LENGH 8
struct j1939_timedate_stats {
int err;
uint32_t tskey_sch;
uint32_t tskey_ack;
uint32_t send;
};
struct j1939_timedate_msg {
uint8_t buf[J1939_TIMEDATE_MAX_TRANSFER_LENGH];
size_t buf_size;
ssize_t len; /* length of received message */
struct sockaddr_can peername;
socklen_t peer_addr_len;
int sock;
};
struct j1939_timedate_err_msg {
struct sock_extended_err *serr;
struct scm_timestamping *tss;
struct j1939_timedate_stats *stats;
};
/*
* struct time_date_packet - Represents the PGN 65254 Time/Date packet
*
* @seconds: Seconds since the last minute (0-59) with a scaling factor,
* meaning each increment represents 0.25 seconds.
* @minutes: Minutes since the last hour (0-59) with no scaling.
* @hours: Hours since midnight (0-23) with no scaling.
* @month: Current month (1-12) with no scaling.
* @day: Day of the month with a scaling factor, each increment represents 0.25
* day.
* @year: Year offset since 1985, each increment represents one year.
* @local_minute_offset: Offset in minutes from UTC, can range from -125 to 125
* minutes.
* @local_hour_offset: Offset in hours from UTC, can range from -125 to 125
* hours.
*
* This structure defines each component of the Time/Date as described in
* PGN 65254, using each byte to represent different components of the standard
* UTC time and optionally adjusted local time based on offsets.
*/
struct j1939_time_date_packet {
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
uint8_t month;
uint8_t day;
uint8_t year;
int8_t local_minute_offset;
int8_t local_hour_offset;
};
#endif /* !_J1939_TIMEDATE_H_ */
-456
View File
@@ -1,456 +0,0 @@
// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/kernel.h>
#include <net/if.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "j1939_timedate_cmn.h"
#define J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS 10
struct j1939_timedate_srv_priv {
int sock_nack;
int sock_main;
struct sockaddr_can sockname;
struct j1939_timedate_stats stats;
struct libj1939_cmn cmn;
};
static void gmtime_to_j1939_pgn_65254_td(struct j1939_time_date_packet *tdp)
{
struct tm utc_tm_buf, local_tm_buf;
int hour_offset, minute_offset;
struct tm *utc_tm, *local_tm;
int year_since_1985;
time_t now;
now = time(NULL);
utc_tm = gmtime_r(&now, &utc_tm_buf);
local_tm = localtime_r(&now, &local_tm_buf);
if (local_tm) {
/* Calculate the offsets */
hour_offset = local_tm->tm_hour - utc_tm->tm_hour;
minute_offset = local_tm->tm_min - utc_tm->tm_min;
/* Handle date rollover */
if (local_tm->tm_mday != utc_tm->tm_mday) {
if (local_tm->tm_hour < 12)
hour_offset += 24; /* past midnight */
else
hour_offset -= 24; /* before midnight */
}
} else {
/* The local time offsets cannot be determined at the moment */
hour_offset = 0xF9;
minute_offset = 0xFF;
}
/*
* Seconds (spn959):
* Resolution: 0.25 /bit, 0 offset
* Data Range: 0 to 250 (0 to 62.5 seconds)
* Operational Range: 0 to 239 (0 to 59.75 seconds)
*/
tdp->seconds = (uint8_t)(utc_tm->tm_sec / 0.25);
if (tdp->seconds > 239)
tdp->seconds = 239;
/*
* Minutes (spn960):
* Resolution: 1 min/bit, 0 offset
* Data Range: 0 to 250 (0 to 250 minutes)
* Operational Range: 0 to 59 (0 to 59 minutes)
*/
tdp->minutes = (uint8_t)utc_tm->tm_min;
if (tdp->minutes > 59)
tdp->minutes = 59;
/*
* Hours (spn961):
* Resolution: 1 hr/bit, 0 offset
* Data Range: 0 to 250 (0 to 250 hours)
* Operational Range: 0 to 23 (0 to 23 hours)
*/
tdp->hours = (uint8_t)utc_tm->tm_hour;
if (tdp->hours > 23)
tdp->hours = 23;
/*
* Day (spn962):
* Resolution: 0.25 /bit, 0 offset
* Data Range: 0 to 250 (0 to 62.5 days)
* Operational Range: 1 to 127 (0.25 to 31.75 days)
*/
tdp->day = (uint8_t)(utc_tm->tm_mday / 0.25);
if (tdp->day < 1 || tdp->day > 127)
tdp->day = 1;
/*
* Month (spn963):
* Resolution: 1 month/bit, 0 offset
* Data Range: 0 to 250 (0 to 250 months)
* Operational Range: 1 to 12 (1 to 12 months)
*/
tdp->month = (uint8_t)(utc_tm->tm_mon + 1);
if (tdp->month < 1 || tdp->month > 12)
tdp->month = 1;
/*
* Year (spn964):
* Resolution: 1 year/bit, 1985 offset
* Data Range: 0 to 250 (1985 to 2235)
* Operational Range: 0 to 250 (1985 to 2235)
*/
year_since_1985 = utc_tm->tm_year - 85;
if (year_since_1985 < 0) {
/* Fallback to year 1985 if year is before 1985 */
tdp->year = 0;
} else if (year_since_1985 > 250) {
/* Fallback to year 2235 if year is beyond 2235 */
tdp->year = 250;
} else {
tdp->year = (uint8_t)year_since_1985;
}
/*
* Local minute offset (spn1601):
* Resolution: 1 min/bit, -125 offset
* Data Range: -125 to 125 minutes
* Operational Range: -59 to 59 minutes
*/
tdp->local_minute_offset = (int8_t)minute_offset;
/*
* Local hour offset (spn1602):
* Resolution: 1 hr/bit, -125 offset
* Data Range: -125 to +125 hours
* Operational Range: -24 to +23 hours
* Note: If the local hour offset parameter is equal to 125 (0xFA),
* the local time then the time parameter is the local time instead of
* UTC.
*/
tdp->local_hour_offset = (int8_t)hour_offset;
}
static int j1939_timedate_srv_send_res(struct j1939_timedate_srv_priv *priv,
struct sockaddr_can *addr)
{
struct sockaddr_can peername = *addr;
struct j1939_time_date_packet tdp;
int ret;
gmtime_to_j1939_pgn_65254_td(&tdp);
peername.can_addr.j1939.pgn = J1939_PGN_TD;
ret = sendto(priv->sock_main, &tdp, sizeof(tdp), 0,
(struct sockaddr *)&peername, sizeof(peername));
if (ret == -1) {
ret = -errno;
pr_warn("failed to send data: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
// check if the received message is a request for the time and date
static int j1939_timedate_srv_process_request(struct j1939_timedate_srv_priv *priv,
struct j1939_timedate_msg *msg)
{
if (msg->buf[0] != (J1939_PGN_TD & 0xff) ||
msg->buf[1] != ((J1939_PGN_TD >> 8) & 0xff) ||
msg->buf[2] != ((J1939_PGN_TD >> 16) & 0xff)) {
/* Don't care, not a time and date request */
return 0;
}
return j1939_timedate_srv_send_res(priv, &msg->peername);
}
static int j1939_timedate_srv_rx_buf(struct j1939_timedate_srv_priv *priv, struct j1939_timedate_msg *msg)
{
pgn_t pgn = msg->peername.can_addr.j1939.pgn;
int ret = 0;
switch (pgn) {
case J1939_PGN_REQUEST_PGN:
ret = j1939_timedate_srv_process_request(priv, msg);
break;
default:
pr_warn("%s: unsupported PGN: %x", __func__, pgn);
/* Not a critical error */
break;
}
return ret;
}
static int j1939_timedate_srv_rx_one(struct j1939_timedate_srv_priv *priv, int sock)
{
struct j1939_timedate_msg *msg;
int flags = 0;
int ret;
msg = malloc(sizeof(*msg));
if (!msg) {
pr_err("can't allocate rx msg struct\n");
return -ENOMEM;
}
msg->buf_size = J1939_TIMEDATE_MAX_TRANSFER_LENGH;
msg->peer_addr_len = sizeof(msg->peername);
msg->sock = sock;
ret = recvfrom(sock, &msg->buf[0], msg->buf_size, flags,
(struct sockaddr *)&msg->peername, &msg->peer_addr_len);
if (ret < 0) {
ret = -errno;
pr_warn("recvfrom() failed: %i %s", ret, strerror(-ret));
return ret;
}
if (ret < 3) {
pr_warn("received too short message: %i", ret);
return -EINVAL;
}
msg->len = ret;
ret = j1939_timedate_srv_rx_buf(priv, msg);
if (ret < 0) {
pr_warn("failed to process rx buf: %i (%s)\n", ret,
strerror(ret));
return ret;
}
return 0;
}
static int j1939_timedate_srv_handle_events(struct j1939_timedate_srv_priv *priv,
unsigned int nfds)
{
int ret;
unsigned int n;
for (n = 0; n < nfds && n < priv->cmn.epoll_events_size; ++n) {
struct epoll_event *ev = &priv->cmn.epoll_events[n];
if (!ev->events) {
warn("no events");
continue;
}
if (ev->events & POLLIN) {
ret = j1939_timedate_srv_rx_one(priv, ev->data.fd);
if (ret) {
warn("recv one");
return ret;
}
}
}
return 0;
}
static int j1939_timedate_srv_process_events_and_tasks(struct j1939_timedate_srv_priv *priv)
{
int ret, nfds;
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
if (ret)
return ret;
if (nfds > 0) {
ret = j1939_timedate_srv_handle_events(priv, nfds);
if (ret)
return ret;
}
return 0;
}
static int j1939_timedate_srv_sock_main_prepare(struct j1939_timedate_srv_priv *priv)
{
struct sockaddr_can addr = priv->sockname;
int ret;
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_main = ret;
ret = libj1939_bind_socket(priv->sock_main, &addr);
if (ret < 0)
return ret;
ret = libj1939_socket_prio(priv->sock_main,
J1939_TIMEDATE_PRIO_DEFAULT);
if (ret < 0)
return ret;
ret = libj1939_set_broadcast(priv->sock_main);
if (ret < 0)
return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_main, EPOLLIN);
}
static int j1939_timedate_srv_sock_prepare(struct j1939_timedate_srv_priv *priv)
{
int ret;
ret = libj1939_create_epoll();
if (ret < 0)
return ret;
priv->cmn.epoll_fd = ret;
priv->cmn.epoll_events = calloc(J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS,
sizeof(struct epoll_event));
if (!priv->cmn.epoll_events)
return -ENOMEM;
priv->cmn.epoll_events_size = J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS;
return j1939_timedate_srv_sock_main_prepare(priv);
}
static void j1939_timedate_srv_print_help(void)
{
printf("Usage: j1939-timedate-srv [options]\n");
printf("Options:\n");
printf(" --interface <interface_name> or -i <interface_name>\n");
printf(" Specifies the CAN interface to use (mandatory).\n");
printf(" --local-address <local_address_hex> or -a <local_address_hex>\n");
printf(" Specifies the local address in hexadecimal (mandatory if\n");
printf(" local name is not provided).\n");
printf(" --local-name <local_name_hex> or -n <local_name_hex>\n");
printf(" Specifies the local NAME in hexadecimal (mandatory if\n");
printf(" local address is not provided).\n");
printf("\n");
printf("Note: Local address and local name are mutually exclusive and one\n");
printf(" must be provided.\n");
printf("\n");
printf("Usage Examples:\n");
printf(" Using local address:\n");
printf(" j1939-timedate-srv -i vcan0 -a 0x90\n");
printf("\n");
printf(" Using local NAME:\n");
printf(" j1939acd -r 64-95 -c /tmp/1122334455667789.jacd 1122334455667789 vcan0 &\n");
printf(" j1939-timedate-srv -i vcan0 -n 0x1122334455667789\n");
}
static int j1939_timedate_srv_parse_args(struct j1939_timedate_srv_priv *priv,
int argc, char *argv[])
{
struct sockaddr_can *local = &priv->sockname;
bool local_address_set = false;
bool local_name_set = false;
bool interface_set = false;
int long_index = 0;
int opt;
static struct option long_options[] = {
{"interface", required_argument, 0, 'i'},
{"local-address", required_argument, 0, 'a'},
{"local-name", required_argument, 0, 'n'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "a:n:i:", long_options, &long_index)) != -1) {
switch (opt) {
case 'a':
local->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
local_address_set = true;
break;
case 'n':
local->can_addr.j1939.name = strtoull(optarg, NULL, 16);
local_name_set = true;
break;
case 'i':
local->can_ifindex = if_nametoindex(optarg);
if (!local->can_ifindex) {
pr_err("Interface %s not found. Error: %d (%s)\n",
optarg, errno, strerror(errno));
return -EINVAL;
}
interface_set = true;
break;
default:
j1939_timedate_srv_print_help();
return -EINVAL;
}
}
if (!interface_set) {
pr_err("interface not specified");
j1939_timedate_srv_print_help();
return -EINVAL;
}
if (local_address_set && local_name_set) {
pr_err("local address and local name or remote address and remote name are mutually exclusive");
j1939_timedate_srv_print_help();
return -EINVAL;
}
return 0;
}
int main(int argc, char *argv[])
{
struct j1939_timedate_srv_priv *priv;
struct timespec ts;
int ret;
priv = malloc(sizeof(*priv));
if (!priv)
err(EXIT_FAILURE, "can't allocate priv");
bzero(priv, sizeof(*priv));
libj1939_init_sockaddr_can(&priv->sockname, J1939_PGN_REQUEST_PGN);
ret = j1939_timedate_srv_parse_args(priv, argc, argv);
if (ret)
return ret;
clock_gettime(CLOCK_MONOTONIC, &ts);
priv->cmn.next_send_time = ts;
ret = j1939_timedate_srv_sock_prepare(priv);
if (ret)
return ret;
while (1) {
ret = j1939_timedate_srv_process_events_and_tasks(priv);
if (ret)
break;
}
close(priv->cmn.epoll_fd);
free(priv->cmn.epoll_events);
close(priv->sock_main);
close(priv->sock_nack);
return ret;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+23 -9
View File
@@ -38,6 +38,7 @@ static const char help_msg[] =
" e.g. 80,50-100,200-210 (defaults to 0-253)" "\n" " e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
" -c, --cache=FILE Cache file to save/restore the source address" "\n" " -c, --cache=FILE Cache file to save/restore the source address" "\n"
" -a, --address=ADDRESS Start with Source Address ADDRESS" "\n" " -a, --address=ADDRESS Start with Source Address ADDRESS" "\n"
" -p, --prefix=STR Prefix to use when logging" "\n"
"\n" "\n"
"NAME is the 64bit nodename" "\n" "NAME is the 64bit nodename" "\n"
"\n" "\n"
@@ -53,13 +54,14 @@ static struct option long_opts[] = {
{ "range", required_argument, NULL, 'r', }, { "range", required_argument, NULL, 'r', },
{ "cache", required_argument, NULL, 'c', }, { "cache", required_argument, NULL, 'c', },
{ "address", required_argument, NULL, 'a', }, { "address", required_argument, NULL, 'a', },
{ "prefix", required_argument, NULL, 'p', },
{ }, { },
}; };
#else #else
#define getopt_long(argc, argv, optstring, longopts, longindex) \ #define getopt_long(argc, argv, optstring, longopts, longindex) \
getopt((argc), (argv), (optstring)) getopt((argc), (argv), (optstring))
#endif #endif
static const char optstring[] = "vr:c:a:?"; static const char optstring[] = "vr:c:a:p:?";
/* byte swap functions */ /* byte swap functions */
static inline int host_is_little_endian(void) static inline int host_is_little_endian(void)
@@ -112,10 +114,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 +128,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 +211,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 +219,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");
@@ -464,6 +466,9 @@ int main(int argc, char *argv[])
struct sockaddr_can saddr; struct sockaddr_can saddr;
uint64_t cmd_name; uint64_t cmd_name;
#ifdef _GNU_SOURCE
program_invocation_name = program_invocation_short_name;
#endif
/* argument parsing */ /* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1) while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) { switch (opt) {
@@ -479,6 +484,15 @@ int main(int argc, char *argv[])
case 'a': case 'a':
s.current_sa = strtoul(optarg, 0, 0); s.current_sa = strtoul(optarg, 0, 0);
break; break;
case 'p':
#ifdef _GNU_SOURCE
if (asprintf(&program_invocation_name, "%s.%s",
program_invocation_short_name, optarg) < 0)
err(1, "asprintf(program invocation name)");
#else
err(0, "compile with -D_GNU_SOURCE to use -p");
#endif
break;
default: default:
fputs(help_msg, stderr); fputs(help_msg, stderr);
exit(1); exit(1);
+29 -20
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 {
@@ -97,8 +97,17 @@ 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 void j1939cat_init_sockaddr_can(struct sockaddr_can *sac)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = J1939_NO_PGN;
}
static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd, 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 +141,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 +149,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 +235,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 +347,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 +420,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 +626,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 +642,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)))
@@ -757,8 +766,8 @@ int main(int argc, char *argv[])
priv->polltimeout = 100000; priv->polltimeout = 100000;
priv->repeat = 1; priv->repeat = 1;
libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN); j1939cat_init_sockaddr_can(&priv->sockname);
libj1939_init_sockaddr_can(&priv->peername, J1939_NO_PGN); j1939cat_init_sockaddr_can(&priv->peername);
ret = j1939cat_parse_args(priv, argc, argv); ret = j1939cat_parse_args(priv, argc, argv);
if (ret) if (ret)
+4 -4
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));
+6 -3
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,
@@ -94,6 +94,9 @@ int main(int argc, char **argv)
struct pollfd pfd[2]; struct pollfd pfd[2];
uint8_t *buf; uint8_t *buf;
#ifdef _GNU_SOURCE
program_invocation_name = program_invocation_short_name;
#endif
/* argument parsing */ /* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1) while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) { switch (opt) {
+32 -39
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)
@@ -155,7 +154,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen)
return 0; return 0;
} }
int parse_canframe(char *cs, union cfu *cu) int parse_canframe(char *cs, cu_t *cu)
{ {
/* documentation see lib.h */ /* documentation see lib.h */
@@ -170,23 +169,21 @@ int parse_canframe(char *cs, union cfu *cu)
memset(cu, 0, sizeof(*cu)); /* init CAN CC/FD/XL frame, e.g. LEN = 0 */ memset(cu, 0, sizeof(*cu)); /* init CAN CC/FD/XL frame, e.g. LEN = 0 */
if (len >= 4 && cs[3] == CANID_DELIM) { /* 3 digits SFF CAN ID */ if (len < 4)
return 0;
idx = 4; /* start of frame data */ if (cs[3] == CANID_DELIM) { /* 3 digits SFF */
/* get 3 digits SFF CAN ID value */ idx = 4;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if ((tmp = asc2nibble(cs[i])) > 0x0F) if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0; return 0;
cu->cc.can_id |= tmp << (2 - i) * 4; cu->cc.can_id |= tmp << (2 - i) * 4;
} }
} else if (len >= 21 && cs[5] == CANID_DELIM && cs[20] == CANID_DELIM) { } else if (cs[5] == CANID_DELIM) { /* 5 digits CAN XL VCID/PRIO*/
/* 5 digits CAN XL VCID/PRIO - but also check for 2nd '#' here */
idx = 6; /* start of CAN XL frame extra content (AF, SDT, etc) */ idx = 6;
/* get 5 digits CAN XL VCID/PRIO */
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
if ((tmp = asc2nibble(cs[i])) > 0x0F) if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0; return 0;
@@ -198,11 +195,9 @@ int parse_canframe(char *cs, union cfu *cu)
cu->xl.prio &= CANXL_PRIO_MASK; cu->xl.prio &= CANXL_PRIO_MASK;
cu->xl.prio |= tmp; cu->xl.prio |= tmp;
} else if (len >= 9 && cs[8] == CANID_DELIM) { /* 8 digits EFF CAN ID */ } else if (cs[8] == CANID_DELIM) { /* 8 digits EFF */
idx = 9; /* start of frame data */ idx = 9;
/* get 8 digits EFF CAN ID value */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if ((tmp = asc2nibble(cs[i])) > 0x0F) if ((tmp = asc2nibble(cs[i])) > 0x0F)
return 0; return 0;
@@ -243,12 +238,11 @@ int parse_canframe(char *cs, union cfu *cu)
cu->fd.flags |= CANFD_FDF; /* dual-use */ cu->fd.flags |= CANFD_FDF; /* dual-use */
idx += 2; idx += 2;
} else if (idx == 6) { /* CAN XL frame extra content '#80:00:11223344#' */ } else if (cs[idx + 14] == CANID_DELIM) { /* CAN XL frame '#80:00:11223344#' */
maxdlen = CANXL_MAX_DLEN; maxdlen = CANXL_MAX_DLEN;
mtu = CANXL_MTU; mtu = CANXL_MTU;
data = cu->xl.data; /* overwrite pointer to CAN XL data */ data = cu->xl.data; /* fill CAN XL data */
/* get CAN XL frame extra content */
if ((cs[idx + 2] != XL_HDR_DELIM) || (cs[idx + 5] != XL_HDR_DELIM)) if ((cs[idx + 2] != XL_HDR_DELIM) || (cs[idx + 5] != XL_HDR_DELIM))
return 0; return 0;
@@ -282,7 +276,6 @@ int parse_canframe(char *cs, union cfu *cu)
idx++; /* skip CANID_DELIM */ idx++; /* skip CANID_DELIM */
} }
/* copy CAN frame data content */
for (i = 0, dlen = 0; i < maxdlen; i++) { for (i = 0, dlen = 0; i < maxdlen; i++) {
if (cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */ if (cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */
idx++; idx++;
@@ -315,7 +308,7 @@ int parse_canframe(char *cs, union cfu *cu)
return mtu; return mtu;
} }
int snprintf_canframe(char *buf, size_t size, union cfu *cu, int sep) int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep)
{ {
/* documentation see lib.h */ /* documentation see lib.h */
@@ -439,7 +432,7 @@ int snprintf_canframe(char *buf, size_t size, union cfu *cu, int sep)
return offset; return offset;
} }
int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view) int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view)
{ {
/* documentation see lib.h */ /* documentation see lib.h */
@@ -784,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;
@@ -800,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))
@@ -826,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;
@@ -865,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)
@@ -885,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;
+5 -7
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
@@ -59,11 +57,11 @@ static inline int pr_debug(const char* fmt, ...) {return 0;}
#endif #endif
/* CAN CC/FD/XL frame union */ /* CAN CC/FD/XL frame union */
union cfu { typedef union {
struct can_frame cc; struct can_frame cc;
struct canfd_frame fd; struct canfd_frame fd;
struct canxl_frame xl; struct canxl_frame xl;
}; } cu_t;
/* /*
* The buffer size for ASCII CAN frame string representations * The buffer size for ASCII CAN frame string representations
@@ -110,7 +108,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen);
* *
*/ */
int parse_canframe(char *cs, union cfu *cu); int parse_canframe(char *cs, cu_t *cu);
/* /*
* Transfers a valid ASCII string describing a CAN frame into the CAN union * Transfers a valid ASCII string describing a CAN frame into the CAN union
* containing CAN CC/FD/XL structs. * containing CAN CC/FD/XL structs.
@@ -180,7 +178,7 @@ int parse_canframe(char *cs, union cfu *cu);
* - CAN FD frames do not have a RTR bit * - CAN FD frames do not have a RTR bit
*/ */
int snprintf_canframe(char *buf, size_t size, union cfu *cu, int sep); int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep);
/* /*
* Creates a CAN frame hexadecimal output in compact format. * Creates a CAN frame hexadecimal output in compact format.
* The CAN data[] is separated by '.' when sep != 0. * The CAN data[] is separated by '.' when sep != 0.
@@ -213,7 +211,7 @@ int snprintf_canframe(char *buf, size_t size, union cfu *cu, int sep);
#define SWAP_DELIMITER '`' #define SWAP_DELIMITER '`'
int snprintf_long_canframe(char *buf, size_t size, union cfu *cu, int view); int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view);
/* /*
* Creates a CAN frame hexadecimal output in user readable format. * Creates a CAN frame hexadecimal output in user readable format.
* *
+5 -264
View File
@@ -11,24 +11,19 @@
*/ */
#include <err.h> #include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <linux/kernel.h>
#include <net/if.h>
#include <net/if.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include <net/if.h>
#include "libj1939.h" #include "libj1939.h"
#include "lib.h"
/* static data */ /* static data */
static struct if_nameindex *saved; static struct if_nameindex *saved;
@@ -200,257 +195,3 @@ const char *libj1939_addr2str(const struct sockaddr_can *can)
return buf; return buf;
} }
void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = pgn;
}
/**
* libj1939_open_socket - Open a new J1939 socket
*
* This function opens a new J1939 socket.
*
* Return: The file descriptor of the new socket, or a negative error code.
*/
int libj1939_open_socket(void)
{
int ret;
/* Create a new CAN J1939 socket */
ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (ret < 0) {
/* Get the error code and print an error message */
ret = -errno;
pr_err("socket(j1939): %d (%s)", ret, strerror(ret));
return ret;
}
return ret;
}
/**
* libj1939_bind_socket - Bind a J1939 socket to a specific address
* @sock: The file descriptor of the socket
* @addr: The address to bind to
*
* This function binds a J1939 socket to a specific address.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_bind_socket(int sock, struct sockaddr_can *addr)
{
int ret;
ret = bind(sock, (void *)addr, sizeof(*addr));
if (ret < 0) {
ret = -errno;
pr_err("failed to bind: %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_connect_socket - Connects a socket to a CAN address.
* @sock: The socket file descriptor.
* @addr: The CAN address to connect to.
*
* This function attempts to establish a connection between the given socket
* and the specified CAN address. If the connection fails, it logs an error
* message with the error code and a description of the error.
*
* Return: 0 on success, or a negative error code on failure.
*/
int libj1939_connect_socket(int sock, struct sockaddr_can *addr)
{
int ret;
ret = connect(sock, (void *)addr, sizeof(*addr));
if (ret < 0) {
ret = -errno;
pr_err("failed to connect socket: %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_socket_prio - Set the priority of a J1939 socket
* @sock: The file descriptor of the socket
* @prio: The priority to set
*
* This function sets the priority of a J1939 socket.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_socket_prio(int sock, int prio)
{
int ret;
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&prio, sizeof(prio));
if (ret < 0) {
ret = -errno;
pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret,
strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_set_broadcast - Enable broadcast on a J1939 socket
* @sock: The file descriptor of the socket
*
* This function enables broadcast on a J1939 socket.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_set_broadcast(int sock)
{
int broadcast = true;
int ret;
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast));
if (ret < 0) {
ret = -errno;
pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_add_socket_to_epoll - Add a socket to an epoll instance
* @epoll_fd: The file descriptor of the epoll instance
* @sock: The file descriptor of the socket
* @events: The events to monitor
*
* This function adds a socket to an epoll instance.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events)
{
struct epoll_event ev = {0};
int ret;
ev.events = events;
ev.data.fd = sock;
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
if (ret < 0) {
ret = errno;
pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_create_epoll - Create a new epoll instance
*
* This function creates a new epoll instance.
*
* Return: The file descriptor of the new epoll instance, or a negative error
* code.
*/
int libj1939_create_epoll(void)
{
int ret, epoll_fd;
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
ret = -errno;
pr_err("epoll_create1: %d (%s)", ret, strerror(ret));
return ret;
}
return epoll_fd;
}
/**
* libj1939_get_timeout_ms - Get the timeout in milliseconds until a specific
* time
* @ts: The time to wait for
* @return: The timeout in milliseconds until the specified time
*
* This function calculates the timeout in milliseconds until a specific time.
*
* Return: The timeout in milliseconds until the specified time.
*/
static int libj1939_get_timeout_ms(struct timespec *ts)
{
struct timespec curr_time;
int64_t time_diff;
int timeout_ms;
clock_gettime(CLOCK_MONOTONIC, &curr_time);
time_diff = timespec_diff_ms(ts, &curr_time);
if (time_diff < 0) {
/* Too late to send next message. Send it now */
timeout_ms = 0;
} else {
if (time_diff > INT_MAX) {
pr_warn("timeout too long: %" PRId64 " ms", time_diff);
time_diff = INT_MAX;
}
timeout_ms = time_diff;
}
return timeout_ms;
}
/**
* libj1939_prepare_for_events - Prepare and wait for events on an epoll
* @cmn: The common J1939 instance data
* @nfds: The number of file descriptors that are ready
* @dont_wait: Don't wait for events, just check if there are any
*
* This function calculates the timeout until the next message should be sent
* or any other event should be handled, prepares the epoll instance for events
* by waiting for the specified timeout or until an event occurs, and waits for
* events on the epoll instance.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds,
bool dont_wait)
{
int ret, timeout_ms;
if (dont_wait)
timeout_ms = 0;
else
timeout_ms = libj1939_get_timeout_ms(&cmn->next_send_time);
ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events,
cmn->epoll_events_size, timeout_ms);
if (ret < 0) {
ret = -errno;
if (ret != -EINTR) {
*nfds = 0;
return ret;
}
}
*nfds = ret;
ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time);
if (ret < 0) {
ret = -errno;
pr_err("failed to get time: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
+1 -25
View File
@@ -13,12 +13,9 @@
/* needed on some 64 bit platforms to get consistent 64-bit types */ /* needed on some 64 bit platforms to get consistent 64-bit types */
#define __SANE_USERSPACE_TYPES__ #define __SANE_USERSPACE_TYPES__
#include <sys/socket.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/j1939.h> #include <linux/can/j1939.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#include <sys/socket.h>
#ifndef J1939_LIB_H #ifndef J1939_LIB_H
#define J1939_LIB_H #define J1939_LIB_H
@@ -27,31 +24,10 @@
extern "C" { extern "C" {
#endif #endif
struct libj1939_cmn {
int epoll_fd;
struct epoll_event *epoll_events;
size_t epoll_events_size;
struct timespec next_send_time;
struct timespec last_time;
};
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr); void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr);
extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can); extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can);
extern const char *libj1939_addr2str(const struct sockaddr_can *can); extern const char *libj1939_addr2str(const struct sockaddr_can *can);
void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
int libj1939_open_socket(void);
int libj1939_bind_socket(int sock, struct sockaddr_can *addr);
int libj1939_connect_socket(int sock, struct sockaddr_can *addr);
int libj1939_socket_prio(int sock, int prio);
int libj1939_set_broadcast(int sock);
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);
int libj1939_create_epoll(void);
int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds,
bool dont_wait);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+31 -162
View File
@@ -54,15 +54,6 @@
#include "lib.h" #include "lib.h"
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
#define ASC_F_XLF 0x00400000
#define ASC_F_RES 0x00800000
#define ASC_F_SEC 0x01000000
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
static void print_usage(char *prg) static void print_usage(char *prg)
@@ -74,17 +65,18 @@ static void print_usage(char *prg)
fprintf(stderr, " -O <outfile> (default stdout)\n"); fprintf(stderr, " -O <outfile> (default stdout)\n");
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n"); fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n"); fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
fprintf(stderr, " -f (use CANFD format also for CAN CC)\n"); fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n");
fprintf(stderr, " -x (use CANXL format also for CAN CC/FD)\n");
fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n"); fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n");
} }
static void can_asc(struct can_frame *cf, int devno, int nortrdlc, static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
char *extra_info, FILE *outfile) char *extra_info, FILE *outfile)
{ {
unsigned int i, dlc; int i;
char id[10]; char id[10];
char *dir = "Rx"; char *dir = "Rx";
int dlc;
struct can_frame *cf = (struct can_frame *)cfd; /* for len8_dlc */
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */ fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
@@ -101,7 +93,7 @@ static void can_asc(struct can_frame *cf, int devno, int nortrdlc,
dir = "Tx"; dir = "Tx";
} }
fprintf(outfile, "%-15s %-4s ", id, dir); fprintf(outfile, "%-15s %s ", id, dir);
if (cf->len == CAN_MAX_DLC && if (cf->len == CAN_MAX_DLC &&
cf->len8_dlc > CAN_MAX_DLC && cf->len8_dlc > CAN_MAX_DLC &&
@@ -128,13 +120,19 @@ static void can_asc(struct can_frame *cf, int devno, int nortrdlc,
static void canfd_asc(struct canfd_frame *cf, int devno, int mtu, static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
char *extra_info, FILE *outfile) char *extra_info, FILE *outfile)
{ {
unsigned int i; int i;
char id[10]; char id[10];
char *dir = "Rx"; char *dir = "Rx";
unsigned int flags = 0; unsigned int flags = 0;
unsigned int dlen = cf->len; unsigned int dlen = cf->len;
unsigned int dlc = can_fd_len2dlc(dlen); unsigned int dlc = can_fd_len2dlc(dlen);
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
/* check for extra info */ /* check for extra info */
if (strlen(extra_info) > 0) { if (strlen(extra_info) > 0) {
/* only the first char is defined so far */ /* only the first char is defined so far */
@@ -142,7 +140,7 @@ static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
dir = "Tx"; dir = "Tx";
} }
fprintf(outfile, "CANFD %3d %-4s ", devno, dir); /* 3 column channel number right aligned */ fprintf(outfile, "CANFD %3d %s ", devno, dir); /* 3 column channel number right aligned */
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK, sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
(cf->can_id & CAN_EFF_FLAG)?'x':' '); (cf->can_id & CAN_EFF_FLAG)?'x':' ');
@@ -176,127 +174,16 @@ static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
fprintf(outfile, "%2d", dlen); fprintf(outfile, "%2d", dlen);
for (i = 0; i < dlen; i++) { for (i = 0; i < (int)dlen; i++) {
fprintf(outfile, " %02X", cf->data[i]); fprintf(outfile, " %02X", cf->data[i]);
} }
fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags); fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags);
} }
static void canxl_asc(union cfu *cu, int devno, int mtu,
char *extra_info, FILE *outfile)
{
char id[10];
char *dir = "Rx";
char *frametype;
unsigned char *dataptr;
unsigned int i, dlen, dlc, flags = 0;
/* check for extra info */
if (strlen(extra_info) > 0) {
/* only the first char is defined so far */
if (extra_info[0] == 'T')
dir = "Tx";
}
switch (mtu) {
case CANXL_MTU:
sprintf(id, "%X", cu->xl.prio & CANXL_PRIO_MASK);
frametype = "XLFF";
dataptr = &cu->xl.data[0];
dlen = cu->xl.len;
dlc = dlen - 1;
flags = (ASC_F_XLF | ASC_F_FDF | ASC_F_BRS);
if (cu->xl.flags & CANXL_SEC)
flags |= ASC_F_SEC;
if (cu->xl.flags & CANXL_RRS)
flags |= ASC_F_RES;
break;
case CANFD_MTU:
if (cu->fd.can_id & CAN_EFF_FLAG) {
sprintf(id, "%Xx", cu->fd.can_id & CAN_EFF_MASK);
frametype = "FEFF";
} else {
sprintf(id, "%X", cu->fd.can_id & CAN_SFF_MASK);
frametype = "FBFF";
}
dataptr = &cu->fd.data[0];
dlen = cu->fd.len;
dlc = can_fd_len2dlc(dlen);
flags = ASC_F_FDF;
if (cu->fd.flags & CANFD_BRS)
flags |= ASC_F_BRS;
if (cu->fd.flags & CANFD_ESI)
flags |= ASC_F_ESI;
break;
case CAN_MTU:
if (cu->cc.can_id & CAN_EFF_FLAG) {
sprintf(id, "%Xx", cu->cc.can_id & CAN_EFF_MASK);
frametype = "CEFF";
} else {
sprintf(id, "%X", cu->cc.can_id & CAN_SFF_MASK);
frametype = "CBFF";
}
dataptr = &cu->cc.data[0];
dlen = cu->cc.len;
dlc = dlen ;
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((dlen == CAN_MAX_DLEN) && (cu->cc.len8_dlc > CAN_MAX_DLEN) &&
(cu->cc.len8_dlc <= CAN_MAX_RAW_DLC))
dlc = cu->cc.len8_dlc;
if (cu->cc.can_id & CAN_RTR_FLAG) {
/* no data length but dlc for RTR frames */
dlen = 0;
flags = ASC_F_RTR;
}
break;
default:
return;
}
fprintf(outfile, "CANXL %3d %-4s ", devno, dir); /* 3 column channel number and direction */
fprintf(outfile, "%s 984438 4656 ", frametype); /* frame type / msg duration / bit count */
fprintf(outfile, "%9s ", id); /* ID / symbolic name (empty) */
if (mtu == CANXL_MTU) /* SDT, SEC bit for CAN XL only */
fprintf(outfile, "%02x %d ", cu->xl.sdt, (cu->xl.flags & CANXL_SEC)?1:0);
fprintf(outfile, "%x %d", dlc, dlen); /* DLC and data length */
if (mtu == CANXL_MTU) /* SBC / PCRC / VCID / AF */
fprintf(outfile, " 1 1f96 %02x %08x",
(unsigned char)((cu->xl.prio >> CANXL_VCID_OFFSET) & CANXL_VCID_VAL_MASK),
cu->xl.af);
for (i = 0; i < dlen; i++) {
fprintf(outfile, " %02x", dataptr[i]);
}
if (mtu == CANFD_MTU) /* stuff field */
fprintf(outfile, " 8");
fprintf(outfile, " 123123 %08x %08x", flags, 0); /* fcsc, msg flags, msg flags ext */
fprintf(outfile, /* bitrate settings for CC/FD/XL */
" 000000050005000e 0000000000a00010"
" 0000000a000a001d 0000000000a00002"
" 000000100010000f 0000000000a00001");
}
#define DEVSZ 22 #define 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 */
@@ -314,15 +201,15 @@ int main(int argc, char **argv)
{ {
static char buf[BUFSZ], device[DEVSZ], afrbuf[AFRSZ], extra_info[EXTRASZ]; static char buf[BUFSZ], device[DEVSZ], afrbuf[AFRSZ], extra_info[EXTRASZ];
static union cfu cu; static cu_t cu;
static struct timeval tv, start_tv; static struct timeval tv, start_tv;
FILE *infile = stdin; FILE *infile = stdin;
FILE *outfile = stdout; FILE *outfile = stdout;
static int maxdev, devno, i, crlf, fdfmt, xlfmt, nortrdlc, d4, opt, mtu; static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu;
int print_banner = 1; int print_banner = 1;
unsigned long long sec, usec; unsigned long long sec, usec;
while ((opt = getopt(argc, argv, "I:O:4nfxr?")) != -1) { while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) {
switch (opt) { switch (opt) {
case 'I': case 'I':
infile = fopen(optarg, "r"); infile = fopen(optarg, "r");
@@ -348,10 +235,6 @@ int main(int argc, char **argv)
fdfmt = 1; fdfmt = 1;
break; break;
case 'x':
xlfmt = 1;
break;
case 'r': case 'r':
nortrdlc = 1; nortrdlc = 1;
break; break;
@@ -407,22 +290,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;
@@ -432,9 +300,6 @@ int main(int argc, char **argv)
(crlf)?"\r\n":"\n"); (crlf)?"\r\n":"\n");
fprintf(outfile, "no internal events logged%s", fprintf(outfile, "no internal events logged%s",
(crlf)?"\r\n":"\n"); (crlf)?"\r\n":"\n");
fprintf(outfile, "// version 18.2.0%s", (crlf)?"\r\n":"\n");
fprintf(outfile, "// Measurement UUID: cc9c7b54-68ae-"
"46d2-a43a-6aa87df7dd74%s", (crlf)?"\r\n":"\n");
} }
for (i = 0, devno = 0; i < maxdev; i++) { for (i = 0, devno = 0; i < maxdev; i++) {
@@ -448,8 +313,14 @@ int main(int argc, char **argv)
mtu = parse_canframe(afrbuf, &cu); mtu = parse_canframe(afrbuf, &cu);
/* no error message frames in non CAN CC frames */ /* convert only CAN CC and CAN FD frames */
if ((mtu != CAN_MTU) && (cu.cc.can_id & CAN_ERR_FLAG)) if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) {
printf("no valid CAN CC/FD frame\n");
return 1;
}
/* we don't support error message frames in CAN FD */
if ((mtu == CANFD_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
continue; continue;
tv.tv_sec = tv.tv_sec - start_tv.tv_sec; tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
@@ -464,12 +335,10 @@ int main(int argc, char **argv)
else else
fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec); fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec);
if ((mtu == CAN_MTU) && (fdfmt == 0) && (xlfmt == 0)) if ((mtu == CAN_MTU) && (fdfmt == 0))
can_asc(&cu.cc, devno, nortrdlc, extra_info, outfile); can_asc(&cu.fd, devno, nortrdlc, extra_info, outfile);
else if ((mtu != CANXL_MTU) && (xlfmt == 0))
canfd_asc(&cu.fd, devno, mtu, extra_info, outfile);
else else
canxl_asc(&cu, devno, mtu, extra_info, outfile); canfd_asc(&cu.fd, devno, mtu, extra_info, outfile);
if (crlf) if (crlf)
fprintf(outfile, "\r"); fprintf(outfile, "\r");
+4 -4
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,14 +61,14 @@
#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
int main(void) int main(void)
{ {
static char buf[BUFSZ], timestamp[TIMESZ], device[DEVSZ], afrbuf[AFRSZ]; static char buf[BUFSZ], timestamp[TIMESZ], device[DEVSZ], afrbuf[AFRSZ];
static union cfu cu; static cu_t cu;
int mtu; int mtu;
while (fgets(buf, BUFSZ-1, stdin)) { while (fgets(buf, BUFSZ-1, stdin)) {
@@ -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);
+2 -1
View File
@@ -72,7 +72,8 @@ int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
return 0; return 0;
/* maybe it's something like "spi0.0" */ /* maybe it's something like "spi0.0" */
if (strchr(file_path, '/')) tmp = strchr(file_path, '/');
if (tmp)
return -ENOENT; return -ENOENT;
/* first try literally */ /* first try literally */
+3 -8
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);
+6 -6
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);