mirror of
https://github.com/linux-can/can-utils.git
synced 2026-09-20 14:29:55 +02:00
Compare commits
250
Commits
v2020.02.0
...
v2021.06.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9dd86fa5c | ||
|
|
affdc1b799 | ||
|
|
a70801f1ce | ||
|
|
1b4e317083 | ||
|
|
f8a2cf01fa | ||
|
|
b88a64e9fc | ||
|
|
70eda640d5 | ||
|
|
fd6829eb4f | ||
|
|
4b94546cf9 | ||
|
|
aaa7fd215f | ||
|
|
553f0d282b | ||
|
|
9c2de072a0 | ||
|
|
5116452e6d | ||
|
|
bdf3e96ef9 | ||
|
|
02b330a87d | ||
|
|
d2f5b3dbe0 | ||
|
|
f11949b7d8 | ||
|
|
b1312a03f0 | ||
|
|
890dcc4735 | ||
|
|
cafc4bf748 | ||
|
|
1792aebd8b | ||
|
|
66de96d337 | ||
|
|
e8c90ddff9 | ||
|
|
fe07dc5837 | ||
|
|
913311fc15 | ||
|
|
ef8cea79f0 | ||
|
|
d72438243a | ||
|
|
3fc6c05ce2 | ||
|
|
dd315316d8 | ||
|
|
84bc52d6ff | ||
|
|
eb66451df2 | ||
|
|
682e01a40a | ||
|
|
280ea436d4 | ||
|
|
33de12680a | ||
|
|
bfaa44fa91 | ||
|
|
305b2e8b79 | ||
|
|
15f3a2e385 | ||
|
|
aa6411075f | ||
|
|
51d675368d | ||
|
|
639498bc80 | ||
|
|
333e631286 | ||
|
|
6a14256323 | ||
|
|
c3d9cc2027 | ||
|
|
972054446a | ||
|
|
6799180bd0 | ||
|
|
11edd1d05e | ||
|
|
a272fd2082 | ||
|
|
1ba0c576ae | ||
|
|
b70d8c050f | ||
|
|
c398e56afb | ||
|
|
d0ad168953 | ||
|
|
c3348ed51e | ||
|
|
856d0a662a | ||
|
|
ccfa3c8b00 | ||
|
|
a6cac755b4 | ||
|
|
86bfa25f9d | ||
|
|
4573e852f9 | ||
|
|
09466c2f1d | ||
|
|
eada3b4f53 | ||
|
|
cb5d2fd653 | ||
|
|
a726c2a57a | ||
|
|
a8131b7996 | ||
|
|
93ef09d9b0 | ||
|
|
677f9ec26f | ||
|
|
f3cf4cdf88 | ||
|
|
2afcbd2fee | ||
|
|
00134246c2 | ||
|
|
a1c20aeb45 | ||
|
|
d699135833 | ||
|
|
de5b9607dc | ||
|
|
36fc75bdb7 | ||
|
|
68d5f87889 | ||
|
|
4d50109a69 | ||
|
|
ac9124c776 | ||
|
|
0bcb5d9c2c | ||
|
|
1e0fb39e8b | ||
|
|
9567230494 | ||
|
|
985121aaad | ||
|
|
7975f9859c | ||
|
|
c9bb22022d | ||
|
|
2f125e44ce | ||
|
|
9841820ea0 | ||
|
|
fb5903f226 | ||
|
|
4aaad29082 | ||
|
|
a16f8ed471 | ||
|
|
6e3b123d5b | ||
|
|
c93d3a63c5 | ||
|
|
5fa35cbe2a | ||
|
|
f4cec293dc | ||
|
|
bd3ea25fe1 | ||
|
|
d8be4d8a4f | ||
|
|
b3b501d922 | ||
|
|
0c888d7942 | ||
|
|
ac8ae17727 | ||
|
|
3794644caa | ||
|
|
fc3b0449a9 | ||
|
|
c55d181360 | ||
|
|
d8435a56af | ||
|
|
204235c9ce | ||
|
|
d3b29dfa48 | ||
|
|
a591dadd96 | ||
|
|
5e713b3ee0 | ||
|
|
5d5ccf38ee | ||
|
|
bda4b0ad8c | ||
|
|
f766174677 | ||
|
|
7759b00c58 | ||
|
|
48bb69bc7b | ||
|
|
b153fe3f35 | ||
|
|
3e85fc5422 | ||
|
|
33f3593436 | ||
|
|
3e67b5cbd1 | ||
|
|
d5320d554e | ||
|
|
17a5fe6022 | ||
|
|
5a93509655 | ||
|
|
d7df79e687 | ||
|
|
18573d1dd2 | ||
|
|
8d2ed4c959 | ||
|
|
c27c61424f | ||
|
|
194959270f | ||
|
|
f6d963b5d9 | ||
|
|
485d813545 | ||
|
|
ce7f22928d | ||
|
|
dd8fb0b697 | ||
|
|
b7ba7f32fc | ||
|
|
b99f540039 | ||
|
|
7fb2585641 | ||
|
|
e1f75da433 | ||
|
|
435a59a394 | ||
|
|
73e421557f | ||
|
|
ea844bdc5e | ||
|
|
e6dfcb773e | ||
|
|
c43a168c68 | ||
|
|
7cb3e760fe | ||
|
|
a4905ed7c8 | ||
|
|
ab23c6f7e7 | ||
|
|
c912d6f8d5 | ||
|
|
58dc257e11 | ||
|
|
327587b2c8 | ||
|
|
659e0acfe6 | ||
|
|
88ad7e5755 | ||
|
|
112421dc22 | ||
|
|
dec3c5eda1 | ||
|
|
bad90515f0 | ||
|
|
da87d595c5 | ||
|
|
af531c3d52 | ||
|
|
8e3c050b1c | ||
|
|
a5c049d37a | ||
|
|
57949154cc | ||
|
|
24b73044c5 | ||
|
|
b29a75d4c6 | ||
|
|
0f9c69c193 | ||
|
|
13ecaa6d7e | ||
|
|
d7f28a0ffe | ||
|
|
e393697112 | ||
|
|
645cd1b1ba | ||
|
|
aa5386f1cb | ||
|
|
ff3d0e0d05 | ||
|
|
29605e3314 | ||
|
|
d92adf68e8 | ||
|
|
063e361cc5 | ||
|
|
e9e1a02085 | ||
|
|
19b3ffe34b | ||
|
|
6553ccaf06 | ||
|
|
1b5d3adbe5 | ||
|
|
e15b044a1d | ||
|
|
669fa79b21 | ||
|
|
75d9c7e95f | ||
|
|
85ae5aaecf | ||
|
|
1f5c9638ab | ||
|
|
1d3125bef2 | ||
|
|
62f995601e | ||
|
|
647210ee1c | ||
|
|
eac93ced80 | ||
|
|
da42cf4bb5 | ||
|
|
43610bd621 | ||
|
|
46895a41c5 | ||
|
|
2c87dcf468 | ||
|
|
8df3d1dd3f | ||
|
|
255e360233 | ||
|
|
d91288f754 | ||
|
|
9b75c6020f | ||
|
|
41c8ead6c0 | ||
|
|
3bb659d18d | ||
|
|
9cde2ebe8f | ||
|
|
7729c046c5 | ||
|
|
61dbb56ef6 | ||
|
|
3014d390b4 | ||
|
|
ad9fc28f9e | ||
|
|
9a079942cd | ||
|
|
ed9c646608 | ||
|
|
df0b25c17e | ||
|
|
3c8197e4d1 | ||
|
|
43a3cca54d | ||
|
|
becc0fc6cc | ||
|
|
c5cb7e1a7c | ||
|
|
729e346d31 | ||
|
|
7575d43fd2 | ||
|
|
2a8867f3cb | ||
|
|
ab2e8ffe0e | ||
|
|
ac55db508a | ||
|
|
64e33bf9ad | ||
|
|
adf29573f4 | ||
|
|
bd6ef44321 | ||
|
|
6d112a7209 | ||
|
|
6f44582c19 | ||
|
|
507ff82d81 | ||
|
|
1665abf46f | ||
|
|
853989bed2 | ||
|
|
f3ced10007 | ||
|
|
819a03f6e2 | ||
|
|
e266422c54 | ||
|
|
5ca66d7bea | ||
|
|
d007263021 | ||
|
|
f91b537c01 | ||
|
|
b43d1b4d27 | ||
|
|
f638cdc79b | ||
|
|
d89b38de8a | ||
|
|
d39cb046d1 | ||
|
|
9e491bc553 | ||
|
|
09f6dc6d17 | ||
|
|
8e6c11128d | ||
|
|
276688f2ad | ||
|
|
0155472ee0 | ||
|
|
211c5cea49 | ||
|
|
c1fdfb09fc | ||
|
|
506252e9bc | ||
|
|
89c66aba5f | ||
|
|
c61c9bc030 | ||
|
|
9240ccfcb7 | ||
|
|
3d6a53550e | ||
|
|
1cf4d86874 | ||
|
|
4db63e4b55 | ||
|
|
24af048812 | ||
|
|
4568d4a180 | ||
|
|
3e2c1d3cbd | ||
|
|
65399166c1 | ||
|
|
1127609357 | ||
|
|
f503097a38 | ||
|
|
c56259ab33 | ||
|
|
6db632531d | ||
|
|
f4a9e5b57d | ||
|
|
69865c8247 | ||
|
|
b740fb7fab | ||
|
|
bceadb8696 | ||
|
|
eb639c1b3d | ||
|
|
6cdccbbafc | ||
|
|
8106214b55 | ||
|
|
da65fdfe0d | ||
|
|
ae69062657 | ||
|
|
506f6f3043 |
+7
-4
@@ -20,6 +20,7 @@ GNUmakefile.in
|
||||
/config/m4/ltsugar.m4
|
||||
/config/m4/ltversion.m4
|
||||
/config/m4/lt~obsolete.m4
|
||||
/mcp251xfd/.dirstamp
|
||||
|
||||
/asc2log
|
||||
/bcmserver
|
||||
@@ -32,6 +33,7 @@ GNUmakefile.in
|
||||
/canlogserver
|
||||
/canplayer
|
||||
/cansend
|
||||
/cansequence
|
||||
/cansniffer
|
||||
/isotpdump
|
||||
/isotpperf
|
||||
@@ -40,12 +42,13 @@ GNUmakefile.in
|
||||
/isotpserver
|
||||
/isotpsniffer
|
||||
/isotptun
|
||||
/jacd
|
||||
/jcat
|
||||
/jspy
|
||||
/jsr
|
||||
/j1939acd
|
||||
/j1939cat
|
||||
/j1939spy
|
||||
/j1939sr
|
||||
/log2asc
|
||||
/log2long
|
||||
/mcp251xfd-dump
|
||||
/slcan_attach
|
||||
/slcand
|
||||
/slcanpty
|
||||
|
||||
+64
-6
@@ -2,6 +2,9 @@ language: c
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# native
|
||||
|
||||
- env: test="x64 4.8.4 (make)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
@@ -27,7 +30,7 @@ matrix:
|
||||
before_script:
|
||||
- mkdir gcc_rel && cd gcc_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
script: make
|
||||
|
||||
- env: test="x64 5.0 (CMake clang)"
|
||||
os: linux
|
||||
@@ -36,7 +39,7 @@ matrix:
|
||||
before_script:
|
||||
- mkdir clang_rel && cd clang_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
script: make
|
||||
|
||||
- env: test="x64 5.0 (CMake clang - Ninja) Debug"
|
||||
os: linux
|
||||
@@ -45,15 +48,70 @@ matrix:
|
||||
before_script:
|
||||
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
|
||||
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
|
||||
script: ninja
|
||||
script: ninja
|
||||
|
||||
# ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (make)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (autotools)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 4.8.4 (CMake gcc)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
before_script:
|
||||
- mkdir gcc_rel && cd gcc_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (CMake clang)"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_rel && cd clang_rel
|
||||
- cmake ..
|
||||
script: make
|
||||
arch: ppc64le
|
||||
|
||||
- env: test="ppc64le 5.0 (CMake clang - Ninja) Debug"
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
|
||||
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
|
||||
script: ninja
|
||||
arch: ppc64le
|
||||
|
||||
# Android
|
||||
|
||||
- env: test="Android NDK (CMake)"
|
||||
os: linux
|
||||
language: android
|
||||
android:
|
||||
components:
|
||||
- build-tools-25.0.2
|
||||
install:
|
||||
components:
|
||||
- build-tools-25.0.2
|
||||
install:
|
||||
- echo y | sdkmanager "ndk-bundle"
|
||||
- echo y | sdkmanager "cmake;3.6.4111459"
|
||||
before_script:
|
||||
|
||||
+150
-2
@@ -1,6 +1,7 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
PRIVATE_LOCAL_CFLAGS := -O2 -g -W -Wall \
|
||||
-Wno-error=unused-parameter \
|
||||
-DSO_RXQ_OVFL=40 \
|
||||
-DPF_CAN=29 \
|
||||
-DAF_CAN=PF_CAN
|
||||
@@ -15,9 +16,104 @@ LOCAL_SRC_FILES := lib.c canframelen.c
|
||||
LOCAL_MODULE := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# j1939lib
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := libj1939.c
|
||||
LOCAL_MODULE := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#
|
||||
# j1939acd
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939acd.c
|
||||
LOCAL_MODULE := j1939acd
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939cat
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939cat.c
|
||||
LOCAL_MODULE := j1939cat
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939spy
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939spy.c
|
||||
LOCAL_MODULE := j1939spy
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# j1939sr
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := j1939sr.c
|
||||
LOCAL_MODULE := j1939sr
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# testj1939
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := testj1939.c
|
||||
LOCAL_MODULE := testj1939
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libj1939
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# candump
|
||||
#
|
||||
@@ -30,6 +126,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -45,6 +142,21 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# cansequence
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := cansequence.c
|
||||
LOCAL_MODULE := cansequence
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -59,10 +171,10 @@ LOCAL_MODULE := bcmserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
|
||||
#
|
||||
# can-calc-bit-timing
|
||||
#
|
||||
@@ -74,6 +186,7 @@ LOCAL_MODULE := can-calc-bit-timing
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -89,6 +202,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -103,6 +217,7 @@ LOCAL_MODULE := canfdtest
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -118,6 +233,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -132,6 +248,7 @@ LOCAL_MODULE := cangw
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -147,6 +264,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -162,6 +280,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -176,6 +295,7 @@ LOCAL_MODULE := cansniffer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -190,6 +310,7 @@ LOCAL_MODULE := isotpdump
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -204,6 +325,7 @@ LOCAL_MODULE := isotprecv
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -218,6 +340,7 @@ LOCAL_MODULE := isotpsend
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -232,6 +355,7 @@ LOCAL_MODULE := isotpserver
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -242,10 +366,11 @@ include $(BUILD_EXECUTABLE)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := isotpsniffer.c
|
||||
LOCAL_MODULE := isotpsniffer.c
|
||||
LOCAL_MODULE := isotpsniffer
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -260,6 +385,7 @@ LOCAL_MODULE := isotptun
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -274,6 +400,7 @@ LOCAL_MODULE := isotpperf
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -289,6 +416,23 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
#
|
||||
# asc2log
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := asc2log.c
|
||||
LOCAL_MODULE := asc2log
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -304,6 +448,7 @@ LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_STATIC_LIBRARIES := libcan
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -318,6 +463,7 @@ LOCAL_MODULE := slcan_attach
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -332,6 +478,7 @@ LOCAL_MODULE := slcand
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -346,5 +493,6 @@ LOCAL_MODULE := slcanpty
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
+15
-5
@@ -2,13 +2,15 @@ cmake_minimum_required(VERSION 3.3)
|
||||
|
||||
project(can-utils LANGUAGES C)
|
||||
|
||||
include (CheckSymbolExists)
|
||||
include (GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
|
||||
if(_GNU_SOURCE)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
endif()
|
||||
|
||||
@@ -31,15 +33,16 @@ set(PROGRAMS_CANLIB
|
||||
canlogserver
|
||||
canplayer
|
||||
cansend
|
||||
cansequence
|
||||
log2asc
|
||||
log2long
|
||||
)
|
||||
|
||||
set(PROGRAMS_J1939
|
||||
jacd
|
||||
jcat
|
||||
jspy
|
||||
jsr
|
||||
j1939acd
|
||||
j1939cat
|
||||
j1939spy
|
||||
j1939sr
|
||||
testj1939
|
||||
)
|
||||
|
||||
@@ -62,6 +65,13 @@ set(PROGRAMS
|
||||
slcanpty
|
||||
)
|
||||
|
||||
add_executable(mcp251xfd-dump
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c
|
||||
mcp251xfd/mcp251xfd-dump.c
|
||||
mcp251xfd/mcp251xfd-main.c
|
||||
mcp251xfd/mcp251xfd-regmap.c
|
||||
)
|
||||
|
||||
if(NOT ANDROID)
|
||||
list(APPEND PROGRAMS ${PROGRAMS_J1939})
|
||||
|
||||
|
||||
+23
-9
@@ -24,6 +24,7 @@ noinst_HEADERS = \
|
||||
include/linux/can/raw.h \
|
||||
include/linux/can/vxcan.h \
|
||||
include/linux/errqueue.h \
|
||||
include/linux/kernel.h \
|
||||
include/linux/net_tstamp.h \
|
||||
include/linux/netlink.h
|
||||
|
||||
@@ -38,6 +39,15 @@ libcan_la_SOURCES = \
|
||||
libj1939_la_SOURCES = \
|
||||
libj1939.c
|
||||
|
||||
mcp251xfd_dump_SOURCES = \
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c \
|
||||
mcp251xfd/mcp251xfd-dump-userspace.h \
|
||||
mcp251xfd/mcp251xfd-dump.c \
|
||||
mcp251xfd/mcp251xfd-dump.h \
|
||||
mcp251xfd/mcp251xfd-main.c \
|
||||
mcp251xfd/mcp251xfd-regmap.c \
|
||||
mcp251xfd/mcp251xfd.h
|
||||
|
||||
bin_PROGRAMS = \
|
||||
asc2log \
|
||||
bcmserver \
|
||||
@@ -50,6 +60,7 @@ bin_PROGRAMS = \
|
||||
canlogserver \
|
||||
canplayer \
|
||||
cansend \
|
||||
cansequence \
|
||||
cansniffer \
|
||||
isotpdump \
|
||||
isotpperf \
|
||||
@@ -58,21 +69,22 @@ bin_PROGRAMS = \
|
||||
isotpserver \
|
||||
isotpsniffer \
|
||||
isotptun \
|
||||
jacd \
|
||||
jcat \
|
||||
jspy \
|
||||
jsr \
|
||||
j1939acd \
|
||||
j1939cat \
|
||||
j1939spy \
|
||||
j1939sr \
|
||||
log2asc \
|
||||
log2long \
|
||||
mcp251xfd-dump \
|
||||
slcan_attach \
|
||||
slcand \
|
||||
slcanpty \
|
||||
testj1939
|
||||
|
||||
jacd_LDADD = libj1939.la
|
||||
jcat_LDADD = libj1939.la
|
||||
jspy_LDADD = libj1939.la
|
||||
jsr_LDADD = libj1939.la
|
||||
j1939acd_LDADD = libj1939.la
|
||||
j1939cat_LDADD = libj1939.la
|
||||
j1939spy_LDADD = libj1939.la
|
||||
j1939sr_LDADD = libj1939.la
|
||||
testj1939_LDADD = libj1939.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
@@ -81,7 +93,9 @@ EXTRA_DIST = \
|
||||
README.md \
|
||||
autogen.sh \
|
||||
can-j1939-kickstart.md \
|
||||
can-j1939.md
|
||||
can-j1939.md \
|
||||
mcp251xfd/99-devcoredump.rules \
|
||||
mcp251xfd/devcoredump
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
configure \
|
||||
|
||||
@@ -67,10 +67,10 @@ PROGRAMS_ISOTP := \
|
||||
isotptun
|
||||
|
||||
PROGRAMS_J1939 := \
|
||||
jacd \
|
||||
jcat \
|
||||
jspy \
|
||||
jsr \
|
||||
j1939acd \
|
||||
j1939cat \
|
||||
j1939spy \
|
||||
j1939sr \
|
||||
testj1939
|
||||
|
||||
PROGRAMS_SLCAN := \
|
||||
@@ -89,12 +89,14 @@ PROGRAMS := \
|
||||
candump \
|
||||
canfdtest \
|
||||
cangen \
|
||||
cansequence \
|
||||
canlogserver \
|
||||
canplayer \
|
||||
cansend \
|
||||
cansniffer \
|
||||
log2asc \
|
||||
log2long \
|
||||
mcp251xfd-dump \
|
||||
slcanpty
|
||||
|
||||
all: $(PROGRAMS)
|
||||
@@ -116,12 +118,13 @@ cangen.o: lib.h
|
||||
canlogserver.o: lib.h
|
||||
canplayer.o: lib.h
|
||||
cansend.o: lib.h
|
||||
cansequence.o: lib.h
|
||||
log2asc.o: lib.h
|
||||
log2long.o: lib.h
|
||||
jacd.o: libj1939.h
|
||||
jcat.o: libj1939.h
|
||||
jspy.o: libj1939.h
|
||||
jsr.o: libj1939.h
|
||||
j1939acd.o: libj1939.h
|
||||
j1939cat.o: libj1939.h
|
||||
j1939spy.o: libj1939.h
|
||||
j1939sr.o: libj1939.h
|
||||
testj1939.o: libj1939.h
|
||||
canframelen.o: canframelen.h
|
||||
|
||||
@@ -131,11 +134,15 @@ cangen: cangen.o lib.o
|
||||
canlogserver: canlogserver.o lib.o
|
||||
canplayer: canplayer.o lib.o
|
||||
cansend: cansend.o lib.o
|
||||
cansequence: cansequence.o lib.o
|
||||
log2asc: log2asc.o lib.o
|
||||
log2long: log2long.o lib.o
|
||||
jacd: jacd.o libj1939.o
|
||||
jcat: jcat.o libj1939.o
|
||||
jspy: jspy.o libj1939.o
|
||||
jsr: jsr.o libj1939.o
|
||||
j1939acd: j1939acd.o libj1939.o
|
||||
j1939cat: j1939cat.o libj1939.o
|
||||
j1939spy: j1939spy.o libj1939.o
|
||||
j1939sr: j1939sr.o libj1939.o
|
||||
testj1939: testj1939.o libj1939.o
|
||||
canbusload: canbusload.o canframelen.o
|
||||
|
||||
mcp251xfd-dump: mcp251xfd/mcp251xfd-dev-coredump.o mcp251xfd/mcp251xfd-dump.o mcp251xfd/mcp251xfd-main.o mcp251xfd/mcp251xfd-regmap.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
@@ -13,7 +13,8 @@ subsystem (aka SocketCAN):
|
||||
* canplayer : replay CAN logfiles
|
||||
* cansend : send a single frame
|
||||
* cangen : generate (random) CAN traffic
|
||||
* cansniffer : display CAN data content differences (just 11bit CAN IDs)
|
||||
* cansequence : send and check sequence of CAN frames with incrementing payload
|
||||
* cansniffer : display CAN data content differences
|
||||
|
||||
#### CAN access via IP sockets
|
||||
* canlogserver : log CAN frames from a remote/local host
|
||||
@@ -38,6 +39,16 @@ subsystem (aka SocketCAN):
|
||||
* isotpperf : ISO15765-2 protocol performance visualisation
|
||||
* isotptun : create a bi-directional IP tunnel on CAN via ISO-TP
|
||||
|
||||
#### J1939/ISOBus tools
|
||||
* j1939acd : address claim daemon
|
||||
* j1939cat : take a file and send and receive it over CAN
|
||||
* j1939spy : spy on J1939 messages using SOC_J1939
|
||||
* j1939sr : send/recv from stdin or to stdout
|
||||
* testj1939 : send/receive test packet
|
||||
|
||||
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)
|
||||
|
||||
#### Log file converters
|
||||
* asc2log : convert ASC logfile to compact CAN frame logfile
|
||||
* log2asc : convert compact CAN frame logfile to ASC logfile
|
||||
|
||||
@@ -42,44 +42,47 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define BUFLEN 400 /* CAN FD mode lines can be pretty long */
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - convert ASC logfile to compact CAN frame logfile.\n", prg);
|
||||
fprintf(stderr, "Usage: %s\n", prg);
|
||||
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "\t-I <infile>\t(default stdin)\n");
|
||||
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
|
||||
}
|
||||
|
||||
void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) {
|
||||
void prframe(FILE *file, struct timeval *tv, int dev, struct canfd_frame *cf, unsigned int max_dlen, char *extra_info) {
|
||||
|
||||
fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
|
||||
fprintf(file, "(%lu.%06lu) ", tv->tv_sec, tv->tv_usec);
|
||||
|
||||
if (dev > 0)
|
||||
fprintf(file, "can%d ", dev-1);
|
||||
else
|
||||
fprintf(file, "canX ");
|
||||
|
||||
/* no CAN FD support so far */
|
||||
fprint_canframe(file, (struct canfd_frame *)cf, "\n", 0, CAN_MAX_DLEN);
|
||||
fprint_canframe(file, cf, extra_info, 0, max_dlen);
|
||||
}
|
||||
|
||||
void get_can_id(struct can_frame *cf, char *idstring, int base) {
|
||||
void get_can_id(struct canfd_frame *cf, char *idstring, int base) {
|
||||
|
||||
if (idstring[strlen(idstring)-1] == 'x') {
|
||||
cf->can_id = CAN_EFF_FLAG;
|
||||
@@ -116,20 +119,239 @@ void calc_tv(struct timeval *tv, struct timeval *read_tv,
|
||||
tv->tv_usec += read_tv->tv_usec;
|
||||
}
|
||||
|
||||
if (tv->tv_usec > 1000000) {
|
||||
if (tv->tv_usec >= 1000000) {
|
||||
tv->tv_usec -= 1000000;
|
||||
tv->tv_sec++;
|
||||
}
|
||||
}
|
||||
|
||||
void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, int dplace, 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;
|
||||
char rtr;
|
||||
int dlc = 0;
|
||||
int data[8];
|
||||
char tmp1[BUFLEN];
|
||||
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
|
||||
char *extra_info;
|
||||
int i, items, found;
|
||||
|
||||
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
|
||||
|
||||
found = 0; /* found valid CAN frame ? */
|
||||
|
||||
if (base == 'h') { /* check for CAN frames with hexadecimal values */
|
||||
|
||||
items = sscanf(buf, "%lu.%lu %d %s %2s %c %d %x %x %x %x %x %x %x %x",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, dir, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]);
|
||||
|
||||
if ((items == dlc + 7 ) || /* data frame */
|
||||
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
|
||||
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
}
|
||||
|
||||
} else { /* check for CAN frames with decimal values */
|
||||
|
||||
items = sscanf(buf, "%lu.%lu %d %s %2s %c %d %d %d %d %d %d %d %d %d",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, dir, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]);
|
||||
|
||||
if ((items == dlc + 7 ) || /* data frame */
|
||||
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
|
||||
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
|
||||
if (dlc > CAN_MAX_DLC)
|
||||
return;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
cf.len = dlc;
|
||||
if (rtr == 'r')
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
else
|
||||
for (i = 0; i < dlc; i++)
|
||||
cf.data[i] = data[i] & 0xFFU;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, extra_info);
|
||||
fflush(outfile);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for ErrorFrames */
|
||||
if (sscanf(buf, "%lu.%lu %d %s",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec,
|
||||
&interface, tmp1) == 4) {
|
||||
|
||||
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
/* do not know more than 'Error' */
|
||||
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
||||
cf.len = CAN_ERR_DLC;
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, "\n");
|
||||
fflush(outfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace, 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 brs, esi, ctmp;
|
||||
unsigned int flags;
|
||||
int dlc, dlen = 0;
|
||||
char tmp1[BUFLEN];
|
||||
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
|
||||
char *extra_info;
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
/* The CANFD format is mainly in hex representation but <DataLength>
|
||||
and probably some content we skip anyway. Don't trust the docs! */
|
||||
|
||||
/* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \
|
||||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \
|
||||
100000 214 223040 80000000 46500250 460a0250 20011736 20010205 */
|
||||
|
||||
/* check for valid line without symbolic name */
|
||||
if (sscanf(buf, "%lu.%lu %*s %d %2s %s %hhx %hhx %x %d ",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
|
||||
|
||||
/* check for valid line with a symbolic name */
|
||||
if (sscanf(buf, "%lu.%lu %*s %d %2s %s %*s %hhx %hhx %x %d ",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
|
||||
|
||||
/* no valid CANFD format pattern */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for allowed (unsigned) value ranges */
|
||||
if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC) ||
|
||||
(brs > 1) || (esi > 1))
|
||||
return;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
/* don't trust ASCII content - sanitize data length */
|
||||
if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen)))
|
||||
return;
|
||||
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
|
||||
/* 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;
|
||||
|
||||
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 MessageDuration and MessageLength to get Flags value */
|
||||
if (sscanf(ptr, " %*x %*x %x ", &flags) != 1)
|
||||
return;
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
|
||||
if (flags & ASC_F_FDF) {
|
||||
dlen = CANFD_MAX_DLEN;
|
||||
if (flags & ASC_F_BRS)
|
||||
cf.flags |= CANFD_BRS;
|
||||
if (flags & ASC_F_ESI)
|
||||
cf.flags |= CANFD_ESI;
|
||||
} else {
|
||||
/* yes. The 'CANFD' format supports classic CAN content! */
|
||||
dlen = CAN_MAX_DLEN;
|
||||
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)) {
|
||||
struct can_frame *ccf = (struct can_frame *)&cf;
|
||||
|
||||
ccf->len8_dlc = dlc;
|
||||
}
|
||||
}
|
||||
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, dlen, extra_info);
|
||||
fflush(outfile);
|
||||
|
||||
/* No support for really strange CANFD ErrorFrames format m( */
|
||||
}
|
||||
|
||||
int get_date(struct timeval *tv, char *date) {
|
||||
|
||||
char ctmp[10];
|
||||
int itmp;
|
||||
|
||||
struct tm tms;
|
||||
unsigned int msecs = 0;
|
||||
|
||||
if (sscanf(date, "%9s %d %9s %9s %d", ctmp, &itmp, ctmp, ctmp, &itmp) == 5) {
|
||||
if (strcasestr(date, " pm ") != NULL) {
|
||||
/* assume EN/US date due to existing am/pm field */
|
||||
|
||||
if (!setlocale(LC_TIME, "en_US")) {
|
||||
@@ -137,29 +359,39 @@ int get_date(struct timeval *tv, char *date) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strptime(date, "%B %d %r %Y", &tms))
|
||||
return 1;
|
||||
if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) {
|
||||
/* The string might contain a milliseconds value which strptime()
|
||||
does not support. So we read the ms value into the year variable
|
||||
before parsing the real year value (hack) */
|
||||
if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms))
|
||||
return 1;
|
||||
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* assume DE date due to non existing am/pm field */
|
||||
|
||||
if (sscanf(date, "%9s %d %9s %d", ctmp, &itmp, ctmp, &itmp) != 4)
|
||||
return 1;
|
||||
|
||||
if (!setlocale(LC_TIME, "de_DE")) {
|
||||
fprintf(stderr, "Setting locale to 'de_DE' failed!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strptime(date, "%B %d %T %Y", &tms))
|
||||
return 1;
|
||||
if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) {
|
||||
/* The string might contain a milliseconds value which strptime()
|
||||
does not support. So we read the ms value into the year variable
|
||||
before parsing the real year value (hack) */
|
||||
if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms))
|
||||
return 1;
|
||||
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
|
||||
}
|
||||
}
|
||||
|
||||
//printf("h %d m %d s %d d %d m %d y %d\n",
|
||||
//tms.tm_hour, tms.tm_min, tms.tm_sec,
|
||||
|
||||
//printf("h %d m %d s %d ms %03d d %d m %d y %d\n",
|
||||
//tms.tm_hour, tms.tm_min, tms.tm_sec, msecs,
|
||||
//tms.tm_mday, tms.tm_mon+1, tms.tm_year+1900);
|
||||
|
||||
tv->tv_sec = mktime(&tms);
|
||||
tv->tv_usec = msecs * 1000;
|
||||
|
||||
if (tv->tv_sec < 0)
|
||||
return 1;
|
||||
@@ -169,24 +401,17 @@ int get_date(struct timeval *tv, char *date) {
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[100], tmp1[100], tmp2[100];
|
||||
char buf[BUFLEN], tmp1[BUFLEN], tmp2[BUFLEN];
|
||||
|
||||
FILE *infile = stdin;
|
||||
FILE *outfile = stdout;
|
||||
static int verbose;
|
||||
struct can_frame cf;
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
static struct timeval tmp_tv; /* tmp frame timestamp from ASC file */
|
||||
static struct timeval date_tv; /* date of the ASC file */
|
||||
static int dplace; /* decimal place 4, 5 or 6 or uninitialized */
|
||||
static char base; /* 'd'ec or 'h'ex */
|
||||
static char timestamps; /* 'a'bsolute or 'r'elative */
|
||||
|
||||
int interface;
|
||||
char rtr;
|
||||
int dlc = 0;
|
||||
int data[8];
|
||||
int i, found, opt;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:O:v?")) != -1) {
|
||||
switch (opt) {
|
||||
@@ -224,7 +449,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
while (fgets(buf, 99, infile)) {
|
||||
while (fgets(buf, BUFLEN-1, infile)) {
|
||||
|
||||
if (!dplace) { /* the representation of a valid CAN frame not known */
|
||||
|
||||
@@ -259,87 +484,35 @@ int main(int argc, char **argv)
|
||||
gettimeofday(&date_tv, NULL);
|
||||
}
|
||||
if (verbose)
|
||||
printf("date %ld => %s", date_tv.tv_sec, ctime(&date_tv.tv_sec));
|
||||
printf("date %lu => %s", date_tv.tv_sec, ctime(&date_tv.tv_sec));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for decimal places length in valid CAN frames */
|
||||
if (sscanf(buf, "%ld.%s %d ", &tv.tv_sec, tmp2, &i) == 3){
|
||||
dplace = strlen(tmp2);
|
||||
if (verbose)
|
||||
printf("decimal place %d, e.g. '%s'\n", dplace, tmp2);
|
||||
if (dplace < 4 || dplace > 6) {
|
||||
printf("invalid dplace %d (must be 4, 5 or 6)!\n", dplace);
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
if (sscanf(buf, "%lu.%s %s ", &tmp_tv.tv_sec, tmp2,
|
||||
tmp1) != 3)
|
||||
continue; /* dplace remains zero until first found CAN frame */
|
||||
}
|
||||
|
||||
dplace = strlen(tmp2);
|
||||
if (verbose)
|
||||
printf("decimal place %d, e.g. '%s'\n", dplace,
|
||||
tmp2);
|
||||
if (dplace < 4 || dplace > 6) {
|
||||
printf("invalid dplace %d (must be 4, 5 or 6)!\n",
|
||||
dplace);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* the representation of a valid CAN frame is known here */
|
||||
/* so try to get CAN frames and ErrorFrames and convert them */
|
||||
|
||||
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
|
||||
|
||||
found = 0; /* found valid CAN frame ? */
|
||||
|
||||
if (base == 'h') { /* check for CAN frames with hexadecimal values */
|
||||
|
||||
if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %x %x %x %x %x %x %x %x",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]
|
||||
) == dlc + 6 ) {
|
||||
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
}
|
||||
|
||||
} else { /* check for CAN frames with decimal values */
|
||||
|
||||
if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %d %d %d %d %d %d %d %d",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
|
||||
tmp1, &rtr, &dlc,
|
||||
&data[0], &data[1], &data[2], &data[3],
|
||||
&data[4], &data[5], &data[6], &data[7]
|
||||
) == dlc + 6 ) {
|
||||
|
||||
found = 1;
|
||||
get_can_id(&cf, tmp1, 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (rtr == 'r')
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
|
||||
cf.can_dlc = dlc & 0x0FU;
|
||||
for (i=0; i<dlc; i++)
|
||||
cf.data[i] = data[i] & 0xFFU;
|
||||
|
||||
calc_tv(&tv, &read_tv, &date_tv, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf);
|
||||
fflush(outfile);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for ErrorFrames */
|
||||
if (sscanf(buf, "%ld.%ld %d %s",
|
||||
&read_tv.tv_sec, &read_tv.tv_usec,
|
||||
&interface, tmp1) == 4) {
|
||||
|
||||
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
/* do not know more than 'Error' */
|
||||
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
||||
cf.can_dlc = CAN_ERR_DLC;
|
||||
|
||||
calc_tv(&tv, &read_tv, &date_tv, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf);
|
||||
fflush(outfile);
|
||||
}
|
||||
/* check classic CAN format or the CANFD tag which can take both types */
|
||||
if (sscanf(buf, "%lu.%lu %s ", &tmp_tv.tv_sec, &tmp_tv.tv_usec, tmp1) == 3){
|
||||
if (!strncmp(tmp1, "CANFD", 5))
|
||||
eval_canfd(buf, &date_tv, timestamps, dplace, outfile);
|
||||
else
|
||||
eval_can(buf, &date_tv, timestamps, base, dplace, outfile);
|
||||
}
|
||||
}
|
||||
fclose(outfile);
|
||||
|
||||
+17
-14
@@ -108,20 +108,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/bcm.h>
|
||||
@@ -135,7 +136,7 @@ void childdied(int i)
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(void)
|
||||
{
|
||||
|
||||
int sl, sa, sc;
|
||||
@@ -180,8 +181,12 @@ int main(int argc, char **argv)
|
||||
saddr.sin_port = htons(PORT);
|
||||
|
||||
while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
|
||||
printf(".");fflush(NULL);
|
||||
usleep(100000);
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
if (listen(sl,3) != 0) {
|
||||
@@ -192,11 +197,9 @@ int main(int argc, char **argv)
|
||||
while (1) {
|
||||
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
|
||||
if (sa > 0 ){
|
||||
|
||||
if (fork())
|
||||
close(sa);
|
||||
else
|
||||
if (!fork())
|
||||
break;
|
||||
close(sa);
|
||||
}
|
||||
else {
|
||||
if (errno != EINTR) {
|
||||
|
||||
+261
-74
@@ -2,7 +2,7 @@
|
||||
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
|
||||
*
|
||||
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
|
||||
* Copyright (C) 2016 Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
* Copyright (C) 2016, 2021 Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
*
|
||||
* Derived from:
|
||||
* can_baud.c - CAN baudrate calculation
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -25,8 +26,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
OPT_TQ = UCHAR_MAX + 1,
|
||||
OPT_PROP_SEG,
|
||||
OPT_PHASE_SEG1,
|
||||
OPT_PHASE_SEG2,
|
||||
OPT_SJW,
|
||||
OPT_BRP,
|
||||
OPT_TSEG1,
|
||||
OPT_TSEG2,
|
||||
};
|
||||
|
||||
/* imported from kernel */
|
||||
|
||||
@@ -131,17 +143,26 @@ static inline void *netdev_priv(const struct net_device *dev)
|
||||
|
||||
static void print_usage(char *cmd)
|
||||
{
|
||||
printf("%s - calculate CAN bit timing parameters.\n", cmd);
|
||||
printf("Usage: %s [options] [<CAN-contoller-name>]\n"
|
||||
"\tOptions:\n"
|
||||
"\t-q : don't print header line\n"
|
||||
"\t-l : list all support CAN controller names\n"
|
||||
"\t-b <bitrate> : bit-rate in bits/sec\n"
|
||||
"\t-s <samp_pt> : sample-point in one-tenth of a percent\n"
|
||||
"Options:\n"
|
||||
"\t-q don't print header line\n"
|
||||
"\t-l list all support CAN controller names\n"
|
||||
"\t-b <bitrate> bit-rate in bits/sec\n"
|
||||
"\t-s <samp_pt> sample-point in one-tenth of a percent\n"
|
||||
"\t or 0 for CIA recommended sample points\n"
|
||||
"\t-c <clock> : real CAN system clock in Hz\n",
|
||||
"\t-c <clock> real CAN system clock in Hz\n"
|
||||
"\n"
|
||||
"Or supply low level bit timing parameters to decode them:\n"
|
||||
"\n"
|
||||
"\t--prop-seg Propagation segment in TQs\n"
|
||||
"\t--phase-seg1 Phase buffer segment 1 in TQs\n"
|
||||
"\t--phase-seg2 Phase buffer segment 2 in TQs\n"
|
||||
"\t--sjw Synchronisation jump width in TQs\n"
|
||||
"\t--brp Bit-rate prescaler\n"
|
||||
"\t--tseg1 Time segment 1 = prop-seg + phase-seg1\n"
|
||||
"\t--tseg2 Time segment 2 = phase_seg2\n",
|
||||
cmd);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
|
||||
@@ -201,6 +222,19 @@ static void printf_btr_mcp251x(struct can_bittiming *bt, bool hdr)
|
||||
}
|
||||
}
|
||||
|
||||
static void printf_btr_mcp251xfd(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
if (hdr) {
|
||||
printf("NBTCFG");
|
||||
} else {
|
||||
uint32_t nbtcfg = ((bt->brp - 1) << 24) |
|
||||
((bt->prop_seg + bt->phase_seg1 - 1) << 16) |
|
||||
((bt->phase_seg2 - 1) << 8) |
|
||||
(bt->sjw - 1);
|
||||
printf("0x%08x", nbtcfg);
|
||||
}
|
||||
}
|
||||
|
||||
static void printf_btr_ti_hecc(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
if (hdr) {
|
||||
@@ -276,7 +310,6 @@ static struct calc_bittiming_const can_calc_consts[] = {
|
||||
{ .clk = 66660000, .name = "mpc5121", },
|
||||
{ .clk = 66666666, .name = "mpc5121" },
|
||||
},
|
||||
.printf_btr = printf_btr_sja1000,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "at91",
|
||||
@@ -329,10 +362,29 @@ static struct calc_bittiming_const can_calc_consts[] = {
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 8000000, },
|
||||
{ .clk = 16000000, },
|
||||
/* The mcp251x uses half of the external OSC clock as the base clock */
|
||||
{ .clk = 8000000 / 2, .name = "8 MHz OSC" },
|
||||
{ .clk = 16000000 / 2, .name = "16 MHz OSC" },
|
||||
{ .clk = 20000000 / 2, .name = "20 MHz OSC" },
|
||||
},
|
||||
.printf_btr = printf_btr_mcp251x,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "mcp251xfd",
|
||||
.tseg1_min = 2,
|
||||
.tseg1_max = 256,
|
||||
.tseg2_min = 1,
|
||||
.tseg2_max = 128,
|
||||
.sjw_max = 128,
|
||||
.brp_min = 1,
|
||||
.brp_max = 256,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 20000000, },
|
||||
{ .clk = 40000000, },
|
||||
},
|
||||
.printf_btr = printf_btr_mcp251xfd,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "ti_hecc",
|
||||
@@ -444,7 +496,7 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
unsigned int spt_nominal; /* nominal sample point */
|
||||
unsigned int best_tseg = 0; /* current best value for tseg */
|
||||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1, tseg2;
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
@@ -540,6 +592,46 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
int tseg1, alltseg;
|
||||
u64 brp64, v64;
|
||||
|
||||
tseg1 = bt->prop_seg + bt->phase_seg1;
|
||||
if (!bt->sjw)
|
||||
bt->sjw = 1;
|
||||
if (bt->sjw > btc->sjw_max ||
|
||||
tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
|
||||
bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
|
||||
return -ERANGE;
|
||||
|
||||
if (!bt->brp) {
|
||||
brp64 = (u64)priv->clock.freq * (u64)bt->tq;
|
||||
if (btc->brp_inc > 1)
|
||||
do_div(brp64, btc->brp_inc);
|
||||
brp64 += 500000000UL - 1;
|
||||
do_div(brp64, 1000000000UL); /* the practicable BRP */
|
||||
if (btc->brp_inc > 1)
|
||||
brp64 *= btc->brp_inc;
|
||||
bt->brp = brp64;
|
||||
}
|
||||
|
||||
v64 = bt->brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = v64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = CAN_CALC_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((CAN_CALC_SYNC_SEG + tseg1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __u32 get_cia_sample_point(__u32 bitrate)
|
||||
{
|
||||
__u32 sampl_pt;
|
||||
@@ -555,6 +647,7 @@ static __u32 get_cia_sample_point(__u32 bitrate)
|
||||
}
|
||||
|
||||
static void print_bit_timing(const struct calc_bittiming_const *btc,
|
||||
const struct can_bittiming *ref_bt,
|
||||
const struct calc_ref_clk *ref_clk,
|
||||
unsigned int bitrate_nominal,
|
||||
unsigned int spt_nominal,
|
||||
@@ -579,13 +672,23 @@ static void print_bit_timing(const struct calc_bittiming_const *btc,
|
||||
ref_clk->name ? ")" : "",
|
||||
ref_clk->clk / 1000000.0);
|
||||
|
||||
btc->printf_btr(&bt, true);
|
||||
if (btc->printf_btr)
|
||||
btc->printf_btr(&bt, true);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
|
||||
printf("%7d ***bitrate not possible***\n", bitrate_nominal);
|
||||
return;
|
||||
if (ref_bt) {
|
||||
bt = *ref_bt;
|
||||
|
||||
if (can_fixup_bittiming(&dev, &bt, &btc->bittiming_const)) {
|
||||
printf("%7d ***parameters exceed controller's range***\n", bitrate_nominal);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
|
||||
printf("%7d ***bitrate not possible***\n", bitrate_nominal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* get nominal sample point */
|
||||
@@ -595,23 +698,33 @@ static void print_bit_timing(const struct calc_bittiming_const *btc,
|
||||
rate_error = abs(bitrate_nominal - bt.bitrate);
|
||||
spt_error = abs(spt_nominal - bt.sample_point);
|
||||
|
||||
printf("%7d "
|
||||
"%6d %3d %4d %4d "
|
||||
"%3d %3d "
|
||||
"%7d %4.1f%% "
|
||||
"%4.1f%% %4.1f%% %4.1f%% ",
|
||||
printf("%7d " /* Bitrate */
|
||||
"%6d %3d %4d %4d " /* TQ[ns], PrS, PhS1, PhS2 */
|
||||
"%3d %3d " /* SJW, BRP */
|
||||
"%7d ", /* real Bitrate */
|
||||
bitrate_nominal,
|
||||
bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2,
|
||||
bt.sjw, bt.brp,
|
||||
bt.bitrate);
|
||||
|
||||
bt.bitrate,
|
||||
100.0 * rate_error / bitrate_nominal,
|
||||
if (100.0 * rate_error / bitrate_nominal > 99.9)
|
||||
printf("≥100%% ");
|
||||
else
|
||||
printf("%4.1f%% ",
|
||||
100.0 * rate_error / bitrate_nominal);
|
||||
|
||||
printf("%4.1f%% %4.1f%% ", /* nom SampP, real SampP */
|
||||
spt_nominal / 10.0,
|
||||
bt.sample_point / 10.0,
|
||||
100.0 * spt_error / spt_nominal);
|
||||
bt.sample_point / 10.0);
|
||||
|
||||
btc->printf_btr(&bt, false);
|
||||
if (100.0 * spt_error / spt_nominal > 99.9)
|
||||
printf("≥100%% ");
|
||||
else
|
||||
printf("%4.1f%% ", /* SampP Error */
|
||||
100.0 * spt_error / spt_nominal);
|
||||
|
||||
if (btc->printf_btr)
|
||||
btc->printf_btr(&bt, false);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -623,22 +736,81 @@ static void do_list(void)
|
||||
printf("%s\n", can_calc_consts[i].bittiming_const.name);
|
||||
}
|
||||
|
||||
static void do_calc(const char *name,
|
||||
const struct can_bittiming *opt_ref_bt,
|
||||
__u32 bitrate_nominal, unsigned int spt_nominal,
|
||||
struct calc_ref_clk *opt_ref_clk, bool quiet)
|
||||
{
|
||||
const struct calc_bittiming_const *btc;
|
||||
const struct calc_ref_clk *ref_clk;
|
||||
unsigned int i, j, k;
|
||||
bool found = false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
|
||||
if (name &&
|
||||
strcmp(can_calc_consts[i].bittiming_const.name, name) != 0)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
btc = &can_calc_consts[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) {
|
||||
if (opt_ref_clk)
|
||||
ref_clk = opt_ref_clk;
|
||||
else
|
||||
ref_clk = &btc->ref_clk[j];
|
||||
|
||||
if (!ref_clk->clk)
|
||||
break;
|
||||
|
||||
if (bitrate_nominal) {
|
||||
print_bit_timing(btc, opt_ref_bt, ref_clk, bitrate_nominal,
|
||||
spt_nominal, quiet);
|
||||
} else {
|
||||
for (k = 0; k < ARRAY_SIZE(common_bitrates); k++)
|
||||
print_bit_timing(btc, opt_ref_bt, ref_clk,
|
||||
common_bitrates[k],
|
||||
spt_nominal, k);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (opt_ref_clk)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
|
||||
do_list();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
__u32 bitrate_nominal = 0;
|
||||
unsigned int spt_nominal = 0;
|
||||
struct calc_ref_clk opt_ref_clk = {
|
||||
.name = "cmd-line",
|
||||
};
|
||||
const struct calc_ref_clk *ref_clk;
|
||||
unsigned int spt_nominal = 0;
|
||||
bool quiet = false, list = false, found = false;
|
||||
char *name = NULL;
|
||||
unsigned int i, j, k;
|
||||
struct can_bittiming bt = { 0 };
|
||||
bool quiet = false, list = false;
|
||||
const char *name = NULL;
|
||||
int opt;
|
||||
|
||||
const struct calc_bittiming_const *btc;
|
||||
const struct option long_options[] = {
|
||||
{ "tq", required_argument, 0, OPT_TQ, },
|
||||
{ "prop-seg", required_argument, 0, OPT_PROP_SEG, },
|
||||
{ "phase-seg1", required_argument, 0, OPT_PHASE_SEG1, },
|
||||
{ "phase-seg2", required_argument, 0, OPT_PHASE_SEG2, },
|
||||
{ "sjw", required_argument, 0, OPT_SJW, },
|
||||
{ "brp", required_argument, 0, OPT_BRP, },
|
||||
{ "tseg1", required_argument, 0, OPT_TSEG1, },
|
||||
{ "tseg2", required_argument, 0, OPT_TSEG2, },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:c:lqs:")) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "b:c:lqs:?", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bitrate_nominal = atoi(optarg);
|
||||
@@ -660,14 +832,59 @@ int main(int argc, char *argv[])
|
||||
spt_nominal = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
case OPT_TQ:
|
||||
bt.tq = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case OPT_PROP_SEG:
|
||||
bt.prop_seg = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case OPT_PHASE_SEG1:
|
||||
bt.phase_seg1 = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case OPT_PHASE_SEG2:
|
||||
bt.phase_seg2 = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case OPT_SJW:
|
||||
bt.sjw = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case OPT_BRP:
|
||||
bt.brp = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case OPT_TSEG1: {
|
||||
__u32 tseg1;
|
||||
|
||||
tseg1 = strtoul(optarg, NULL, 10);
|
||||
bt.prop_seg = tseg1 / 2;
|
||||
bt.phase_seg1 = tseg1 - bt.prop_seg;
|
||||
break;
|
||||
}
|
||||
|
||||
case OPT_TSEG2:
|
||||
bt.phase_seg2 = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind + 1)
|
||||
if (argc > optind + 1) {
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == optind + 1)
|
||||
name = argv[optind];
|
||||
@@ -677,46 +894,16 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100))
|
||||
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100)) {
|
||||
print_usage(argv[0]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
|
||||
if (name && strcmp(can_calc_consts[i].bittiming_const.name, name))
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
btc = &can_calc_consts[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) {
|
||||
if (opt_ref_clk.clk)
|
||||
ref_clk = &opt_ref_clk;
|
||||
else
|
||||
ref_clk = &btc->ref_clk[j];
|
||||
|
||||
if (!ref_clk->clk)
|
||||
break;
|
||||
|
||||
if (bitrate_nominal) {
|
||||
print_bit_timing(btc, ref_clk, bitrate_nominal,
|
||||
spt_nominal, quiet);
|
||||
} else {
|
||||
for (k = 0; k < ARRAY_SIZE(common_bitrates); k++)
|
||||
print_bit_timing(btc, ref_clk,
|
||||
common_bitrates[k],
|
||||
spt_nominal, k);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (opt_ref_clk.clk)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
|
||||
do_list();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
do_calc(name,
|
||||
bt.prop_seg ? &bt: NULL,
|
||||
bitrate_nominal, spt_nominal,
|
||||
opt_ref_clk.clk ? &opt_ref_clk : NULL,
|
||||
quiet);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# can-j1939 kernel module installation #
|
||||
|
||||
|
||||
|
||||
### Problem
|
||||
|
||||
You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939
|
||||
modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64
|
||||
```
|
||||
|
||||
and also this:
|
||||
|
||||
```bash
|
||||
avra@vm-debian:~/can/can-utils$ testj1939
|
||||
testj1939: socket(j1939): Protocol not supported
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Solution
|
||||
|
||||
Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine.
|
||||
|
||||
|
||||
|
||||
#### 1. Download kernel source ####
|
||||
|
||||
We will download Debian patched kernel 5.8. First update your sources
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ sudo apt update
|
||||
```
|
||||
|
||||
and then look at available Debian patched kernel source packages
|
||||
|
||||
```
|
||||
avra@vm-debian:~$ apt-cache search linux-source
|
||||
linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches
|
||||
linux-source - Linux kernel source (meta-package)
|
||||
linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches
|
||||
linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches
|
||||
linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches
|
||||
linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches
|
||||
linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches
|
||||
```
|
||||
|
||||
If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this
|
||||
|
||||
```
|
||||
echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list
|
||||
```
|
||||
|
||||
Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours)
|
||||
|
||||
```
|
||||
deb http://security.debian.org/debian-security buster/updates main contrib
|
||||
deb-src http://security.debian.org/debian-security buster/updates main contrib
|
||||
|
||||
deb http://deb.debian.org/debian/ buster main contrib non-free
|
||||
deb-src http://deb.debian.org/debian/ buster main contrib non-free
|
||||
|
||||
deb http://deb.debian.org/debian buster-backports main contrib
|
||||
```
|
||||
|
||||
After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package
|
||||
|
||||
```
|
||||
sudo apt install linux-source-5.8
|
||||
```
|
||||
|
||||
and unpack it
|
||||
```
|
||||
avra@vm-debian:~$ cd /usr/src
|
||||
avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz
|
||||
avra@vm-debian:/usr/src$ cd linux-source-5.8
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2. Add can-j1939 module to kernel ####
|
||||
|
||||
First we need some packages for **menuconfig**
|
||||
|
||||
```
|
||||
sudo apt-get install libncurses5 libncurses5-dev
|
||||
```
|
||||
|
||||
copy and use our old configuration to run **menuconfig**
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig
|
||||
```
|
||||
|
||||
where we enable SAE J1939 kernel module as shown
|
||||
|
||||
```
|
||||
- Networking Support
|
||||
- Can bus subsystem support
|
||||
- <M> SAE J1939
|
||||
```
|
||||
|
||||
Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following
|
||||
```
|
||||
CONFIG_SYSTEM_TRUSTED_KEYS=""
|
||||
```
|
||||
|
||||
and save the file.
|
||||
|
||||
|
||||
|
||||
#### 3. Compile and install kernel and modules
|
||||
|
||||
We will have to download necessary packages
|
||||
|
||||
```
|
||||
sudo apt install build-essential libssl-dev libelf-dev bison flex
|
||||
```
|
||||
|
||||
compile kernel (using threads to make it faster)
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc)
|
||||
```
|
||||
|
||||
install
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install
|
||||
```
|
||||
|
||||
and update grub
|
||||
|
||||
```
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub
|
||||
avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot
|
||||
```
|
||||
|
||||
Check if installation is correct with
|
||||
|
||||
```
|
||||
sudo modprobe can-j1939
|
||||
```
|
||||
|
||||
and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works:
|
||||
|
||||
```
|
||||
sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko
|
||||
```
|
||||
|
||||
If it does then all you need to do is
|
||||
|
||||
```
|
||||
sudo depmod -av
|
||||
```
|
||||
|
||||
reboot once, and **modprobe** command from the above should finally work.
|
||||
|
||||
|
||||
|
||||
#### 4. Install headers if needed
|
||||
|
||||
You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with
|
||||
|
||||
```
|
||||
nano /usr/include/linux/can.h
|
||||
```
|
||||
|
||||
If in the struct **sockaddr_can** you don’t see **j1939**, then header files did not upgrade and you need to do it manually
|
||||
|
||||
```
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h
|
||||
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/
|
||||
```
|
||||
|
||||
That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy!
|
||||
@@ -44,7 +44,7 @@ You should have this output in terminal 1
|
||||
40 02300: 01 23
|
||||
|
||||
This means, from NAME 0, SA 40, PGN 02300 was received,
|
||||
with 2 databytes, *01* & *02*.
|
||||
with 2 databytes, *01* & *23*.
|
||||
|
||||
now emit this CAN message:
|
||||
|
||||
|
||||
+21
-19
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* canbusload.c
|
||||
* canbusload.c - monitor CAN bus load
|
||||
*
|
||||
* Copyright (c) 2002-2008 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
@@ -42,21 +42,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -91,14 +91,16 @@ static char *prg;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - monitor CAN bus load.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
|
||||
fprintf(stderr, "Options: -t (show current time on the first line)\n");
|
||||
fprintf(stderr, " -c (colorize lines)\n");
|
||||
fprintf(stderr, " -b (show bargraph in %d%% resolution)\n", PERCENTRES);
|
||||
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
|
||||
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
|
||||
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -t (show current time on the first line)\n");
|
||||
fprintf(stderr, " -c (colorize lines)\n");
|
||||
fprintf(stderr, " -b (show bargraph in %d%% resolution)\n", PERCENTRES);
|
||||
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
|
||||
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
|
||||
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXSOCK);
|
||||
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>\n\n");
|
||||
@@ -107,7 +109,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
|
||||
fprintf(stderr, "For each given interface the data is presented in one line which contains:\n\n");
|
||||
fprintf(stderr, "(interface) (received CAN frames) (used bits total) (used bits for payload)\n");
|
||||
fprintf(stderr, "\nExample:\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000 can2@500000 can3@500000 -r -t -b -c\n\n");
|
||||
fprintf(stderr, "%s 2014-02-01 21:13:16 (worst case bitstuffing)\n", prg);
|
||||
fprintf(stderr, " can0@100000 805 74491 36656 74%% |XXXXXXXXXXXXXX......|\n");
|
||||
@@ -298,7 +300,7 @@ int main(int argc, char **argv)
|
||||
ptr = argv[optind+i];
|
||||
|
||||
nbytes = strlen(ptr);
|
||||
if (nbytes >= IFNAMSIZ+sizeof("@1000000")+1) {
|
||||
if (nbytes >= (int)(IFNAMSIZ+sizeof("@1000000")+1)) {
|
||||
printf("name of CAN device '%s' is too long!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
@@ -322,7 +324,7 @@ int main(int argc, char **argv)
|
||||
|
||||
nbytes = nptr - ptr; /* interface name is up the first '@' */
|
||||
|
||||
if (nbytes >= IFNAMSIZ) {
|
||||
if (nbytes >= (int)IFNAMSIZ) {
|
||||
printf("name of CAN device '%s' is too long!\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
@@ -394,7 +396,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nbytes < sizeof(struct can_frame)) {
|
||||
if (nbytes < (int)sizeof(struct can_frame)) {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -42,23 +42,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -72,9 +73,10 @@
|
||||
#endif
|
||||
|
||||
/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
|
||||
#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
|
||||
#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
|
||||
#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
|
||||
#define SOF_TIMESTAMPING_SOFTWARE (1 << 4)
|
||||
#define SOF_TIMESTAMPING_RX_SOFTWARE (1 << 3)
|
||||
#define SOF_TIMESTAMPING_RAW_HARDWARE (1 << 6)
|
||||
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
|
||||
|
||||
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
|
||||
#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
|
||||
@@ -85,40 +87,47 @@
|
||||
#define SILENT_INI 42 /* detect user setting on commandline */
|
||||
#define SILENT_OFF 0 /* no silent mode */
|
||||
#define SILENT_ANI 1 /* silent mode with animation */
|
||||
#define SILENT_ON 2 /* silent mode (completely silent) */
|
||||
#define SILENT_ON 2 /* silent mode (completely silent) */
|
||||
|
||||
#define BOLD ATTBOLD
|
||||
#define RED ATTBOLD FGRED
|
||||
#define GREEN ATTBOLD FGGREEN
|
||||
#define YELLOW ATTBOLD FGYELLOW
|
||||
#define BLUE ATTBOLD FGBLUE
|
||||
#define MAGENTA ATTBOLD FGMAGENTA
|
||||
#define CYAN ATTBOLD FGCYAN
|
||||
#define BOLD ATTBOLD
|
||||
#define RED (ATTBOLD FGRED)
|
||||
#define GREEN (ATTBOLD FGGREEN)
|
||||
#define YELLOW (ATTBOLD FGYELLOW)
|
||||
#define BLUE (ATTBOLD FGBLUE)
|
||||
#define MAGENTA (ATTBOLD FGMAGENTA)
|
||||
#define CYAN (ATTBOLD FGCYAN)
|
||||
|
||||
const char col_on [MAXCOL][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
|
||||
const char col_off [] = ATTRESET;
|
||||
static const char col_on[MAXCOL][19] = { BLUE, RED, GREEN, BOLD, MAGENTA, CYAN };
|
||||
static const char col_off[] = ATTRESET;
|
||||
|
||||
struct if_info { /* bundled information per open socket */
|
||||
int s; /* socket */
|
||||
char *cmdlinename;
|
||||
__u32 dropcnt;
|
||||
__u32 last_dropcnt;
|
||||
};
|
||||
static struct if_info sock_info[MAXSOCK];
|
||||
|
||||
static char *cmdlinename[MAXSOCK];
|
||||
static __u32 dropcnt[MAXSOCK];
|
||||
static __u32 last_dropcnt[MAXSOCK];
|
||||
static char devname[MAXIFNAMES][IFNAMSIZ+1];
|
||||
static int dindex[MAXIFNAMES];
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
const int canfd_on = 1;
|
||||
static int dindex[MAXIFNAMES];
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
static const int canfd_on = 1;
|
||||
|
||||
#define MAXANI 4
|
||||
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
|
||||
const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
|
||||
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
|
||||
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static volatile int running = 1;
|
||||
|
||||
void print_usage(char *prg)
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - dump CAN bus traffic.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
|
||||
fprintf(stderr, "Options: -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -H (read hardware timestamps instead of system timestamps)\n");
|
||||
fprintf(stderr, " -c (increment color mode level)\n");
|
||||
fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n");
|
||||
@@ -132,41 +141,44 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
|
||||
fprintf(stderr, " -d (monitor dropped CAN frames)\n");
|
||||
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n");
|
||||
fprintf(stderr, " -8 (display raw DLC values in {} for Classical CAN)\n");
|
||||
fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n");
|
||||
fprintf(stderr, " -T <msecs> (terminate after <msecs> without any reception)\n");
|
||||
fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
|
||||
fprintf(stderr, "on the commandline in the form: <ifname>[,filter]*\n");
|
||||
fprintf(stderr, "\nComma separated filters can be specified for each given CAN interface:\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, " #<error_mask> (set error frame filter, see include/linux/can/error.h)\n");
|
||||
fprintf(stderr, " [j|J] (join the given CAN filters - logical AND semantic)\n");
|
||||
fprintf(stderr, "\nFilters:\n");
|
||||
fprintf(stderr, " Comma separated filters can be specified for each given CAN interface:\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask>\n (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask>\n (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, " #<error_mask>\n (set error frame filter, see include/linux/can/error.h)\n");
|
||||
fprintf(stderr, " [j|J]\n (join the given CAN filters - logical AND semantic)\n");
|
||||
fprintf(stderr, "\nCAN IDs, masks and data content are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "When the can_id is 8 digits long the CAN_EFF_FLAG is set for 29 bit EFF format.\n");
|
||||
fprintf(stderr, "Without any given filter all data frames are received ('0:0' default filter).\n");
|
||||
fprintf(stderr, "\nUse interface name '%s' to receive from all CAN interfaces.\n", ANYDEV);
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n", prg);
|
||||
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF (log only error frames but no(!) data frames)\n", prg);
|
||||
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF (log error frames and also all data frames)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF (match only for extended CAN ID 12345678)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,123:7FF (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,123:C00007FF (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
|
||||
fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n\n", prg);
|
||||
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF\n (log only error frames but no(!) data frames)\n", prg);
|
||||
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF\n (log error frames and also all data frames)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF\n (match only for extended CAN ID 12345678)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,123:7FF\n (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
|
||||
fprintf(stderr, "%s vcan2,123:C00007FF\n (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void sigterm(int signo)
|
||||
static void sigterm(int signo)
|
||||
{
|
||||
running = 0;
|
||||
}
|
||||
|
||||
int idx2dindex(int ifidx, int socket) {
|
||||
static int idx2dindex(int ifidx, int socket)
|
||||
{
|
||||
|
||||
int i;
|
||||
struct ifreq ifr;
|
||||
|
||||
for (i=0; i < MAXIFNAMES; i++) {
|
||||
for (i = 0; i < MAXIFNAMES; i++) {
|
||||
if (dindex[i] == ifidx)
|
||||
return i;
|
||||
}
|
||||
@@ -174,7 +186,7 @@ int idx2dindex(int ifidx, int socket) {
|
||||
/* create new interface index cache entry */
|
||||
|
||||
/* remove index cache zombies first */
|
||||
for (i=0; i < MAXIFNAMES; i++) {
|
||||
for (i = 0; i < MAXIFNAMES; i++) {
|
||||
if (dindex[i]) {
|
||||
ifr.ifr_ifindex = dindex[i];
|
||||
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
|
||||
@@ -182,13 +194,13 @@ int idx2dindex(int ifidx, int socket) {
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i < MAXIFNAMES; i++)
|
||||
for (i = 0; i < MAXIFNAMES; i++)
|
||||
if (!dindex[i]) /* free entry */
|
||||
break;
|
||||
|
||||
if (i == MAXIFNAMES) {
|
||||
fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
|
||||
MAXIFNAMES);
|
||||
MAXIFNAMES);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -198,7 +210,7 @@ int idx2dindex(int ifidx, int socket) {
|
||||
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
|
||||
perror("SIOCGIFNAME");
|
||||
|
||||
if (max_devname_len < strlen(ifr.ifr_name))
|
||||
if (max_devname_len < (int)strlen(ifr.ifr_name))
|
||||
max_devname_len = strlen(ifr.ifr_name);
|
||||
|
||||
strcpy(devname[i], ifr.ifr_name);
|
||||
@@ -210,11 +222,69 @@ int idx2dindex(int ifidx, int socket) {
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void sprint_timestamp(const char timestamp, const struct timeval *tv,
|
||||
struct timeval *const last_tv, char *ts_buffer)
|
||||
{
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
sprintf(ts_buffer, "(%010lu.%06lu) ", tv->tv_sec, tv->tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv->tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
sprintf(ts_buffer, "(%s.%06lu) ", timestring, tv->tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
if (last_tv->tv_sec == 0) /* first init */
|
||||
*last_tv = *tv;
|
||||
diff.tv_sec = tv->tv_sec - last_tv->tv_sec;
|
||||
diff.tv_usec = tv->tv_usec - last_tv->tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
sprintf(ts_buffer, "(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
*last_tv = *tv; /* update for delta calculation */
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void print_timestamp(const char timestamp, const struct timeval *tv,
|
||||
struct timeval *const last_tv)
|
||||
{
|
||||
static char buffer[TIMESTAMPSZ];
|
||||
|
||||
sprint_timestamp(timestamp, tv, last_tv, buffer);
|
||||
printf("%s", buffer);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fd_set rdfs;
|
||||
int s[MAXSOCK];
|
||||
int fd_epoll;
|
||||
struct epoll_event events_pending[MAXSOCK];
|
||||
struct epoll_event event_setup = {
|
||||
.events = EPOLLIN, /* prepare the common part */
|
||||
};
|
||||
unsigned char timestamp = 0;
|
||||
unsigned char logtimestamp = 'a';
|
||||
unsigned char hwtimestamp = 0;
|
||||
unsigned char down_causes_exit = 1;
|
||||
unsigned char dropmonitor = 0;
|
||||
@@ -227,12 +297,12 @@ int main(int argc, char **argv)
|
||||
unsigned char logfrmt = 0;
|
||||
int count = 0;
|
||||
int rcvbuf_size = 0;
|
||||
int opt, ret;
|
||||
int opt, num_events;
|
||||
int currmax, numfilter;
|
||||
int join_filter;
|
||||
char *ptr, *nptr;
|
||||
struct sockaddr_can addr;
|
||||
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
|
||||
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3 * sizeof(struct timespec) + sizeof(__u32))];
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -242,26 +312,30 @@ int main(int argc, char **argv)
|
||||
int nbytes, i, maxdlen;
|
||||
struct ifreq ifr;
|
||||
struct timeval tv, last_tv;
|
||||
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
|
||||
int timeout_ms = -1; /* default to no timeout */
|
||||
FILE *logfile = NULL;
|
||||
|
||||
signal(SIGTERM, sigterm);
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_usec = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:heT:?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:he8T:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
timestamp = optarg[0];
|
||||
logtimestamp = optarg[0];
|
||||
if ((timestamp != 'a') && (timestamp != 'A') &&
|
||||
(timestamp != 'd') && (timestamp != 'z')) {
|
||||
fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
|
||||
basename(argv[0]), optarg[0]);
|
||||
basename(argv[0]), optarg[0]);
|
||||
timestamp = 0;
|
||||
}
|
||||
if ((logtimestamp != 'a') && (logtimestamp != 'z')) {
|
||||
logtimestamp = 'a';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
@@ -288,6 +362,10 @@ int main(int argc, char **argv)
|
||||
view |= CANLIB_VIEW_ERROR;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
view |= CANLIB_VIEW_LEN8_DLC;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
silent = atoi(optarg);
|
||||
if (silent > SILENT_ON) {
|
||||
@@ -334,14 +412,11 @@ int main(int argc, char **argv)
|
||||
|
||||
case 'T':
|
||||
errno = 0;
|
||||
timeout_config.tv_usec = strtol(optarg, NULL, 0);
|
||||
timeout_ms = strtol(optarg, NULL, 0);
|
||||
if (errno != 0) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
timeout_config.tv_sec = timeout_config.tv_usec / 1000;
|
||||
timeout_config.tv_usec = (timeout_config.tv_usec % 1000) * 1000;
|
||||
timeout_current = &timeout;
|
||||
break;
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
@@ -354,9 +429,9 @@ int main(int argc, char **argv)
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
if (logfrmt && view) {
|
||||
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
|
||||
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP/RAWDLC options!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -375,8 +450,14 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i=0; i < currmax; i++) {
|
||||
fd_epoll = epoll_create(1);
|
||||
if (fd_epoll < 0) {
|
||||
perror("epoll_create");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < currmax; i++) {
|
||||
struct if_info* obj = &sock_info[i];
|
||||
ptr = argv[optind+i];
|
||||
nptr = strchr(ptr, ',');
|
||||
|
||||
@@ -384,13 +465,19 @@ int main(int argc, char **argv)
|
||||
printf("open %d '%s'.\n", i, ptr);
|
||||
#endif
|
||||
|
||||
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (s[i] < 0) {
|
||||
obj->s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (obj->s < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
|
||||
event_setup.data.ptr = obj; /* remember the instance as private data */
|
||||
if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, obj->s, &event_setup)) {
|
||||
perror("failed to add socket to epoll");
|
||||
return 1;
|
||||
}
|
||||
|
||||
obj->cmdlinename = ptr; /* save pointer to cmdline name of this socket */
|
||||
|
||||
if (nptr)
|
||||
nbytes = nptr - ptr; /* interface name is up the first ',' */
|
||||
@@ -414,8 +501,8 @@ int main(int argc, char **argv)
|
||||
printf("using interface name '%s'.\n", ifr.ifr_name);
|
||||
#endif
|
||||
|
||||
if (strcmp(ANYDEV, ifr.ifr_name)) {
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
if (strcmp(ANYDEV, ifr.ifr_name) != 0) {
|
||||
if (ioctl(obj->s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
exit(1);
|
||||
}
|
||||
@@ -448,44 +535,44 @@ int main(int argc, char **argv)
|
||||
|
||||
while (nptr) {
|
||||
|
||||
ptr = nptr+1; /* hop behind the ',' */
|
||||
ptr = nptr + 1; /* hop behind the ',' */
|
||||
nptr = strchr(ptr, ','); /* update exit condition */
|
||||
|
||||
if (sscanf(ptr, "%x:%x",
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_mask) == 2) {
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr+8) == ':')
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr + 8) == ':')
|
||||
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
|
||||
numfilter++;
|
||||
} else if (sscanf(ptr, "%x~%x",
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_mask) == 2) {
|
||||
rfilter[numfilter].can_id |= CAN_INV_FILTER;
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr+8) == '~')
|
||||
rfilter[numfilter].can_id |= CAN_INV_FILTER;
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr + 8) == '~')
|
||||
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
|
||||
numfilter++;
|
||||
} else if (*ptr == 'j' || *ptr == 'J') {
|
||||
join_filter = 1;
|
||||
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
|
||||
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
|
||||
fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (err_mask)
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
||||
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
||||
&err_mask, sizeof(err_mask));
|
||||
|
||||
if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
|
||||
if (join_filter && setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
|
||||
&join_filter, sizeof(join_filter)) < 0) {
|
||||
perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (numfilter)
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
rfilter, numfilter * sizeof(struct can_filter));
|
||||
|
||||
free(rfilter);
|
||||
@@ -493,26 +580,25 @@ int main(int argc, char **argv)
|
||||
} /* if (nptr) */
|
||||
|
||||
/* try to switch the socket into CAN FD mode */
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
|
||||
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
|
||||
|
||||
if (rcvbuf_size) {
|
||||
|
||||
int curr_rcvbuf_size;
|
||||
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
|
||||
|
||||
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUFFORCE,
|
||||
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
|
||||
#ifdef DEBUG
|
||||
printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
|
||||
#endif
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
|
||||
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
|
||||
perror("setsockopt SO_RCVBUF");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
|
||||
if (getsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
|
||||
&curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
|
||||
perror("getsockopt SO_RCVBUF");
|
||||
return 1;
|
||||
@@ -520,28 +606,27 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Only print a warning the first time we detect the adjustment */
|
||||
/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
|
||||
if (!i && curr_rcvbuf_size < rcvbuf_size*2)
|
||||
if (!i && curr_rcvbuf_size < rcvbuf_size * 2)
|
||||
fprintf(stderr, "The socket receive buffer size was "
|
||||
"adjusted due to /proc/sys/net/core/rmem_max.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (timestamp || log || logfrmt) {
|
||||
|
||||
if (hwtimestamp) {
|
||||
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE | \
|
||||
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE);
|
||||
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
|
||||
×tamping_flags, sizeof(timestamping_flags)) < 0) {
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMPING,
|
||||
×tamping_flags, sizeof(timestamping_flags)) < 0) {
|
||||
perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
const int timestamp_on = 1;
|
||||
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMP,
|
||||
×tamp_on, sizeof(timestamp_on)) < 0) {
|
||||
perror("setsockopt SO_TIMESTAMP");
|
||||
return 1;
|
||||
@@ -550,17 +635,16 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (dropmonitor) {
|
||||
|
||||
const int dropmonitor_on = 1;
|
||||
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RXQ_OVFL,
|
||||
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
|
||||
perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
if (bind(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
@@ -606,196 +690,160 @@ int main(int argc, char **argv)
|
||||
msg.msg_control = &ctrlmsg;
|
||||
|
||||
while (running) {
|
||||
|
||||
FD_ZERO(&rdfs);
|
||||
for (i=0; i<currmax; i++)
|
||||
FD_SET(s[i], &rdfs);
|
||||
|
||||
if (timeout_current)
|
||||
*timeout_current = timeout_config;
|
||||
|
||||
if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
|
||||
//perror("select");
|
||||
running = 0;
|
||||
num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms);
|
||||
if (num_events == -1) {
|
||||
if (errno != EINTR)
|
||||
running = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
|
||||
for (i = 0; i < num_events; i++) { /* check waiting CAN RAW sockets */
|
||||
struct if_info* obj = events_pending[i].data.ptr;
|
||||
int idx;
|
||||
char *extra_info = "";
|
||||
|
||||
if (FD_ISSET(s[i], &rdfs)) {
|
||||
/* these settings may be modified by recvmsg() */
|
||||
iov.iov_len = sizeof(frame);
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
msg.msg_controllen = sizeof(ctrlmsg);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
int idx;
|
||||
nbytes = recvmsg(obj->s, &msg, 0);
|
||||
idx = idx2dindex(addr.can_ifindex, obj->s);
|
||||
|
||||
/* these settings may be modified by recvmsg() */
|
||||
iov.iov_len = sizeof(frame);
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
msg.msg_controllen = sizeof(ctrlmsg);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
nbytes = recvmsg(s[i], &msg, 0);
|
||||
idx = idx2dindex(addr.can_ifindex, s[i]);
|
||||
|
||||
if (nbytes < 0) {
|
||||
if ((errno == ENETDOWN) && !down_causes_exit) {
|
||||
fprintf(stderr, "%s: interface down\n", devname[idx]);
|
||||
continue;
|
||||
}
|
||||
perror("read");
|
||||
return 1;
|
||||
if (nbytes < 0) {
|
||||
if ((errno == ENETDOWN) && !down_causes_exit) {
|
||||
fprintf(stderr, "%s: interface down\n", devname[idx]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((size_t)nbytes == CAN_MTU)
|
||||
maxdlen = CAN_MAX_DLEN;
|
||||
else if ((size_t)nbytes == CANFD_MTU)
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
else {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count && (--count == 0))
|
||||
running = 0;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_TIMESTAMP) {
|
||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
|
||||
|
||||
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
||||
|
||||
/*
|
||||
* stamp[0] is the software timestamp
|
||||
* stamp[1] is deprecated
|
||||
* stamp[2] is the raw hardware timestamp
|
||||
* See chapter 2.1.2 Receive timestamps in
|
||||
* linux/Documentation/networking/timestamping.txt
|
||||
*/
|
||||
tv.tv_sec = stamp[2].tv_sec;
|
||||
tv.tv_usec = stamp[2].tv_nsec/1000;
|
||||
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
|
||||
memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
|
||||
}
|
||||
|
||||
/* check for (unlikely) dropped frames on this specific socket */
|
||||
if (dropcnt[i] != last_dropcnt[i]) {
|
||||
|
||||
__u32 frames = dropcnt[i] - last_dropcnt[i];
|
||||
|
||||
if (silent != SILENT_ON)
|
||||
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
|
||||
|
||||
if (log)
|
||||
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
|
||||
|
||||
last_dropcnt[i] = dropcnt[i];
|
||||
}
|
||||
|
||||
/* once we detected a EFF frame indent SFF frames accordingly */
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
view |= CANLIB_VIEW_INDENT_SFF;
|
||||
|
||||
if (log) {
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* log CAN frame with absolute timestamp & device */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
fprintf(logfile, "(%010ld.%06ld) %*s %s\n",
|
||||
tv.tv_sec, tv.tv_usec,
|
||||
max_devname_len, devname[idx], buf);
|
||||
}
|
||||
|
||||
if ((logfrmt) && (silent == SILENT_OFF)){
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* print CAN frame in log file style to stdout */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
printf("(%010ld.%06ld) %*s %s\n",
|
||||
tv.tv_sec, tv.tv_usec,
|
||||
max_devname_len, devname[idx], buf);
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
if (silent != SILENT_OFF){
|
||||
if (silent == SILENT_ANI) {
|
||||
printf("%c\b", anichar[silentani%=MAXANI]);
|
||||
silentani++;
|
||||
}
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
|
||||
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06ld) ", timestring, tv.tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
if (last_tv.tv_sec == 0) /* first init */
|
||||
last_tv = tv;
|
||||
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv = tv; /* update for delta calculation */
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
|
||||
printf("%*s", max_devname_len, devname[idx]);
|
||||
|
||||
if (extra_msg_info) {
|
||||
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
printf (" TX %s", extra_m_info[frame.flags & 3]);
|
||||
else
|
||||
printf (" RX %s", extra_m_info[frame.flags & 3]);
|
||||
}
|
||||
|
||||
printf("%s ", (color==1)?col_off:"");
|
||||
|
||||
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
|
||||
|
||||
printf("%s", (color>1)?col_off:"");
|
||||
printf("\n");
|
||||
perror("read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_fflush:
|
||||
if ((size_t)nbytes == CAN_MTU)
|
||||
maxdlen = CAN_MAX_DLEN;
|
||||
else if ((size_t)nbytes == CANFD_MTU)
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
else {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count && (--count == 0))
|
||||
running = 0;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_TIMESTAMP) {
|
||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
|
||||
|
||||
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
||||
|
||||
/*
|
||||
* stamp[0] is the software timestamp
|
||||
* stamp[1] is deprecated
|
||||
* stamp[2] is the raw hardware timestamp
|
||||
* See chapter 2.1.2 Receive timestamps in
|
||||
* linux/Documentation/networking/timestamping.txt
|
||||
*/
|
||||
tv.tv_sec = stamp[2].tv_sec;
|
||||
tv.tv_usec = stamp[2].tv_nsec/1000;
|
||||
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
|
||||
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
|
||||
}
|
||||
|
||||
/* check for (unlikely) dropped frames on this specific socket */
|
||||
if (obj->dropcnt != obj->last_dropcnt) {
|
||||
|
||||
__u32 frames = obj->dropcnt - obj->last_dropcnt;
|
||||
|
||||
if (silent != SILENT_ON)
|
||||
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
|
||||
|
||||
if (log)
|
||||
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
|
||||
|
||||
obj->last_dropcnt = obj->dropcnt;
|
||||
}
|
||||
|
||||
/* once we detected a EFF frame indent SFF frames accordingly */
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
view |= CANLIB_VIEW_INDENT_SFF;
|
||||
|
||||
if (extra_msg_info) {
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
extra_info = " T";
|
||||
else
|
||||
extra_info = " R";
|
||||
}
|
||||
|
||||
if (log) {
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
char ts_buf[TIMESTAMPSZ];
|
||||
|
||||
sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf);
|
||||
|
||||
/* log CAN frame with absolute timestamp & device */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
fprintf(logfile, "%s%*s %s%s\n", ts_buf,
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
}
|
||||
|
||||
if ((logfrmt) && (silent == SILENT_OFF)){
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* print CAN frame in log file style to stdout */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
print_timestamp(logtimestamp, &tv, &last_tv);
|
||||
|
||||
printf("%*s %s%s\n",
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
if (silent != SILENT_OFF){
|
||||
if (silent == SILENT_ANI) {
|
||||
printf("%c\b", anichar[silentani %= MAXANI]);
|
||||
silentani++;
|
||||
}
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
||||
print_timestamp(timestamp, &tv, &last_tv);
|
||||
printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : "");
|
||||
printf("%*s", max_devname_len, devname[idx]);
|
||||
|
||||
if (extra_msg_info) {
|
||||
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
printf (" TX %s", extra_m_info[frame.flags & 3]);
|
||||
else
|
||||
printf (" RX %s", extra_m_info[frame.flags & 3]);
|
||||
}
|
||||
|
||||
printf("%s ", (color == 1) ? col_off : "");
|
||||
|
||||
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
|
||||
|
||||
printf("%s", (color > 1) ? col_off : "");
|
||||
printf("\n");
|
||||
|
||||
out_fflush:
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<currmax; i++)
|
||||
close(s[i]);
|
||||
for (i = 0; i < currmax; i++)
|
||||
close(sock_info[i].s);
|
||||
|
||||
close(fd_epoll);
|
||||
|
||||
if (log)
|
||||
fclose(logfile);
|
||||
|
||||
+137
-73
@@ -17,23 +17,24 @@
|
||||
* Send feedback to <linux-can@vger.kernel.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
#include <getopt.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -48,31 +49,37 @@ static int verbose;
|
||||
static int sockfd;
|
||||
static int test_loops;
|
||||
static int exit_sig;
|
||||
static int inflight_count = CAN_MSG_COUNT;
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s - Full-duplex test program (DUT and host part).\n"
|
||||
"Usage: %s [options] <can-interface>\n"
|
||||
"\n"
|
||||
"Options: -v (low verbosity)\n"
|
||||
" -vv (high verbosity)\n"
|
||||
"Options:\n"
|
||||
" -f COUNT (number of frames in flight, default: %d)\n"
|
||||
" -g (generate messages)\n"
|
||||
" -l COUNT (test loop count)\n"
|
||||
" -v (low verbosity)\n"
|
||||
" -vv (high verbosity)\n"
|
||||
"\n"
|
||||
"With the option '-g' CAN messages are generated and checked\n"
|
||||
"on <can-interface>, otherwise all messages received on the\n"
|
||||
"<can-interface> are sent back incrementing the CAN id and\n"
|
||||
"all data bytes. The program can be aborted with ^C.\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
"\ton DUT : %s -v can0\n"
|
||||
"\ton Host: %s -g -v can2\n",
|
||||
prg, prg, prg);
|
||||
"Examples:\n"
|
||||
"\ton DUT:\n"
|
||||
"%s -v can0\n"
|
||||
"\ton Host:\n"
|
||||
"%s -g -v can2\n",
|
||||
prg, prg, CAN_MSG_COUNT, prg, prg);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void print_frame(struct can_frame *frame, int inc)
|
||||
static void print_frame(const struct can_frame *frame, int inc)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -82,12 +89,12 @@ static void print_frame(struct can_frame *frame, int inc)
|
||||
} else {
|
||||
printf("[%d]", frame->can_dlc);
|
||||
for (i = 0; i < frame->can_dlc; i++)
|
||||
printf(" %02x", frame->data[i] + inc);
|
||||
printf(" %02x", (uint8_t)(frame->data[i] + inc));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_compare(struct can_frame *exp, struct can_frame *rec, int inc)
|
||||
static void print_compare(const struct can_frame *exp, const struct can_frame *rec, int inc)
|
||||
{
|
||||
printf("expected: ");
|
||||
print_frame(exp, inc);
|
||||
@@ -109,8 +116,8 @@ static void compare_frame(struct can_frame *exp, struct can_frame *rec, int inc)
|
||||
running = 0;
|
||||
} else {
|
||||
for (i = 0; i < rec->can_dlc; i++) {
|
||||
if (rec->data[i] != ((exp->data[i] + inc) & 0xff)) {
|
||||
printf("Databyte %x mismatch !\n", i);
|
||||
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
|
||||
printf("Databyte %x mismatch!\n", i);
|
||||
print_compare(exp,
|
||||
rec, inc);
|
||||
running = 0;
|
||||
@@ -174,29 +181,63 @@ static int send_frame(struct can_frame *frame)
|
||||
|
||||
while ((ret = send(sockfd, frame, sizeof(*frame), 0))
|
||||
!= sizeof(*frame)) {
|
||||
if (ret < 0) {
|
||||
if (errno != ENOBUFS) {
|
||||
perror("send failed");
|
||||
return -1;
|
||||
} else {
|
||||
if (verbose) {
|
||||
printf("N");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ret >= 0) {
|
||||
fprintf(stderr, "send returned %d", ret);
|
||||
return -1;
|
||||
}
|
||||
if (errno != ENOBUFS) {
|
||||
perror("send failed");
|
||||
return -1;
|
||||
}
|
||||
if (verbose) {
|
||||
printf("N");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_frame(const struct can_frame *frame)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
if (frame->can_id != CAN_MSG_ID) {
|
||||
printf("unexpected Message ID 0x%04x!\n", frame->can_id);
|
||||
err = -1;
|
||||
}
|
||||
|
||||
if (frame->can_dlc != CAN_MSG_LEN) {
|
||||
printf("unexpected Message length %d!\n", frame->can_dlc);
|
||||
err = -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < frame->can_dlc; i++) {
|
||||
if (frame->data[i] != (uint8_t)(frame->data[i-1] + 1)) {
|
||||
printf("Frame inconsistent!\n");
|
||||
print_frame(frame, 0);
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void inc_frame(struct can_frame *frame)
|
||||
{
|
||||
int i;
|
||||
|
||||
frame->can_id++;
|
||||
for (i = 0; i < frame->can_dlc; i++)
|
||||
frame->data[i]++;
|
||||
}
|
||||
|
||||
static int can_echo_dut(void)
|
||||
{
|
||||
unsigned int frame_count = 0;
|
||||
struct can_frame frame;
|
||||
int i;
|
||||
|
||||
while (running) {
|
||||
if (recv_frame(&frame))
|
||||
@@ -205,19 +246,11 @@ static int can_echo_dut(void)
|
||||
if (verbose == 1) {
|
||||
echo_progress(frame.data[0]);
|
||||
} else if (verbose > 1) {
|
||||
printf("%04x: ", frame.can_id);
|
||||
if (frame.can_id & CAN_RTR_FLAG) {
|
||||
printf("remote request");
|
||||
} else {
|
||||
printf("[%d]", frame.can_dlc);
|
||||
for (i = 0; i < frame.can_dlc; i++)
|
||||
printf(" %02x", frame.data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
print_frame(&frame, 0);
|
||||
}
|
||||
frame.can_id++;
|
||||
for (i = 0; i < frame.can_dlc; i++)
|
||||
frame.data[i]++;
|
||||
|
||||
check_frame(&frame);
|
||||
inc_frame(&frame);
|
||||
if (send_frame(&frame))
|
||||
return -1;
|
||||
|
||||
@@ -236,15 +269,26 @@ static int can_echo_dut(void)
|
||||
|
||||
static int can_echo_gen(void)
|
||||
{
|
||||
struct can_frame tx_frames[CAN_MSG_COUNT];
|
||||
int recv_tx[CAN_MSG_COUNT];
|
||||
struct can_frame *tx_frames;
|
||||
int *recv_tx;
|
||||
struct can_frame rx_frame;
|
||||
unsigned char counter = 0;
|
||||
int send_pos = 0, recv_rx_pos = 0, recv_tx_pos = 0, unprocessed = 0, loops = 0;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
tx_frames = calloc(inflight_count, sizeof(* tx_frames));
|
||||
if (!tx_frames)
|
||||
return -1;
|
||||
|
||||
recv_tx = calloc(inflight_count, sizeof(* recv_tx));
|
||||
if (!recv_tx) {
|
||||
err = -1;
|
||||
goto out_free_tx_frames;
|
||||
}
|
||||
|
||||
while (running) {
|
||||
if (unprocessed < CAN_MSG_COUNT) {
|
||||
if (unprocessed < inflight_count) {
|
||||
/* still send messages */
|
||||
tx_frames[send_pos].can_dlc = CAN_MSG_LEN;
|
||||
tx_frames[send_pos].can_id = CAN_MSG_ID;
|
||||
@@ -252,11 +296,13 @@ static int can_echo_gen(void)
|
||||
|
||||
for (i = 0; i < CAN_MSG_LEN; i++)
|
||||
tx_frames[send_pos].data[i] = counter + i;
|
||||
if (send_frame(&tx_frames[send_pos]))
|
||||
return -1;
|
||||
if (send_frame(&tx_frames[send_pos])) {
|
||||
err = -1;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
send_pos++;
|
||||
if (send_pos == CAN_MSG_COUNT)
|
||||
if (send_pos == inflight_count)
|
||||
send_pos = 0;
|
||||
unprocessed++;
|
||||
if (verbose == 1)
|
||||
@@ -268,8 +314,10 @@ static int can_echo_gen(void)
|
||||
else
|
||||
millisleep(1);
|
||||
} else {
|
||||
if (recv_frame(&rx_frame))
|
||||
return -1;
|
||||
if (recv_frame(&rx_frame)) {
|
||||
err = -1;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (verbose > 1)
|
||||
print_frame(&rx_frame, 0);
|
||||
@@ -279,21 +327,22 @@ static int can_echo_gen(void)
|
||||
compare_frame(&tx_frames[recv_tx_pos], &rx_frame, 0);
|
||||
recv_tx[recv_tx_pos] = 1;
|
||||
recv_tx_pos++;
|
||||
if (recv_tx_pos == CAN_MSG_COUNT)
|
||||
if (recv_tx_pos == inflight_count)
|
||||
recv_tx_pos = 0;
|
||||
continue;
|
||||
} else {
|
||||
if (!recv_tx[recv_rx_pos]) {
|
||||
printf("RX before TX!\n");
|
||||
running = 0;
|
||||
}
|
||||
/* compare with expected */
|
||||
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
|
||||
recv_rx_pos++;
|
||||
if (recv_rx_pos == CAN_MSG_COUNT)
|
||||
recv_rx_pos = 0;
|
||||
}
|
||||
|
||||
if (!recv_tx[recv_rx_pos]) {
|
||||
printf("RX before TX!\n");
|
||||
print_frame(&rx_frame, 0);
|
||||
running = 0;
|
||||
}
|
||||
/* compare with expected */
|
||||
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
|
||||
recv_rx_pos++;
|
||||
if (recv_rx_pos == inflight_count)
|
||||
recv_rx_pos = 0;
|
||||
|
||||
loops++;
|
||||
if (test_loops && loops >= test_loops)
|
||||
break;
|
||||
@@ -304,7 +353,12 @@ static int can_echo_gen(void)
|
||||
|
||||
printf("\nTest messages sent and received: %d\n", loops);
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
free(recv_tx);
|
||||
out_free_tx_frames:
|
||||
free(tx_frames);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -320,20 +374,25 @@ int main(int argc, char *argv[])
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
while ((opt = getopt(argc, argv, "gl:v")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "f:gl:v?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
test_loops = atoi(optarg);;
|
||||
case 'f':
|
||||
inflight_count = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
echo_gen = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
test_loops = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
break;
|
||||
@@ -362,6 +421,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
addr.can_family = family;
|
||||
addr.can_ifindex = if_nametoindex(intf_name);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
|
||||
+7
-6
@@ -44,13 +44,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "canframelen.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "canframelen.h"
|
||||
|
||||
/**
|
||||
* Functions and types for CRC checks.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* cangen.c - CAN frames generator for testing purposes
|
||||
* cangen.c - CAN frames generator
|
||||
*
|
||||
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
@@ -42,34 +42,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define DEFAULT_GAP 200 /* ms */
|
||||
#define DEFAULT_BURST_COUNT 1
|
||||
|
||||
#define MODE_RANDOM 0
|
||||
#define MODE_INCREMENT 1
|
||||
#define MODE_FIX 2
|
||||
#define MODE_RANDOM_EVEN 3
|
||||
#define MODE_RANDOM_ODD 4
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
@@ -78,17 +82,21 @@ static unsigned long long enobufs_count;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\n%s: generate CAN frames\n\n", prg);
|
||||
fprintf(stderr, "%s - CAN frames generator.\n\n", prg);
|
||||
fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -g <ms> (gap in milli seconds "
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli seconds "
|
||||
"- default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -e (generate extended frame mode "
|
||||
"(EFF) CAN frames)\n");
|
||||
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
|
||||
fprintf(stderr, " -b (generate CAN FD CAN frames"
|
||||
" with bitrate switch (BRS))\n");
|
||||
fprintf(stderr, " -R (send RTR frame)\n");
|
||||
fprintf(stderr, " -m (mix -e -f -b -R frames)\n");
|
||||
fprintf(stderr, " -E (generate CAN FD CAN frames"
|
||||
" with error state (ESI))\n");
|
||||
fprintf(stderr, " -R (generate RTR frames)\n");
|
||||
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
|
||||
fprintf(stderr, " -m (mix -e -f -b -E -R frames)\n");
|
||||
fprintf(stderr, " -I <mode> (CAN ID"
|
||||
" generation mode - see below)\n");
|
||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc)"
|
||||
@@ -103,28 +111,32 @@ void print_usage(char *prg)
|
||||
" write() syscalls)\n");
|
||||
fprintf(stderr, " -x (disable local loopback of "
|
||||
"generated CAN frames)\n");
|
||||
fprintf(stderr, " -c <count> (number of messages to send in burst, "
|
||||
"default 1)\n");
|
||||
fprintf(stderr, " -v (increment verbose level for "
|
||||
"printing sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Generation modes:\n");
|
||||
fprintf(stderr, "'r' => random values (default)\n");
|
||||
fprintf(stderr, "'i' => increment values\n");
|
||||
fprintf(stderr, "<hexvalue> => fix value using <hexvalue>\n\n");
|
||||
fprintf(stderr, " 'r' => random values (default)\n");
|
||||
fprintf(stderr, " 'e' => random values, even ID\n");
|
||||
fprintf(stderr, " 'o' => random values, odd ID\n");
|
||||
fprintf(stderr, " 'i' => increment values\n");
|
||||
fprintf(stderr, " <value> => fixed value (in hexadecimal for -I and -D)\n\n");
|
||||
fprintf(stderr, "When incrementing the CAN data the data length code "
|
||||
"minimum is set to 1.\n");
|
||||
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v ", prg);
|
||||
fprintf(stderr, "(fixed CAN ID and length, inc. data)\n");
|
||||
fprintf(stderr, "%s vcan0 -e -L i -v -v -v ", prg);
|
||||
fprintf(stderr, "(generate EFF frames, incr. length)\n");
|
||||
fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8 ", prg);
|
||||
fprintf(stderr, "(fixed CAN data payload and length)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -i -x ", prg);
|
||||
fprintf(stderr, "(full load test ignoring -ENOBUFS)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -p 10 -x ", prg);
|
||||
fprintf(stderr, "(full load test with polling, 10ms timeout)\n");
|
||||
fprintf(stderr, "%s vcan0 ", prg);
|
||||
fprintf(stderr, "(my favourite default :)\n\n");
|
||||
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v\n", prg);
|
||||
fprintf(stderr, "\t(fixed CAN ID and length, inc. data)\n");
|
||||
fprintf(stderr, "%s vcan0 -e -L i -v -v -v\n", prg);
|
||||
fprintf(stderr, "\t(generate EFF frames, incr. length)\n");
|
||||
fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8\n", prg);
|
||||
fprintf(stderr, "\t(fixed CAN data payload and length)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -i -x\n", prg);
|
||||
fprintf(stderr, "\t(full load test ignoring -ENOBUFS)\n");
|
||||
fprintf(stderr, "%s vcan0 -g 0 -p 10 -x\n", prg);
|
||||
fprintf(stderr, "\t(full load test with polling, 10ms timeout)\n");
|
||||
fprintf(stderr, "%s vcan0\n", prg);
|
||||
fprintf(stderr, "\t(my favourite default :)\n\n");
|
||||
}
|
||||
|
||||
void sigterm(int signo)
|
||||
@@ -135,11 +147,13 @@ void sigterm(int signo)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
double gap = DEFAULT_GAP;
|
||||
unsigned long burst_count = DEFAULT_BURST_COUNT;
|
||||
unsigned long polltimeout = 0;
|
||||
unsigned char ignore_enobufs = 0;
|
||||
unsigned char extended = 0;
|
||||
unsigned char canfd = 0;
|
||||
unsigned char brs = 0;
|
||||
unsigned char esi = 0;
|
||||
unsigned char mix = 0;
|
||||
unsigned char id_mode = MODE_RANDOM;
|
||||
unsigned char data_mode = MODE_RANDOM;
|
||||
@@ -147,7 +161,9 @@ int main(int argc, char **argv)
|
||||
unsigned char loopback_disable = 0;
|
||||
unsigned char verbose = 0;
|
||||
unsigned char rtr_frame = 0;
|
||||
unsigned char len8_dlc = 0;
|
||||
int count = 0;
|
||||
unsigned long burst_sent_count = 0;
|
||||
int mtu, maxdlen;
|
||||
uint64_t incdata = 0;
|
||||
int incdlc = 0;
|
||||
@@ -160,6 +176,7 @@ int main(int argc, char **argv)
|
||||
|
||||
struct sockaddr_can addr;
|
||||
static struct canfd_frame frame;
|
||||
struct can_frame *ccf = (struct can_frame *)&frame;
|
||||
int nbytes;
|
||||
int i;
|
||||
struct ifreq ifr;
|
||||
@@ -175,7 +192,7 @@ int main(int argc, char **argv)
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
while ((opt = getopt(argc, argv, "ig:ebfmI:L:D:xp:n:vRh?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vR8h?")) != -1) {
|
||||
switch (opt) {
|
||||
|
||||
case 'i':
|
||||
@@ -199,6 +216,11 @@ int main(int argc, char **argv)
|
||||
canfd = 1;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
esi = 1; /* error state indicator implies CAN FD */
|
||||
canfd = 1;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
mix = 1;
|
||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||
@@ -209,6 +231,10 @@ int main(int argc, char **argv)
|
||||
id_mode = MODE_RANDOM;
|
||||
} else if (optarg[0] == 'i') {
|
||||
id_mode = MODE_INCREMENT;
|
||||
} else if (optarg[0] == 'e') {
|
||||
id_mode = MODE_RANDOM_EVEN;
|
||||
} else if (optarg[0] == 'o') {
|
||||
id_mode = MODE_RANDOM_ODD;
|
||||
} else {
|
||||
id_mode = MODE_FIX;
|
||||
frame.can_id = strtoul(optarg, NULL, 16);
|
||||
@@ -240,6 +266,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
burst_count = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
@@ -252,6 +282,10 @@ int main(int argc, char **argv)
|
||||
rtr_frame = 1;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
len8_dlc = 1;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
polltimeout = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
@@ -279,7 +313,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
ts.tv_sec = gap / 1000;
|
||||
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000ll);
|
||||
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000LL);
|
||||
|
||||
/* recognize obviously missing commandline option */
|
||||
if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) {
|
||||
@@ -341,11 +375,19 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
||||
frame.len = can_dlc2len(can_len2dlc(frame.len));
|
||||
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
|
||||
} else {
|
||||
/* sanitize CAN 2.0 frame length */
|
||||
if (frame.len > 8)
|
||||
frame.len = 8;
|
||||
/* sanitize Classical CAN 2.0 frame length */
|
||||
if (len8_dlc) {
|
||||
if (frame.len > CAN_MAX_RAW_DLC)
|
||||
frame.len = CAN_MAX_RAW_DLC;
|
||||
|
||||
if (frame.len > CAN_MAX_DLEN)
|
||||
ccf->len8_dlc = frame.len;
|
||||
}
|
||||
|
||||
if (frame.len > CAN_MAX_DLEN)
|
||||
frame.len = CAN_MAX_DLEN;
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
@@ -369,6 +411,8 @@ int main(int argc, char **argv)
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
if (brs)
|
||||
frame.flags |= CANFD_BRS;
|
||||
if (esi)
|
||||
frame.flags |= CANFD_ESI;
|
||||
} else {
|
||||
mtu = CAN_MTU;
|
||||
maxdlen = CAN_MAX_DLEN;
|
||||
@@ -376,6 +420,10 @@ int main(int argc, char **argv)
|
||||
|
||||
if (id_mode == MODE_RANDOM)
|
||||
frame.can_id = random();
|
||||
else if (id_mode == MODE_RANDOM_EVEN)
|
||||
frame.can_id = random() & ~0x1;
|
||||
else if (id_mode == MODE_RANDOM_ODD)
|
||||
frame.can_id = random() | 0x1;
|
||||
|
||||
if (extended) {
|
||||
frame.can_id &= CAN_EFF_MASK;
|
||||
@@ -389,11 +437,19 @@ int main(int argc, char **argv)
|
||||
if (dlc_mode == MODE_RANDOM) {
|
||||
|
||||
if (canfd)
|
||||
frame.len = can_dlc2len(random() & 0xF);
|
||||
frame.len = can_fd_dlc2len(random() & 0xF);
|
||||
else {
|
||||
frame.len = random() & 0xF;
|
||||
if (frame.len & 8)
|
||||
|
||||
if (frame.len > CAN_MAX_DLEN) {
|
||||
/* generate Classic CAN len8 DLCs? */
|
||||
if (len8_dlc)
|
||||
ccf->len8_dlc = frame.len;
|
||||
|
||||
frame.len = 8; /* for about 50% of the frames */
|
||||
} else {
|
||||
ccf->len8_dlc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,8 +504,8 @@ resend:
|
||||
if (poll(&fds, 1, polltimeout) < 0) {
|
||||
perror("poll");
|
||||
return 1;
|
||||
} else
|
||||
goto resend;
|
||||
}
|
||||
goto resend;
|
||||
} else
|
||||
enobufs_count++;
|
||||
|
||||
@@ -458,22 +514,34 @@ resend:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (gap) /* gap == 0 => performance test :-] */
|
||||
burst_sent_count++;
|
||||
if (gap && burst_sent_count >= burst_count) /* gap == 0 => performance test :-] */
|
||||
if (nanosleep(&ts, NULL))
|
||||
return 1;
|
||||
|
||||
if (burst_sent_count >= burst_count)
|
||||
burst_sent_count = 0;
|
||||
|
||||
if (id_mode == MODE_INCREMENT)
|
||||
frame.can_id++;
|
||||
|
||||
if (dlc_mode == MODE_INCREMENT) {
|
||||
|
||||
incdlc++;
|
||||
incdlc %= CAN_MAX_RAW_DLC + 1;
|
||||
|
||||
if (canfd && !mix) {
|
||||
incdlc &= 0xF;
|
||||
frame.len = can_dlc2len(incdlc);
|
||||
if (canfd && !mix)
|
||||
frame.len = can_fd_dlc2len(incdlc);
|
||||
else if (len8_dlc) {
|
||||
if (incdlc > CAN_MAX_DLEN) {
|
||||
frame.len = CAN_MAX_DLEN;
|
||||
ccf->len8_dlc = incdlc;
|
||||
} else {
|
||||
frame.len = incdlc;
|
||||
ccf->len8_dlc = 0;
|
||||
}
|
||||
} else {
|
||||
incdlc %= 9;
|
||||
incdlc %= CAN_MAX_DLEN + 1;
|
||||
frame.len = incdlc;
|
||||
}
|
||||
}
|
||||
@@ -490,8 +558,10 @@ resend:
|
||||
i = random();
|
||||
extended = i&1;
|
||||
canfd = i&2;
|
||||
if (canfd)
|
||||
if (canfd) {
|
||||
brs = i&4;
|
||||
esi = i&8;
|
||||
}
|
||||
rtr_frame = ((i&24) == 24); /* reduce RTR frames to 1/4 */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +42,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/can/gw.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/can/gw.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum {
|
||||
UNSPEC,
|
||||
@@ -80,7 +80,7 @@ struct fdmodattr {
|
||||
|
||||
/* some netlink helpers stolen from iproute2 package */
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *)(((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
((struct rtattr *)(((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
||||
int alen)
|
||||
@@ -88,7 +88,7 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
||||
int len = RTA_LENGTH(alen);
|
||||
struct rtattr *rta;
|
||||
|
||||
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
|
||||
if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen) {
|
||||
fprintf(stderr, "addattr_l: message exceeded bound of %d\n",
|
||||
maxlen);
|
||||
return -1;
|
||||
@@ -222,55 +222,60 @@ void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8)
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - manage PF_CAN netlink gateway.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options]\n\n", prg);
|
||||
fprintf(stderr, "Commands: -A (add a new rule)\n");
|
||||
fprintf(stderr, " -D (delete a rule)\n");
|
||||
fprintf(stderr, " -F (flush / delete all rules)\n");
|
||||
fprintf(stderr, " -L (list all rules)\n");
|
||||
fprintf(stderr, "Mandatory: -s <src_dev> (source netdevice)\n");
|
||||
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
|
||||
fprintf(stderr, "Options: -X (this is a CAN FD rule)\n");
|
||||
fprintf(stderr, " -t (preserve src_dev rx timestamp)\n");
|
||||
fprintf(stderr, " -e (echo sent frames - recommended on vcanx)\n");
|
||||
fprintf(stderr, " -i (allow to route to incoming interface)\n");
|
||||
fprintf(stderr, " -u <uid> (user defined modification identifier)\n");
|
||||
fprintf(stderr, " -l <hops> (limit the number of frame hops / routings)\n");
|
||||
fprintf(stderr, " -f <filter> (set CAN filter)\n");
|
||||
fprintf(stderr, " -m <mod> (set Classic CAN frame modifications)\n");
|
||||
fprintf(stderr, " -M <MOD> (set CAN FD frame modifications)\n");
|
||||
fprintf(stderr, " -x <from_idx>:<to_idx>:<result_idx>:<init_xor_val> (XOR checksum)\n");
|
||||
fprintf(stderr, " -c <from>:<to>:<result>:<init_val>:<xor_val>:<crctab[256]> (CRC8 cs)\n");
|
||||
fprintf(stderr, " -p <profile>:[<profile_data>] (CRC8 checksum profile & parameters)\n");
|
||||
fprintf(stderr, "Commands:\n");
|
||||
fprintf(stderr, " -A (add a new rule)\n");
|
||||
fprintf(stderr, " -D (delete a rule)\n");
|
||||
fprintf(stderr, " -F (flush / delete all rules)\n");
|
||||
fprintf(stderr, " -L (list all rules)\n");
|
||||
fprintf(stderr, "Mandatory:\n");
|
||||
fprintf(stderr, " -s <src_dev> (source netdevice)\n");
|
||||
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -X (this is a CAN FD rule)\n");
|
||||
fprintf(stderr, " -t (preserve src_dev rx timestamp)\n");
|
||||
fprintf(stderr, " -e (echo sent frames - recommended on vcanx)\n");
|
||||
fprintf(stderr, " -i (allow to route to incoming interface)\n");
|
||||
fprintf(stderr, " -u <uid> (user defined modification identifier)\n");
|
||||
fprintf(stderr, " -l <hops> (limit the number of frame hops / routings)\n");
|
||||
fprintf(stderr, " -f <filter> (set CAN filter)\n");
|
||||
fprintf(stderr, " -m <mod> (set Classical CAN frame modifications)\n");
|
||||
fprintf(stderr, " -M <MOD> (set CAN FD frame modifications)\n");
|
||||
fprintf(stderr, " -x <from_idx>:<to_idx>:<result_idx>:<init_xor_val> (XOR checksum)\n");
|
||||
fprintf(stderr, " -c <from>:<to>:<result>:<init_val>:<xor_val>:<crctab[256]> (CRC8 cs)\n");
|
||||
fprintf(stderr, " -p <profile>:[<profile_data>] (CRC8 checksum profile & parameters)\n");
|
||||
fprintf(stderr, "\nValues are given and expected in hexadecimal values. Leading 0s can be omitted.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<filter> is a <value><mask> CAN identifier filter\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, "<filter> is a <value><mask> CAN identifier filter:\n");
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<mod> is a CAN frame modification instruction consisting of\n");
|
||||
fprintf(stderr, "<mod> is a Classical CAN frame modification instruction consisting of\n");
|
||||
fprintf(stderr, "<instruction>:<can_frame-elements>:<can_id>.<can_dlc>.<can_data>\n");
|
||||
fprintf(stderr, " - <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " - <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " - <can_id> is an u32 value containing the CAN Identifier\n");
|
||||
fprintf(stderr, " - <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
|
||||
fprintf(stderr, " - <can_data> is always eight(!) u8 values containing the CAN frames data\n");
|
||||
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " <can_id> is an u32 value containing the CAN Identifier\n");
|
||||
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code in hex (0 .. F)\n");
|
||||
fprintf(stderr, " <can_data> is always eight(!) u8 values containing the CAN frames data\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<MOD> is a CAN FD frame modification instruction consisting of\n");
|
||||
fprintf(stderr, "<instruction>:<canfd_frame-elements>:<can_id>.<flags>.<len>.<can_data>\n");
|
||||
fprintf(stderr, " - <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " - <canfd_frame-elements> is _one_ or _more_ of 'I'd 'F'lags 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " - <can_id> is an u32 value containing the CAN FD Identifier\n");
|
||||
fprintf(stderr, " - <flags> is an u8 value containing CAN FD flags (CANFD_BRS, CANFD_ESI)\n");
|
||||
fprintf(stderr, " - <len> is an u8 value containing the data length (0 .. 64)\n");
|
||||
fprintf(stderr, " - <can_data> is always 64(!) u8 values containing the CAN FD frames data\n");
|
||||
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " <canfd_frame-elements> is _one_ or _more_ of 'I'd 'F'lags 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " <can_id> is an u32 value containing the CAN FD Identifier\n");
|
||||
fprintf(stderr, " <flags> is an u8 value containing CAN FD flags (CANFD_BRS, CANFD_ESI)\n");
|
||||
fprintf(stderr, " <len> is an u8 value containing the data length in hex (0 .. 40)\n");
|
||||
fprintf(stderr, " <can_data> is always 64(!) u8 values containing the CAN FD frames data\n");
|
||||
fprintf(stderr, "The max. four modifications are performed in the order AND -> OR -> XOR -> SET\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Example:\n");
|
||||
fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Supported CRC 8 profiles:\n");
|
||||
fprintf(stderr, "Profile '%d' (1U8) - add one additional u8 value\n", CGW_CRC8PRF_1U8);
|
||||
fprintf(stderr, "Profile '%d' (16U8) - add u8 value from table[16] indexed by (data[1] & 0xF)\n", CGW_CRC8PRF_16U8);
|
||||
fprintf(stderr, "Profile '%d' (SFFID_XOR) - add u8 value (can_id & 0xFF) ^ (can_id >> 8 & 0xFF)\n", CGW_CRC8PRF_SFFID_XOR);
|
||||
fprintf(stderr, " Profile '%d' (1U8) add one additional u8 value\n", CGW_CRC8PRF_1U8);
|
||||
fprintf(stderr, " Profile '%d' (16U8) add u8 value from table[16] indexed by (data[1] & 0xF)\n", CGW_CRC8PRF_16U8);
|
||||
fprintf(stderr, " Profile '%d' (SFFID_XOR) add u8 value (can_id & 0xFF) ^ (can_id >> 8 & 0xFF)\n", CGW_CRC8PRF_SFFID_XOR);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -290,14 +295,14 @@ int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8)
|
||||
int ret = 1;
|
||||
char *ptr;
|
||||
|
||||
if (sscanf(optarg, "%hhd:", &crc8->profile) != 1)
|
||||
if (sscanf(optarg, "%hhu:", &crc8->profile) != 1)
|
||||
return ret;
|
||||
|
||||
switch (crc8->profile) {
|
||||
|
||||
case CGW_CRC8PRF_1U8:
|
||||
|
||||
if (sscanf(optarg, "%hhd:%2hhx", &crc8->profile, &crc8->profile_data[0]) == 2)
|
||||
if (sscanf(optarg, "%hhu:%2hhx", &crc8->profile, &crc8->profile_data[0]) == 2)
|
||||
ret = 0;
|
||||
|
||||
break;
|
||||
@@ -701,8 +706,8 @@ int main(int argc, char **argv)
|
||||
struct can_filter filter;
|
||||
struct sockaddr_nl nladdr;
|
||||
|
||||
struct cgw_csum_xor cs_xor;
|
||||
struct cgw_csum_crc8 cs_crc8;
|
||||
struct cgw_csum_xor cs_xor = { 0 };
|
||||
struct cgw_csum_crc8 cs_crc8 = { 0 };
|
||||
char crc8tab[513] = {0};
|
||||
|
||||
struct modattr modmsg[CGW_MOD_FUNCS];
|
||||
@@ -712,8 +717,6 @@ int main(int argc, char **argv)
|
||||
int i;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&cs_xor, 0, sizeof(cs_xor));
|
||||
memset(&cs_crc8, 0, sizeof(cs_crc8));
|
||||
|
||||
while ((opt = getopt(argc, argv, "ADFLs:d:Xteiu:l:f:c:p:x:m:M:?")) != -1) {
|
||||
switch (opt) {
|
||||
@@ -767,7 +770,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (sscanf(optarg, "%hhd", &limit_hops) != 1 || !(limit_hops)) {
|
||||
if (sscanf(optarg, "%hhu", &limit_hops) != 1 || !(limit_hops)) {
|
||||
printf("Bad hop limit definition '%s'.\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+27
-24
@@ -42,29 +42,29 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -89,7 +89,8 @@ void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
|
||||
fprintf(stderr, "Options: -m <mask> (ID filter mask. Default 0x00000000) *\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -m <mask> (ID filter mask. Default 0x00000000) *\n");
|
||||
fprintf(stderr, " -v <value> (ID filter value. Default 0x00000000) *\n");
|
||||
fprintf(stderr, " -i <0|1> (invert the specified ID filter) *\n");
|
||||
fprintf(stderr, " -e <emask> (mask for error frames)\n");
|
||||
@@ -139,7 +140,7 @@ int idx2dindex(int ifidx, int socket)
|
||||
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
|
||||
perror("SIOCGIFNAME");
|
||||
|
||||
if (max_devname_len < strlen(ifr.ifr_name))
|
||||
if (max_devname_len < (int)strlen(ifr.ifr_name))
|
||||
max_devname_len = strlen(ifr.ifr_name);
|
||||
|
||||
strcpy(devname[i], ifr.ifr_name);
|
||||
@@ -161,7 +162,7 @@ void childdied(int i)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a Signalhandler for a cought SIGTERM
|
||||
* This is a Signalhandler for a caught SIGTERM
|
||||
*/
|
||||
void shutdown_gra(int i)
|
||||
{
|
||||
@@ -280,8 +281,12 @@ int main(int argc, char **argv)
|
||||
inaddr.sin_port = htons(port);
|
||||
|
||||
while(bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
|
||||
printf(".");fflush(NULL);
|
||||
usleep(100000);
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
if (listen(socki, 3) != 0) {
|
||||
@@ -295,15 +300,14 @@ int main(int argc, char **argv)
|
||||
//printf("accepted\n");
|
||||
if (!fork())
|
||||
break;
|
||||
else
|
||||
close(accsocket);
|
||||
close(accsocket);
|
||||
}
|
||||
else if (errno != EINTR) {
|
||||
perror("accept");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i=0; i<currmax; i++) {
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -352,15 +356,14 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
|
||||
if (strcmp(ANYDEV, argv[optind+i])) {
|
||||
if (strcmp(ANYDEV, argv[optind + i]) != 0) {
|
||||
strcpy(ifr.ifr_name, argv[optind+i]);
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
exit(1);
|
||||
}
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
}
|
||||
else
|
||||
} else
|
||||
addr.can_ifindex = 0; /* any can interface */
|
||||
|
||||
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
@@ -409,7 +412,7 @@ int main(int argc, char **argv)
|
||||
|
||||
idx = idx2dindex(addr.can_ifindex, s[i]);
|
||||
|
||||
sprintf(temp, "(%ld.%06ld) %*s ",
|
||||
sprintf(temp, "(%lu.%06lu) %*s ",
|
||||
tv.tv_sec, tv.tv_usec, max_devname_len, devname[idx]);
|
||||
sprint_canframe(temp+strlen(temp), &frame, 0, maxdlen);
|
||||
strcat(temp, "\n");
|
||||
@@ -421,7 +424,7 @@ int main(int argc, char **argv)
|
||||
|
||||
#if 0
|
||||
/* print CAN frame in log file style to stdout */
|
||||
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
||||
printf("%*s ", max_devname_len, devname[idx]);
|
||||
fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
|
||||
#endif
|
||||
|
||||
+55
-36
@@ -42,19 +42,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -77,30 +77,34 @@ extern int optind, opterr, optopt;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - replay a compact CAN frame logfile to CAN devices.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s <options> [interface assignment]*\n\n", prg);
|
||||
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -l <num> "
|
||||
"(process input file <num> times)\n"
|
||||
" "
|
||||
"(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS);
|
||||
fprintf(stderr, " -t (ignore timestamps: "
|
||||
"send frames immediately)\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli "
|
||||
"seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -s <s> (skip gaps in "
|
||||
"timestamps > 's' seconds)\n");
|
||||
fprintf(stderr, " -x (disable local "
|
||||
"loopback of sent CAN frames)\n");
|
||||
fprintf(stderr, " -v (verbose: print "
|
||||
"sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Interface assignment: 0..n assignments like "
|
||||
"<write-if>=<log-if>\n");
|
||||
fprintf(stderr, "e.g. vcan2=can0 ( send frames received from can0 on "
|
||||
"vcan2 )\n");
|
||||
fprintf(stderr, "extra hook: stdout=can0 ( print logfile line marked with can0 on "
|
||||
"stdout )\n");
|
||||
fprintf(stderr, "No assignments => send frames to the interface(s) they "
|
||||
"had been received from.\n\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -l <num> "
|
||||
"(process input file <num> times)\n"
|
||||
" "
|
||||
"(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS);
|
||||
fprintf(stderr, " -t (ignore timestamps: "
|
||||
"send frames immediately)\n");
|
||||
fprintf(stderr, " -i (interactive - wait "
|
||||
"for ENTER key to process next frame)\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli "
|
||||
"seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -s <s> (skip gaps in "
|
||||
"timestamps > 's' seconds)\n");
|
||||
fprintf(stderr, " -x (disable local "
|
||||
"loopback of sent CAN frames)\n");
|
||||
fprintf(stderr, " -v (verbose: print "
|
||||
"sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Interface assignment:\n");
|
||||
fprintf(stderr, " 0..n assignments like <write-if>=<log-if>\n\n");
|
||||
fprintf(stderr, " e.g. vcan2=can0 (send frames received from can0 on "
|
||||
"vcan2)\n");
|
||||
fprintf(stderr, " extra hook: stdout=can0 (print logfile line marked with can0 on "
|
||||
"stdout)\n");
|
||||
fprintf(stderr, " No assignments => send frames to the interface(s) they "
|
||||
"had been received from\n\n");
|
||||
fprintf(stderr, "Lines in the logfile not beginning with '(' (start of "
|
||||
"timestamp) are ignored.\n\n");
|
||||
}
|
||||
@@ -137,7 +141,7 @@ static inline int frames_to_send(struct timeval *today, struct timeval *diff,
|
||||
cmp.tv_sec = log->tv_sec + diff->tv_sec;
|
||||
cmp.tv_usec = log->tv_usec + diff->tv_usec;
|
||||
|
||||
if (cmp.tv_usec > 1000000) {
|
||||
if (cmp.tv_usec >= 1000000) {
|
||||
cmp.tv_usec -= 1000000;
|
||||
cmp.tv_sec++;
|
||||
}
|
||||
@@ -213,7 +217,7 @@ int add_assignment(char *mode, int socket, char *txname, char *rxname,
|
||||
}
|
||||
strcpy(asgn[i].rxif, rxname);
|
||||
|
||||
if (strcmp(txname, "stdout")) {
|
||||
if (strcmp(txname, "stdout") != 0) {
|
||||
strcpy(ifr.ifr_name, txname);
|
||||
if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
@@ -242,6 +246,7 @@ int main(int argc, char **argv)
|
||||
FILE *infile = stdin;
|
||||
unsigned long gap = DEFAULT_GAP;
|
||||
int use_timestamps = 1;
|
||||
int interactive = 0; /* wait for ENTER keypress to process next frame */
|
||||
static int verbose, opt, delay_loops;
|
||||
static unsigned long skipgap;
|
||||
static int loopback_disable = 0;
|
||||
@@ -252,7 +257,7 @@ int main(int argc, char **argv)
|
||||
int eof, txmtu, i, j;
|
||||
char *fret;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:l:tg:s:xv?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:l:tig:s:xv?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -276,6 +281,10 @@ int main(int argc, char **argv)
|
||||
use_timestamps = 0;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
interactive = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
gap = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
@@ -318,6 +327,12 @@ int main(int argc, char **argv)
|
||||
printf("%d loops\n", loops);
|
||||
}
|
||||
|
||||
/* ignore timestamps from logfile when in single step keypress mode */
|
||||
if (interactive) {
|
||||
use_timestamps = 0;
|
||||
printf("interactive mode: press ENTER to process next CAN frame ...\n");
|
||||
}
|
||||
|
||||
sleep_ts.tv_sec = gap / 1000;
|
||||
sleep_ts.tv_nsec = (gap % 1000) * 1000000;
|
||||
|
||||
@@ -357,7 +372,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
strcpy(buf, argv[optind+i]);
|
||||
for (j=0; j<BUFSZ; j++) { /* find '=' in assignment */
|
||||
for (j=0; j<(int)BUFSZ; j++) { /* find '=' in assignment */
|
||||
if (buf[j] == '=')
|
||||
break;
|
||||
}
|
||||
@@ -393,7 +408,7 @@ int main(int argc, char **argv)
|
||||
|
||||
eof = 0;
|
||||
|
||||
if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
@@ -411,6 +426,10 @@ int main(int argc, char **argv)
|
||||
while ((!use_timestamps) ||
|
||||
(frames_to_send(&today_tv, &diff_tv, &log_tv) < 0)) {
|
||||
|
||||
/* wait for keypress to process next frame */
|
||||
if (interactive)
|
||||
getchar();
|
||||
|
||||
/* log_tv/device/ascframe are valid here */
|
||||
|
||||
if (strlen(device) >= IFNAMSIZ) {
|
||||
@@ -472,7 +491,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
@@ -493,7 +512,7 @@ int main(int argc, char **argv)
|
||||
/* test for logfile timestamps jumping backwards OR */
|
||||
/* if the user likes to skip long gaps in the timestamps */
|
||||
if ((last_log_tv.tv_sec > log_tv.tv_sec) ||
|
||||
(skipgap && labs(last_log_tv.tv_sec - log_tv.tv_sec) > skipgap))
|
||||
(skipgap && labs(last_log_tv.tv_sec - log_tv.tv_sec) > (long)skipgap))
|
||||
create_diff_tv(&today_tv, &diff_tv, &log_tv);
|
||||
|
||||
last_log_tv = log_tv;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets
|
||||
* cansend.c - send CAN-frames via CAN_RAW sockets
|
||||
*
|
||||
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
@@ -56,6 +56,33 @@
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
|
||||
fprintf(stderr, "\n<can_frame>:\n");
|
||||
fprintf(stderr, " <can_id>#{data} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#{data}_{dlc} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len}_{dlc} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
|
||||
fprintf(stderr, "<can_id>:\n"
|
||||
" 3 (SFF) or 8 (EFF) hex chars\n");
|
||||
fprintf(stderr, "{data}:\n"
|
||||
" 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
|
||||
fprintf(stderr, "{len}:\n"
|
||||
" an optional 0..8 value as RTR frames can contain a valid dlc field\n");
|
||||
fprintf(stderr, "_{dlc}:\n"
|
||||
" an optional 9..F data length code value when payload length is 8\n");
|
||||
fprintf(stderr, "<flags>:\n"
|
||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
|
||||
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int s; /* can raw socket */
|
||||
@@ -68,27 +95,15 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check command line options */
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <device> <can_frame>.\n", argv[0]);
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse CAN frame */
|
||||
required_mtu = parse_canframe(argv[2], &frame);
|
||||
if (!required_mtu){
|
||||
fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n");
|
||||
fprintf(stderr, " <can_id>#{data} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for 'classic' CAN 2.0 RTR frames\n");
|
||||
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
|
||||
fprintf(stderr, "<can_id> can have 3 (SFF) or 8 (EFF) hex chars\n");
|
||||
fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally");
|
||||
fprintf(stderr, " separated by '.')\n");
|
||||
fprintf(stderr, "{len} is an optional 0..8 value as RTR frames can contain a");
|
||||
fprintf(stderr, " valid dlc field\n");
|
||||
fprintf(stderr, "<flags> a single ASCII Hex value (0 .. F) which defines");
|
||||
fprintf(stderr, " canfd_frame.flags\n\n");
|
||||
fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / ");
|
||||
fprintf(stderr, "123##1 / 213##311223344\n 1F334455#1122334455667788 / ");
|
||||
fprintf(stderr, "123#R / 00000123#R3\n\n");
|
||||
fprintf(stderr, "\nWrong CAN-frame format!\n\n");
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -110,7 +125,7 @@ int main(int argc, char **argv)
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
if (required_mtu > CAN_MTU) {
|
||||
if (required_mtu > (int)CAN_MTU) {
|
||||
|
||||
/* check if the frame fits into the CAN netdevice */
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||
@@ -132,7 +147,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
||||
frame.len = can_dlc2len(can_len2dlc(frame.len));
|
||||
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
|
||||
}
|
||||
|
||||
/* disable default receive filter on this RAW socket */
|
||||
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
// Copyright (c) 2007, 2008, 2009, 2010, 2014, 2015, 2019 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
// Copyright (c) 2005 Pengutronix,
|
||||
// Sascha Hauer <kernel@pengutronix.de>
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#define CAN_ID_DEFAULT (2)
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static int s = -1;
|
||||
static bool running = true;
|
||||
static bool infinite = true;
|
||||
static unsigned int drop_until_quit;
|
||||
static unsigned int drop_count;
|
||||
static bool use_poll = false;
|
||||
|
||||
static unsigned int loopcount = 1;
|
||||
static int verbose;
|
||||
|
||||
static struct can_frame frame = {
|
||||
.can_dlc = 1,
|
||||
};
|
||||
static struct can_filter filter[] = {
|
||||
{ .can_id = CAN_ID_DEFAULT, },
|
||||
};
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [<can-interface>] [Options]\n"
|
||||
"\n"
|
||||
"cansequence sends CAN messages with a rising sequence number as payload.\n"
|
||||
"When the -r option is given, cansequence expects to receive these messages\n"
|
||||
"and prints an error message if a wrong sequence number is encountered.\n"
|
||||
"The main purpose of this program is to test the reliability of CAN links.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -e, --extended send extended frame\n"
|
||||
" -i, --identifier=ID CAN Identifier (default = %u)\n"
|
||||
" --loop=COUNT send message COUNT times\n"
|
||||
" -p, --poll use poll(2) to wait for buffer space while sending\n"
|
||||
" -q, --quit <num> quit if <num> wrong sequences are encountered\n"
|
||||
" -r, --receive work as receiver\n"
|
||||
" -v, --verbose be verbose (twice to be even more verbose\n"
|
||||
" -h, --help this help\n"
|
||||
" --version print version information and exit\n",
|
||||
prg, CAN_ID_DEFAULT);
|
||||
}
|
||||
|
||||
static void sig_handler(int signo)
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
|
||||
|
||||
static void do_receive()
|
||||
{
|
||||
uint8_t ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
|
||||
struct iovec iov = {
|
||||
.iov_base = &frame,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &ctrlmsg,
|
||||
};
|
||||
const int dropmonitor_on = 1;
|
||||
bool sequence_init = true;
|
||||
unsigned int sequence_wrap = 0;
|
||||
uint32_t sequence_mask = 0xff;
|
||||
uint32_t sequence_rx = 0;
|
||||
uint32_t sequence_delta = 0;
|
||||
uint32_t sequence = 0;
|
||||
unsigned int overflow_old = 0;
|
||||
can_err_mask_t err_mask = CAN_ERR_MASK;
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RXQ_OVFL,
|
||||
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
|
||||
perror("setsockopt() SO_RXQ_OVFL not supported by your Linux Kernel");
|
||||
}
|
||||
|
||||
/* enable recv. of error messages */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask))) {
|
||||
perror("setsockopt()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* enable recv. now */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, filter, sizeof(filter))) {
|
||||
perror("setsockopt()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while ((infinite || loopcount--) && running) {
|
||||
ssize_t nbytes;
|
||||
|
||||
msg.msg_iov[0].iov_len = sizeof(frame);
|
||||
msg.msg_controllen = sizeof(ctrlmsg);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
nbytes = recvmsg(s, &msg, 0);
|
||||
if (nbytes < 0) {
|
||||
perror("read()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (frame.can_id & CAN_ERR_FLAG) {
|
||||
fprintf(stderr,
|
||||
"sequence CNT: %6u, ERRORFRAME %7x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
sequence, frame.can_id,
|
||||
frame.data[0], frame.data[1], frame.data[2], frame.data[3],
|
||||
frame.data[4], frame.data[5], frame.data[6], frame.data[7]);
|
||||
continue;
|
||||
}
|
||||
|
||||
sequence_rx = frame.data[0];
|
||||
|
||||
if (sequence_init) {
|
||||
sequence_init = false;
|
||||
sequence = sequence_rx;
|
||||
}
|
||||
|
||||
sequence_delta = (sequence_rx - sequence) & sequence_mask;
|
||||
if (sequence_delta) {
|
||||
struct cmsghdr *cmsg;
|
||||
uint32_t overflow = 0;
|
||||
uint32_t overflow_delta;
|
||||
|
||||
drop_count++;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_RXQ_OVFL) {
|
||||
memcpy(&overflow, CMSG_DATA(cmsg), sizeof(overflow));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
overflow_delta = overflow - overflow_old;
|
||||
|
||||
fprintf(stderr,
|
||||
"sequence CNT: %6u, RX: %6u expected: %3u missing: %4u skt overfl d: %4u a: %4u delta: %3u incident: %u\n",
|
||||
sequence, sequence_rx,
|
||||
sequence & sequence_mask, sequence_delta,
|
||||
overflow_delta, overflow,
|
||||
sequence_delta - overflow_delta,
|
||||
drop_count);
|
||||
|
||||
if (drop_count == drop_until_quit)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
sequence = sequence_rx;
|
||||
overflow_old = overflow;
|
||||
} else if (verbose > 1) {
|
||||
printf("sequence CNT: %6u, RX: %6u\n", sequence, sequence_rx);
|
||||
}
|
||||
|
||||
sequence++;
|
||||
if (verbose && !(sequence & sequence_mask))
|
||||
printf("sequence wrap around (%d)\n", sequence_wrap++);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void do_send()
|
||||
{
|
||||
unsigned int seq_wrap = 0;
|
||||
uint8_t sequence = 0;
|
||||
|
||||
while ((infinite || loopcount--) && running) {
|
||||
ssize_t len;
|
||||
|
||||
if (verbose > 1)
|
||||
printf("sending frame. sequence number: %d\n", sequence);
|
||||
|
||||
again:
|
||||
len = write(s, &frame, sizeof(frame));
|
||||
if (len == -1) {
|
||||
switch (errno) {
|
||||
case ENOBUFS: {
|
||||
int err;
|
||||
struct pollfd fds[] = {
|
||||
{
|
||||
.fd = s,
|
||||
.events = POLLOUT,
|
||||
},
|
||||
};
|
||||
|
||||
if (!use_poll) {
|
||||
perror("write");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
err = poll(fds, 1, 1000);
|
||||
if (err == -1 && errno != -EINTR) {
|
||||
perror("poll()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
case EINTR: /* fallthrough */
|
||||
goto again;
|
||||
default:
|
||||
perror("write");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
frame.data[0]++;
|
||||
sequence++;
|
||||
|
||||
if (verbose && !sequence)
|
||||
printf("sequence wrap around (%d)\n", seq_wrap++);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct sigaction act = {
|
||||
.sa_handler = sig_handler,
|
||||
};
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_can addr;
|
||||
char *interface = "can0";
|
||||
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
|
||||
int extended = 0;
|
||||
int receive = 0;
|
||||
int opt;
|
||||
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
sigaction(SIGHUP, &act, NULL);
|
||||
|
||||
struct option long_options[] = {
|
||||
{ "extended", no_argument, 0, 'e' },
|
||||
{ "identifier", required_argument, 0, 'i' },
|
||||
{ "loop", required_argument, 0, 'l' },
|
||||
{ "poll", no_argument, 0, 'p' },
|
||||
{ "quit", optional_argument, 0, 'q' },
|
||||
{ "receive", no_argument, 0, 'r' },
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'e':
|
||||
extended = true;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
filter->can_id = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
receive = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (optarg) {
|
||||
loopcount = strtoul(optarg, NULL, 0);
|
||||
infinite = false;
|
||||
} else {
|
||||
infinite = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
use_poll = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
if (optarg)
|
||||
drop_until_quit = strtoul(optarg, NULL, 0);
|
||||
else
|
||||
drop_until_quit = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[optind] != NULL)
|
||||
interface = argv[optind];
|
||||
|
||||
if (extended) {
|
||||
filter->can_mask = CAN_EFF_MASK;
|
||||
filter->can_id &= CAN_EFF_MASK;
|
||||
filter->can_id |= CAN_EFF_FLAG;
|
||||
} else {
|
||||
filter->can_mask = CAN_SFF_MASK;
|
||||
filter->can_id &= CAN_SFF_MASK;
|
||||
}
|
||||
frame.can_id = filter->can_id;
|
||||
filter->can_mask |= CAN_EFF_FLAG;
|
||||
|
||||
printf("interface = %s, family = %d, type = %d, proto = %d\n",
|
||||
interface, family, type, proto);
|
||||
|
||||
s = socket(family, type, proto);
|
||||
if (s < 0) {
|
||||
perror("socket()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
addr.can_family = family;
|
||||
strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
|
||||
if (ioctl(s, SIOCGIFINDEX, &ifr)) {
|
||||
perror("ioctl()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
/* first don't recv. any msgs */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0)) {
|
||||
perror("setsockopt()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
do_receive();
|
||||
else
|
||||
do_send();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+386
-295
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -19,7 +19,7 @@ CFLAGS="${CFLAGS} -Wall"
|
||||
AC_PROG_CC
|
||||
LT_INIT(win32-dll)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2])
|
||||
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2 subdir-objects])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
#
|
||||
|
||||
+35
-16
@@ -84,6 +84,7 @@ typedef __u32 can_err_mask_t;
|
||||
|
||||
/* CAN payload length and DLC definitions according to ISO 11898-1 */
|
||||
#define CAN_MAX_DLC 8
|
||||
#define CAN_MAX_RAW_DLC 15
|
||||
#define CAN_MAX_DLEN 8
|
||||
|
||||
/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
|
||||
@@ -91,30 +92,39 @@ typedef __u32 can_err_mask_t;
|
||||
#define CANFD_MAX_DLEN 64
|
||||
|
||||
/**
|
||||
* struct can_frame - basic CAN frame structure
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code
|
||||
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
|
||||
* mapping of the 'data length code' to the real payload length
|
||||
* @__pad: padding
|
||||
* @__res0: reserved / padding
|
||||
* @__res1: reserved / padding
|
||||
* @data: CAN frame payload (up to 8 byte)
|
||||
* struct can_frame - Classical CAN frame structure (aka CAN 2.0B)
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
* @len: CAN frame payload length in byte (0 .. 8)
|
||||
* @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8)
|
||||
* @__pad: padding
|
||||
* @__res0: reserved / padding
|
||||
* @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length
|
||||
* len8_dlc contains values from 9 .. 15 when the payload length is
|
||||
* 8 bytes but the DLC value (see ISO 11898-1) is greater then 8.
|
||||
* CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver.
|
||||
* @data: CAN frame payload (up to 8 byte)
|
||||
*/
|
||||
struct can_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
|
||||
__u8 __pad; /* padding */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 __res1; /* reserved / padding */
|
||||
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
|
||||
union {
|
||||
/* CAN frame payload length in byte (0 .. CAN_MAX_DLEN)
|
||||
* was previously named can_dlc so we need to carry that
|
||||
* name for legacy support
|
||||
*/
|
||||
__u8 len;
|
||||
__u8 can_dlc; /* deprecated */
|
||||
} __attribute__((packed)); /* disable padding added in some ABIs */
|
||||
__u8 __pad; /* padding */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */
|
||||
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
* defined bits for canfd_frame.flags
|
||||
*
|
||||
* The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
|
||||
* be set in the CAN frame bitstream on the wire. The EDL bit switch turns
|
||||
* The use of struct canfd_frame implies the FD Frame (FDF) bit to
|
||||
* be set in the CAN frame bitstream on the wire. The FDF bit switch turns
|
||||
* the CAN controllers bitstream processor into the CAN FD mode which creates
|
||||
* two new options within the CAN FD frame specification:
|
||||
*
|
||||
@@ -125,9 +135,18 @@ struct can_frame {
|
||||
* controller only the CANFD_BRS bit is relevant for real CAN controllers when
|
||||
* building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
|
||||
* sense for virtual CAN interfaces to test applications with echoed frames.
|
||||
*
|
||||
* The struct can_frame and struct canfd_frame intentionally share the same
|
||||
* layout to be able to write CAN frame content into a CAN FD frame structure.
|
||||
* When this is done the former differentiation via CAN_MTU / CANFD_MTU gets
|
||||
* lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of
|
||||
* using struct canfd_frame for mixed CAN / CAN FD content (dual use).
|
||||
* N.B. the Kernel APIs do NOT provide mixed CAN / CAN FD content inside of
|
||||
* struct canfd_frame therefore the CANFD_FDF flag is disregarded by Linux.
|
||||
*/
|
||||
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
|
||||
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
|
||||
#define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */
|
||||
|
||||
/**
|
||||
* struct canfd_frame - CAN flexible data rate frame structure
|
||||
|
||||
@@ -98,8 +98,8 @@ enum {
|
||||
|
||||
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
|
||||
#define CGW_MOD_ID 0x01
|
||||
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */
|
||||
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */
|
||||
#define CGW_MOD_DLC 0x02 /* Classical CAN data length code */
|
||||
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD (plain) data length */
|
||||
#define CGW_MOD_DATA 0x04
|
||||
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/*
|
||||
* linux/can/isotp.h
|
||||
*
|
||||
* Definitions for isotp CAN sockets
|
||||
* Definitions for isotp CAN sockets (ISO 15765-2:2016)
|
||||
*
|
||||
* Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
|
||||
* Copyright (c) 2008 Volkswagen Group Electronic Research
|
||||
* Copyright (c) 2020 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -39,13 +39,12 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* Send feedback to <linux-can@vger.kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef CAN_ISOTP_H
|
||||
#define CAN_ISOTP_H
|
||||
#ifndef _UAPI_CAN_ISOTP_H
|
||||
#define _UAPI_CAN_ISOTP_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/can.h>
|
||||
|
||||
#define SOL_CAN_ISOTP (SOL_CAN_BASE + CAN_ISOTP)
|
||||
@@ -123,7 +122,6 @@ struct can_isotp_ll_options {
|
||||
/* by the CAN netdriver configuration */
|
||||
};
|
||||
|
||||
|
||||
/* flags for isotp behaviour */
|
||||
|
||||
#define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */
|
||||
@@ -136,7 +134,8 @@ struct can_isotp_ll_options {
|
||||
#define CAN_ISOTP_FORCE_TXSTMIN 0x080 /* ignore stmin from received FC */
|
||||
#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */
|
||||
#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */
|
||||
|
||||
#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */
|
||||
#define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */
|
||||
|
||||
/* default values */
|
||||
|
||||
@@ -161,7 +160,6 @@ struct can_isotp_ll_options {
|
||||
* these default settings can be changed via sockopts.
|
||||
* For that reason the STmin value is intentionally _not_ checked for
|
||||
* consistency and copied directly into the flow control (FC) frame.
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
#endif /* !_UAPI_CAN_ISOTP_H */
|
||||
|
||||
@@ -100,6 +100,7 @@ struct can_ctrlmode {
|
||||
#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
|
||||
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
|
||||
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
|
||||
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
|
||||
|
||||
/*
|
||||
* CAN device statistics
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#include <linux/can.h>
|
||||
|
||||
#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW)
|
||||
enum {
|
||||
SCM_CAN_RAW_ERRQUEUE = 1,
|
||||
};
|
||||
|
||||
/* for socket options affecting the socket (not the global system) */
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _LINUX_KERNEL_H
|
||||
#define _LINUX_KERNEL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint32_t __le32;
|
||||
|
||||
struct mcp251xfd_mem;
|
||||
|
||||
struct regmap {
|
||||
struct mcp251xfd_mem *mem;
|
||||
};
|
||||
|
||||
#define pr_info(...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define pr_cont(...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define BUILD_BUG_ON(...)
|
||||
|
||||
#define BITS_PER_LONG (sizeof(long) * 8)
|
||||
|
||||
#define ____cacheline_aligned
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
int regmap_bulk_read(struct regmap *map, unsigned int reg,
|
||||
void *val, size_t val_count);
|
||||
|
||||
#define SZ_2K 0x00000800
|
||||
|
||||
#define __packed __attribute__((__packed__))
|
||||
|
||||
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
|
||||
|
||||
#define BIT(nr) (UL(1) << (nr))
|
||||
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#define _AC(X,Y) X
|
||||
#define _AT(T,X) X
|
||||
#else
|
||||
#define __AC(X,Y) (X##Y)
|
||||
#define _AC(X,Y) __AC(X,Y)
|
||||
#define _AT(T,X) ((T)(X))
|
||||
#endif
|
||||
|
||||
#define _UL(x) (_AC(x, UL))
|
||||
#define _ULL(x) (_AC(x, ULL))
|
||||
|
||||
#define UL(x) (_UL(x))
|
||||
#define ULL(x) (_ULL(x))
|
||||
|
||||
#define GENMASK(h, l) \
|
||||
(((~UL(0)) - (UL(1) << (l)) + 1) & \
|
||||
(~UL(0) >> (BITS_PER_LONG - 1 - (h))))
|
||||
|
||||
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
|
||||
|
||||
#define FIELD_PREP(_mask, _val) \
|
||||
({ \
|
||||
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
|
||||
})
|
||||
|
||||
#define FIELD_GET(_mask, _reg) \
|
||||
({ \
|
||||
(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
|
||||
})
|
||||
|
||||
#define min_t(type, x, y) ({ \
|
||||
type __min1 = (x); \
|
||||
type __min2 = (y); \
|
||||
__min1 < __min2 ? __min1 : __min2; })
|
||||
|
||||
#define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
|
||||
|
||||
static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
static inline u8 can_dlc2len(u8 can_dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
}
|
||||
|
||||
#endif /* _LINUX_KERNEL_H */
|
||||
@@ -96,7 +96,7 @@ struct nlmsghdr {
|
||||
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
|
||||
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
|
||||
(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
|
||||
(nlh)->nlmsg_len <= (len))
|
||||
(int)((nlh)->nlmsg_len) <= (len))
|
||||
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
|
||||
|
||||
#define NLMSG_NOOP 0x1 /* Nothing. */
|
||||
|
||||
+71
-67
@@ -42,22 +42,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#include "terminal.h"
|
||||
|
||||
#define NO_CAN_ID 0xFFFFFFFFU
|
||||
@@ -68,20 +69,23 @@ const int canfd_on = 1;
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
|
||||
fprintf(stderr, " -c (color mode)\n");
|
||||
fprintf(stderr, " -a (print data also in ASCII-chars)\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -u (print uds messages)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
|
||||
fprintf(stderr, " -c (color mode)\n");
|
||||
fprintf(stderr, " -a (print data also in ASCII-chars)\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -u (print uds messages)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "\nUDS output contains a flag which provides information about the type of the message.\n");
|
||||
fprintf(stderr, "Flags: [SRQ] = Service Request\n");
|
||||
fprintf(stderr, " [PSR] = Positive Service Response\n");
|
||||
fprintf(stderr, " [NRC] = Negative Response Code\n");
|
||||
fprintf(stderr, " [???] = Unknown (not specified)\n");
|
||||
fprintf(stderr, "\nUDS output contains a flag which provides information about the type of the \n");
|
||||
fprintf(stderr, "message.\n\n");
|
||||
fprintf(stderr, "Flags:\n");
|
||||
fprintf(stderr, " [SRQ] = Service Request\n");
|
||||
fprintf(stderr, " [PSR] = Positive Service Response\n");
|
||||
fprintf(stderr, " [NRC] = Negative Response Code\n");
|
||||
fprintf(stderr, " [???] = Unknown (not specified)\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -332,65 +336,66 @@ int main(int argc, char **argv)
|
||||
if (nbytes < 0) {
|
||||
perror("read");
|
||||
return 1;
|
||||
} else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
}
|
||||
if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
fprintf(stderr, "read: incomplete CAN frame %zu %d\n", sizeof(frame), nbytes);
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
if (frame.can_id == src && ext && !extany &&
|
||||
extaddr != frame.data[0])
|
||||
continue;
|
||||
|
||||
if (frame.can_id == src && ext && !extany && extaddr != frame.data[0])
|
||||
continue;
|
||||
if (frame.can_id == dst && rx_ext && !rx_extany &&
|
||||
rx_extaddr != frame.data[0])
|
||||
continue;
|
||||
|
||||
if (frame.can_id == dst && rx_ext && !rx_extany && rx_extaddr != frame.data[0])
|
||||
continue;
|
||||
if (color)
|
||||
printf("%s", (frame.can_id == src) ? FGRED : FGBLUE);
|
||||
|
||||
if (color)
|
||||
printf("%s", (frame.can_id == src)? FGRED:FGBLUE);
|
||||
if (timestamp) {
|
||||
ioctl(s, SIOCGSTAMP, &tv);
|
||||
|
||||
if (timestamp) {
|
||||
ioctl(s, SIOCGSTAMP, &tv);
|
||||
|
||||
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06ld) ", timestring, tv.tv_usec);
|
||||
}
|
||||
switch (timestamp) {
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
if (last_tv.tv_sec == 0) /* first init */
|
||||
last_tv = tv;
|
||||
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S",
|
||||
&tm);
|
||||
printf("(%s.%06lu) ", timestring, tv.tv_usec);
|
||||
} break;
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv = tv; /* update for delta calculation */
|
||||
}
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
if (last_tv.tv_sec == 0) /* first init */
|
||||
last_tv = tv;
|
||||
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%lu.%06lu) ", diff.tv_sec,
|
||||
diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv =
|
||||
tv; /* update for delta calculation */
|
||||
} break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
printf(" %s %8X", argv[optind], frame.can_id & CAN_EFF_MASK);
|
||||
@@ -407,7 +412,7 @@ int main(int argc, char **argv)
|
||||
|
||||
datidx = 0;
|
||||
n_pci = frame.data[ext];
|
||||
|
||||
|
||||
switch (n_pci & 0xF0) {
|
||||
case 0x00:
|
||||
is_ff = 1;
|
||||
@@ -498,7 +503,6 @@ int main(int argc, char **argv)
|
||||
printf("%s", ATTRESET);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
+30
-27
@@ -42,18 +42,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
@@ -65,11 +65,13 @@
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - ISO15765-2 protocol performance visualisation.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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, " -x <addr> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr))\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -x <addr> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr))\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -221,19 +223,21 @@ int main(int argc, char **argv)
|
||||
ret = nbytes;
|
||||
running = 0;
|
||||
continue;
|
||||
} else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
}
|
||||
if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
|
||||
fprintf(stderr, "read: incomplete CAN frame %zu %d\n", sizeof(frame), nbytes);
|
||||
ret = nbytes;
|
||||
running = 0;
|
||||
continue;
|
||||
} else {
|
||||
if (rcvlen) {
|
||||
/* make sure to process only the detected PDU CAN frame type */
|
||||
if (canfd_on && (nbytes != CANFD_MTU))
|
||||
continue;
|
||||
if (!canfd_on && (nbytes != CAN_MTU))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcvlen) {
|
||||
/* make sure to process only the detected PDU CAN frame type */
|
||||
if (canfd_on && (nbytes != CANFD_MTU))
|
||||
continue;
|
||||
if (!canfd_on && (nbytes != CAN_MTU))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check extended address if provided */
|
||||
if (ext && extaddr != frame.data[0])
|
||||
@@ -247,13 +251,13 @@ int main(int argc, char **argv)
|
||||
|
||||
n_pci = frame.data[rx_ext];
|
||||
/* check flow control PCI only */
|
||||
if ((n_pci & 0xF0) == 0x30) {
|
||||
bs = frame.data[rx_ext+1];
|
||||
stmin = frame.data[rx_ext+2];
|
||||
} else
|
||||
if ((n_pci & 0xF0) != 0x30)
|
||||
continue;
|
||||
|
||||
bs = frame.data[rx_ext + 1];
|
||||
stmin = frame.data[rx_ext + 2];
|
||||
}
|
||||
|
||||
|
||||
/* data content starts and index datidx */
|
||||
datidx = 0;
|
||||
|
||||
@@ -353,7 +357,7 @@ int main(int argc, char **argv)
|
||||
if (rcvlen) {
|
||||
if (rcvlen > fflen)
|
||||
rcvlen = fflen;
|
||||
|
||||
|
||||
percent = (rcvlen * 100 / fflen);
|
||||
printf("\r %3lu%% ", percent);
|
||||
|
||||
@@ -363,7 +367,7 @@ int main(int argc, char **argv)
|
||||
percent = 100;
|
||||
|
||||
for (i=0; i < NUMBAR; i++){
|
||||
if (i < percent/PERCENTRES)
|
||||
if (i < (int)(percent/PERCENTRES))
|
||||
printf("X");
|
||||
else
|
||||
printf(".");
|
||||
@@ -395,7 +399,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check devisor to be not zero */
|
||||
if (diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000){
|
||||
printf("%ld.%06lds ", diff_tv.tv_sec, diff_tv.tv_usec);
|
||||
printf("%lu.%06lus ", diff_tv.tv_sec, diff_tv.tv_usec);
|
||||
printf("=> %lu byte/s", (fflen * 1000) /
|
||||
(diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000));
|
||||
} else
|
||||
@@ -406,7 +410,6 @@ int main(int argc, char **argv)
|
||||
fflen = rcvlen = 0;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
close(s);
|
||||
|
||||
+16
-15
@@ -42,16 +42,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -62,17 +62,18 @@
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -f <time ns> (force rx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
|
||||
fprintf(stderr, " -l (loop: do not exit after pdu reception.)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -f <time ns> (force rx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
|
||||
fprintf(stderr, " -l (loop: do not exit after pdu reception.)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "The pdu data is written on STDOUT in space separated ASCII hex values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
+26
-14
@@ -42,16 +42,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -62,15 +62,18 @@
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
|
||||
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
|
||||
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
|
||||
fprintf(stderr, " -b (block until the PDU transmission is completed)\n");
|
||||
fprintf(stderr, " -S (SF broadcast mode for functional addressing)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
@@ -92,7 +95,7 @@ int main(int argc, char **argv)
|
||||
|
||||
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:?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bSL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
@@ -175,6 +178,14 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
opts.flags |= CAN_ISOTP_SF_BROADCAST;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
@@ -201,7 +212,8 @@ int main(int argc, char **argv)
|
||||
|
||||
if ((argc - optind != 1) ||
|
||||
(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) &&
|
||||
(!(opts.flags & CAN_ISOTP_SF_BROADCAST)))) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+33
-29
@@ -57,21 +57,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -100,28 +101,29 @@ void childdied(int i)
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s -l <port> -s <can_id> -d <can_id> [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: (* = mandatory)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, "ip addressing:\n");
|
||||
fprintf(stderr, " * -l <port> (local port for the server)\n");
|
||||
fprintf(stderr, " -l <port> * (local port for the server)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "isotp addressing:\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, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\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, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "padding:\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "rx path: (config, which is sent to the sender / data source)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions)\n");
|
||||
fprintf(stderr, "rx path:\n (config, which is sent to the sender / data source)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "tx path: (config, which changes local tx settings)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, "tx path:\n (config, which changes local tx settings)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "(* = mandatory option)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "All values except for '-l' and '-t' are expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
@@ -298,9 +300,13 @@ int main(int argc, char **argv)
|
||||
saddr.sin_port = htons(local_port);
|
||||
|
||||
while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
|
||||
struct timespec f = {
|
||||
.tv_nsec = 100 * 1000 * 1000,
|
||||
};
|
||||
|
||||
printf(".");
|
||||
fflush(NULL);
|
||||
usleep(100000);
|
||||
nanosleep(&f, NULL);
|
||||
}
|
||||
|
||||
if (listen(sl, 3) != 0) {
|
||||
@@ -311,11 +317,9 @@ int main(int argc, char **argv)
|
||||
while (1) {
|
||||
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
|
||||
if (sa > 0 ){
|
||||
|
||||
if (fork())
|
||||
close(sa);
|
||||
else
|
||||
if (!fork())
|
||||
break;
|
||||
close(sa);
|
||||
}
|
||||
else {
|
||||
if (errno != EINTR) {
|
||||
|
||||
+19
-23
@@ -42,23 +42,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
#include <linux/sockios.h>
|
||||
#include "terminal.h"
|
||||
|
||||
#define NO_CAN_ID 0xFFFFFFFFU
|
||||
|
||||
@@ -69,14 +69,15 @@
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||
fprintf(stderr, "Options: -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, " -x <addr> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode - rx addr)\n");
|
||||
fprintf(stderr, " -c (color mode)\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -x <addr> (extended addressing mode)\n");
|
||||
fprintf(stderr, " -X <addr> (extended addressing mode - rx addr)\n");
|
||||
fprintf(stderr, " -c (color mode)\n");
|
||||
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
|
||||
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "\n");
|
||||
@@ -100,7 +101,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
|
||||
printf("(%lu.%06lu) ", tv->tv_sec, tv->tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
@@ -110,7 +111,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
|
||||
|
||||
tm = *localtime(&tv->tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06ld) ", timestring, tv->tv_usec);
|
||||
printf("(%s.%06lu) ", timestring, tv->tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -127,7 +128,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
|
||||
printf("(%lu.%06lu) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
*last_tv = *tv; /* update for delta calculation */
|
||||
@@ -322,12 +323,7 @@ int main(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
|
||||
perror("setsockopt");
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
if ((setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
|
||||
if ((llopts.mtu) && (setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
|
||||
perror("setsockopt");
|
||||
r = 1;
|
||||
goto out;
|
||||
|
||||
+24
-22
@@ -48,21 +48,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/isotp.h>
|
||||
@@ -102,23 +102,25 @@ void perror_syslog(const char *s)
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - IP over CAN ISO-TP (ISO15765-2) tunnel / proof-of-concept.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n\n", prg);
|
||||
fprintf(stderr, "This program creates a Linux tunnel netdevice 'ctunX' and transfers the\n");
|
||||
fprintf(stderr, "ethernet frames inside ISO15765-2 (unreliable) datagrams on CAN.\n\n");
|
||||
fprintf(stderr, "Options: -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, " -n <name> (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
|
||||
fprintf(stderr, " -D (daemonize to background when tun device created)\n");
|
||||
fprintf(stderr, " -h (half duplex mode.)\n");
|
||||
fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
|
||||
fprintf(stderr, " -n <name> (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
|
||||
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
|
||||
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
|
||||
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
|
||||
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
|
||||
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
|
||||
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
|
||||
fprintf(stderr, " -D (daemonize to background when tun device created)\n");
|
||||
fprintf(stderr, " -h (half duplex mode.)\n");
|
||||
fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "Use e.g. 'ifconfig ctun0 123.123.123.1 pointopoint 123.123.123.2 up'\n");
|
||||
fprintf(stderr, "to create a point-to-point IP connection on CAN.\n");
|
||||
|
||||
+56
-54
@@ -10,29 +10,29 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <err.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/j1939.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
static const char help_msg[] =
|
||||
"jacd: An SAE J1939 address claiming daemon" "\n"
|
||||
"Usage: jacd [options] NAME [INTF]" "\n"
|
||||
"\n"
|
||||
"j1939acd: An SAE J1939 address claiming daemon" "\n"
|
||||
"Usage: j1939acd [options] NAME [INTF]" "\n"
|
||||
"Options:\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -r, --range=RANGE Ranges of source addresses" "\n"
|
||||
" e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
|
||||
@@ -42,8 +42,9 @@ static const char help_msg[] =
|
||||
"\n"
|
||||
"NAME is the 64bit nodename" "\n"
|
||||
"\n"
|
||||
"Example:" "\n"
|
||||
"jacd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
|
||||
"Examples:" "\n"
|
||||
"j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
|
||||
"j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0" "\n"
|
||||
;
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
@@ -182,7 +183,7 @@ static const struct j1939_filter filt[] = {
|
||||
.pgn = J1939_PGN_REQUEST,
|
||||
.pgn_mask = J1939_PGN_PDU1_MAX,
|
||||
}, {
|
||||
.pgn = 0x0fed8,
|
||||
.pgn = J1939_PGN_ADDRESS_COMMANDED,
|
||||
.pgn_mask = J1939_PGN_MAX,
|
||||
},
|
||||
};
|
||||
@@ -198,7 +199,7 @@ static int open_socket(const char *device, uint64_t name)
|
||||
.addr = J1939_IDLE_ADDR,
|
||||
.pgn = J1939_NO_PGN,
|
||||
},
|
||||
.can_ifindex = if_nametoindex(s.intf),
|
||||
.can_ifindex = if_nametoindex(device),
|
||||
};
|
||||
|
||||
if (s.verbose)
|
||||
@@ -251,7 +252,7 @@ static int repeat_address(int sock, uint64_t name)
|
||||
ret = sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr,
|
||||
sizeof(saddr));
|
||||
if (must_warn(ret))
|
||||
err(1, "send address claim for 0x%02x", s.last_sa);
|
||||
fprintf(stderr, "send address claim for 0x%02x\n", s.last_sa);
|
||||
return ret;
|
||||
}
|
||||
static int claim_address(int sock, uint64_t name, int sa)
|
||||
@@ -290,7 +291,7 @@ static int request_addresses(int sock)
|
||||
fprintf(stderr, "- sendto(, { 0, 0xee, 0, }, %zi, 0, %s, %zi);\n", sizeof(dat), libj1939_addr2str(&saddr), sizeof(saddr));
|
||||
ret = sendto(sock, dat, sizeof(dat), 0, (void *)&saddr, sizeof(saddr));
|
||||
if (must_warn(ret))
|
||||
err(1, "send request for address claims");
|
||||
fprintf(stdout, "send request for address claims");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -364,7 +365,7 @@ static void install_signal(int sig)
|
||||
static void schedule_itimer(int msec)
|
||||
{
|
||||
int ret;
|
||||
struct itimerval val = {};
|
||||
struct itimerval val = { 0 };
|
||||
|
||||
val.it_value.tv_sec = msec / 1000;
|
||||
val.it_value.tv_usec = (msec % 1000) * 1000;
|
||||
@@ -382,10 +383,9 @@ static inline int addr_status_mine(int sa)
|
||||
{
|
||||
if (sa == s.current_sa)
|
||||
return '*';
|
||||
else if (addr[sa].flags & F_USE)
|
||||
if (addr[sa].flags & F_USE)
|
||||
return '+';
|
||||
else
|
||||
return '-';
|
||||
return '-';
|
||||
}
|
||||
|
||||
static void dump_status(void)
|
||||
@@ -471,32 +471,34 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'c':
|
||||
s.cachefile = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
s.ranges = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
s.current_sa = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'p':
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'c':
|
||||
s.cachefile = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
s.ranges = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
s.current_sa = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'p':
|
||||
#ifdef _GNU_SOURCE
|
||||
if (asprintf(&program_invocation_name, "%s.%s", program_invocation_short_name, optarg) < 0)
|
||||
err(1, "asprintf(program invocation name)");
|
||||
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");
|
||||
err(0, "compile with -D_GNU_SOURCE to use -p");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind])
|
||||
s.name = strtoull(argv[optind++], 0, 16);
|
||||
if (argv[optind])
|
||||
@@ -512,12 +514,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
if ((s.current_sa < J1939_IDLE_ADDR) && !(addr[s.current_sa].flags & F_USE)) {
|
||||
if (s.verbose)
|
||||
err(0, "forget saved address 0x%02x", s.current_sa);
|
||||
fprintf(stderr, "- forget saved address 0x%02x\n", s.current_sa);
|
||||
s.current_sa = J1939_IDLE_ADDR;
|
||||
}
|
||||
|
||||
if (s.verbose)
|
||||
err(0, "ready for %s:%016llx", s.intf, (long long)s.name);
|
||||
fprintf(stderr, "- ready for %s:%016llx\n", s.intf, (long long)s.name);
|
||||
if (!s.intf || !s.name)
|
||||
err(1, "bad arguments");
|
||||
ret = sock = open_socket(s.intf, s.name);
|
||||
@@ -581,7 +583,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
if (s.state == STATE_REQ_SENT) {
|
||||
if (s.verbose)
|
||||
err(0, "request sent, pending for 1250 ms");
|
||||
fprintf(stderr, "- request sent, pending for 1250 ms\n");
|
||||
schedule_itimer(1250);
|
||||
s.state = STATE_REQ_PENDING;
|
||||
} else if (s.state == STATE_OPERATIONAL) {
|
||||
@@ -611,14 +613,14 @@ int main(int argc, char *argv[])
|
||||
/* ourselves, disable itimer */
|
||||
s.current_sa = sa;
|
||||
if (s.verbose)
|
||||
err(0, "claimed 0x%02x", sa);
|
||||
fprintf(stderr, "- claimed 0x%02x\n", sa);
|
||||
} else if (sa == s.current_sa) {
|
||||
if (s.verbose)
|
||||
err(0, "address collision for 0x%02x", sa);
|
||||
fprintf(stderr, "- address collision for 0x%02x\n", sa);
|
||||
if (s.name > saddr.can_addr.j1939.name) {
|
||||
sa = choose_new_sa(s.name, sa);
|
||||
if (sa == J1939_IDLE_ADDR) {
|
||||
err(0, "no address left");
|
||||
fprintf(stdout, "no address left");
|
||||
/* put J1939_IDLE_ADDR in cache file */
|
||||
s.current_sa = sa;
|
||||
goto done;
|
||||
@@ -629,7 +631,7 @@ int main(int argc, char *argv[])
|
||||
schedule_itimer(50);
|
||||
}
|
||||
break;
|
||||
case 0x0fed8:
|
||||
case J1939_PGN_ADDRESS_COMMANDED:
|
||||
if (!host_is_little_endian())
|
||||
bswap(dat, 8);
|
||||
memcpy(&cmd_name, dat, 8);
|
||||
@@ -643,7 +645,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
done:
|
||||
if (s.verbose)
|
||||
err(0, "shutdown");
|
||||
fprintf(stderr, "- shutdown\n");
|
||||
claim_address(sock, s.name, J1939_IDLE_ADDR);
|
||||
save_cache();
|
||||
return 0;
|
||||
+121
-103
@@ -8,19 +8,21 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <net/if.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
#define J1939_MAX_ETP_PACKET_SIZE (7 * 0x00ffffff)
|
||||
#define JCAT_BUF_SIZE (1000 * 1024)
|
||||
|
||||
@@ -36,13 +38,13 @@
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
|
||||
struct jcat_stats {
|
||||
struct j1939cat_stats {
|
||||
int err;
|
||||
uint32_t tskey;
|
||||
uint32_t send;
|
||||
};
|
||||
|
||||
struct jcat_priv {
|
||||
struct j1939cat_priv {
|
||||
int sock;
|
||||
int infile;
|
||||
int outfile;
|
||||
@@ -55,6 +57,7 @@ struct jcat_priv {
|
||||
bool todo_recv;
|
||||
bool todo_filesize;
|
||||
bool todo_connect;
|
||||
int todo_broadcast;
|
||||
|
||||
unsigned long polltimeout;
|
||||
|
||||
@@ -63,12 +66,12 @@ struct jcat_priv {
|
||||
|
||||
struct sock_extended_err *serr;
|
||||
struct scm_timestamping *tss;
|
||||
struct jcat_stats stats;
|
||||
struct j1939cat_stats stats;
|
||||
};
|
||||
|
||||
static const char help_msg[] =
|
||||
"jcat: netcat tool for j1939\n"
|
||||
"Usage: jcat FROM TO\n"
|
||||
"j1939cat: netcat-like tool for j1939\n"
|
||||
"Usage: j1939cat [options] FROM TO\n"
|
||||
" FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n"
|
||||
"Options:\n"
|
||||
" -i <infile> (default stdin)\n"
|
||||
@@ -77,17 +80,18 @@ static const char help_msg[] =
|
||||
" -P <timeout> poll timeout in milliseconds before sending data.\n"
|
||||
" With this option send() will be used with MSG_DONTWAIT flag.\n"
|
||||
" -R <count> Set send repeat count. Default: 1\n"
|
||||
" -B Allow to send and receive broadcast packets.\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
"jcat -i some_file_to_send can0:0x80 :0x90,0x12300\n"
|
||||
"jcat can0:0x90 -r > /tmp/some_file_to_receive\n"
|
||||
"j1939cat -i some_file_to_send can0:0x80 :0x90,0x12300\n"
|
||||
"j1939cat can0:0x90 -r > /tmp/some_file_to_receive\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
static const char optstring[] = "?i:vs:rp:P:R:";
|
||||
static const char optstring[] = "?hi:vs:rp:P:R:B";
|
||||
|
||||
|
||||
static void jcat_init_sockaddr_can(struct sockaddr_can *sac)
|
||||
static void j1939cat_init_sockaddr_can(struct sockaddr_can *sac)
|
||||
{
|
||||
sac->can_family = AF_CAN;
|
||||
sac->can_addr.j1939.addr = J1939_NO_ADDR;
|
||||
@@ -95,7 +99,7 @@ static void jcat_init_sockaddr_can(struct sockaddr_can *sac)
|
||||
sac->can_addr.j1939.pgn = J1939_NO_PGN;
|
||||
}
|
||||
|
||||
static ssize_t jcat_send_one(struct jcat_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)
|
||||
{
|
||||
ssize_t num_sent;
|
||||
@@ -121,7 +125,7 @@ static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (num_sent > buf_size) /* Should never happen */ {
|
||||
if (num_sent > (ssize_t)buf_size) /* Should never happen */ {
|
||||
warn("%s: send more then read", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -129,10 +133,10 @@ static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd,
|
||||
return num_sent;
|
||||
}
|
||||
|
||||
static void jcat_print_timestamp(struct jcat_priv *priv, const char *name,
|
||||
static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *name,
|
||||
struct timespec *cur)
|
||||
{
|
||||
struct jcat_stats *stats = &priv->stats;
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
|
||||
if (!(cur->tv_sec | cur->tv_nsec))
|
||||
return;
|
||||
@@ -144,7 +148,7 @@ static void jcat_print_timestamp(struct jcat_priv *priv, const char *name,
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static const char *jcat_tstype_to_str(int tstype)
|
||||
static const char *j1939cat_tstype_to_str(int tstype)
|
||||
{
|
||||
switch (tstype) {
|
||||
case SCM_TSTAMP_SCHED:
|
||||
@@ -159,17 +163,17 @@ static const char *jcat_tstype_to_str(int tstype)
|
||||
}
|
||||
|
||||
/* Check the stats of SCM_TIMESTAMPING_OPT_STATS */
|
||||
static void jcat_scm_opt_stats(struct jcat_priv *priv, void *buf, int len)
|
||||
static void j1939cat_scm_opt_stats(struct j1939cat_priv *priv, void *buf, int len)
|
||||
{
|
||||
struct jcat_stats *stats = &priv->stats;
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
int offset = 0;
|
||||
|
||||
while (offset < len) {
|
||||
struct nlattr *nla = (struct nlattr *) (buf + offset);
|
||||
struct nlattr *nla = (struct nlattr *) ((char *)buf + offset);
|
||||
|
||||
switch (nla->nla_type) {
|
||||
case J1939_NLA_BYTES_ACKED:
|
||||
stats->send = *(uint32_t *)((void *)nla + NLA_HDRLEN);
|
||||
stats->send = *(uint32_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
default:
|
||||
warnx("not supported J1939_NLA field\n");
|
||||
@@ -179,9 +183,9 @@ static void jcat_scm_opt_stats(struct jcat_priv *priv, void *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
static int jcat_extract_serr(struct jcat_priv *priv)
|
||||
static int j1939cat_extract_serr(struct j1939cat_priv *priv)
|
||||
{
|
||||
struct jcat_stats *stats = &priv->stats;
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
struct sock_extended_err *serr = priv->serr;
|
||||
struct scm_timestamping *tss = priv->tss;
|
||||
|
||||
@@ -205,13 +209,12 @@ static int jcat_extract_serr(struct jcat_priv *priv)
|
||||
serr->ee_errno);
|
||||
stats->tskey = serr->ee_data;
|
||||
|
||||
jcat_print_timestamp(priv, jcat_tstype_to_str(serr->ee_info),
|
||||
j1939cat_print_timestamp(priv, j1939cat_tstype_to_str(serr->ee_info),
|
||||
&tss->ts[0]);
|
||||
|
||||
if (serr->ee_info == SCM_TSTAMP_SCHED)
|
||||
return -EINTR;
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
case SO_EE_ORIGIN_LOCAL:
|
||||
/*
|
||||
* The serr->ee_origin == SO_EE_ORIGIN_LOCAL is
|
||||
@@ -232,7 +235,7 @@ static int jcat_extract_serr(struct jcat_priv *priv)
|
||||
warnx("serr: unknown ee_info: %i",
|
||||
serr->ee_info);
|
||||
|
||||
jcat_print_timestamp(priv, " ABT", &tss->ts[0]);
|
||||
j1939cat_print_timestamp(priv, " ABT", &tss->ts[0]);
|
||||
warnx("serr: tx error: %i, %s", serr->ee_errno, strerror(serr->ee_errno));
|
||||
|
||||
return serr->ee_errno;
|
||||
@@ -243,7 +246,7 @@ static int jcat_extract_serr(struct jcat_priv *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
|
||||
static int j1939cat_parse_cm(struct j1939cat_priv *priv, struct cmsghdr *cm)
|
||||
{
|
||||
const size_t hdr_len = CMSG_ALIGN(sizeof(struct cmsghdr));
|
||||
|
||||
@@ -253,7 +256,7 @@ static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
|
||||
void *jstats = (void *)CMSG_DATA(cm);
|
||||
|
||||
/* Activated with SOF_TIMESTAMPING_OPT_STATS */
|
||||
jcat_scm_opt_stats(priv, jstats, cm->cmsg_len - hdr_len);
|
||||
j1939cat_scm_opt_stats(priv, jstats, cm->cmsg_len - hdr_len);
|
||||
} else if (cm->cmsg_level == SOL_CAN_J1939 &&
|
||||
cm->cmsg_type == SCM_J1939_ERRQUEUE) {
|
||||
priv->serr = (void *)CMSG_DATA(cm);
|
||||
@@ -264,7 +267,7 @@ static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jcat_recv_err(struct jcat_priv *priv)
|
||||
static int j1939cat_recv_err(struct j1939cat_priv *priv)
|
||||
{
|
||||
char control[100];
|
||||
struct cmsghdr *cm;
|
||||
@@ -285,18 +288,18 @@ static int jcat_recv_err(struct jcat_priv *priv)
|
||||
|
||||
for (cm = CMSG_FIRSTHDR(&msg); cm && cm->cmsg_len;
|
||||
cm = CMSG_NXTHDR(&msg, cm)) {
|
||||
jcat_parse_cm(priv, cm);
|
||||
j1939cat_parse_cm(priv, cm);
|
||||
if (priv->serr && priv->tss)
|
||||
return jcat_extract_serr(priv);
|
||||
return j1939cat_extract_serr(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jcat_send_loop(struct jcat_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)
|
||||
{
|
||||
struct jcat_stats *stats = &priv->stats;
|
||||
struct j1939cat_stats *stats = &priv->stats;
|
||||
ssize_t count;
|
||||
char *tmp_buf = buf;
|
||||
unsigned int events = POLLOUT | POLLERR;
|
||||
@@ -317,34 +320,32 @@ static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf,
|
||||
ret = poll(&fds, 1, priv->polltimeout);
|
||||
if (ret == -EINTR)
|
||||
continue;
|
||||
else if (ret < 0)
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
else if (!ret)
|
||||
if (!ret)
|
||||
return -ETIME;
|
||||
|
||||
if (!(fds.revents & events)) {
|
||||
warn("%s: something else is wrong", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (fds.revents & POLLERR) {
|
||||
ret = jcat_recv_err(priv);
|
||||
ret = j1939cat_recv_err(priv);
|
||||
if (ret == -EINTR)
|
||||
continue;
|
||||
else if (ret)
|
||||
if (ret)
|
||||
return ret;
|
||||
else if ((priv->repeat - 1) == stats->tskey)
|
||||
if ((priv->repeat - 1) == stats->tskey)
|
||||
tx_done = true;
|
||||
|
||||
}
|
||||
|
||||
if (fds.revents & POLLOUT) {
|
||||
num_sent = jcat_send_one(priv, out_fd, tmp_buf, count);
|
||||
num_sent = j1939cat_send_one(priv, out_fd, tmp_buf, count);
|
||||
if (num_sent < 0)
|
||||
return num_sent;
|
||||
}
|
||||
} else {
|
||||
num_sent = jcat_send_one(priv, out_fd, tmp_buf, count);
|
||||
num_sent = j1939cat_send_one(priv, out_fd, tmp_buf, count);
|
||||
if (num_sent < 0)
|
||||
return num_sent;
|
||||
}
|
||||
@@ -366,13 +367,14 @@ static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jcat_sendfile(struct jcat_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)
|
||||
{
|
||||
int ret = EXIT_SUCCESS;
|
||||
off_t orig = 0;
|
||||
char *buf;
|
||||
size_t to_read, num_read, buf_size;
|
||||
ssize_t num_read;
|
||||
size_t to_read, buf_size;
|
||||
|
||||
buf_size = min(priv->max_transfer, count);
|
||||
buf = malloc(buf_size);
|
||||
@@ -408,7 +410,7 @@ static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd,
|
||||
if (num_read == 0)
|
||||
break; /* EOF */
|
||||
|
||||
ret = jcat_send_loop(priv, out_fd, buf, num_read);
|
||||
ret = j1939cat_send_loop(priv, out_fd, buf, num_read);
|
||||
if (ret)
|
||||
goto do_free;
|
||||
|
||||
@@ -437,7 +439,7 @@ do_nofree:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t jcat_get_file_size(int fd)
|
||||
static size_t j1939cat_get_file_size(int fd)
|
||||
{
|
||||
off_t offset;
|
||||
|
||||
@@ -451,20 +453,21 @@ static size_t jcat_get_file_size(int fd)
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int jcat_send(struct jcat_priv *priv)
|
||||
static int j1939cat_send(struct j1939cat_priv *priv)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
int ret, i;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (priv->todo_filesize)
|
||||
size = jcat_get_file_size(priv->infile);
|
||||
size = j1939cat_get_file_size(priv->infile);
|
||||
|
||||
if (!size)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
for (i = 0; i < priv->repeat; i++) {
|
||||
priv->round++;
|
||||
ret = jcat_sendfile(priv, priv->sock, priv->infile, NULL, size);
|
||||
ret = j1939cat_sendfile(priv, priv->sock, priv->infile, NULL, size);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
@@ -475,7 +478,7 @@ static int jcat_send(struct jcat_priv *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size)
|
||||
static int j1939cat_recv_one(struct j1939cat_priv *priv, uint8_t *buf, size_t buf_size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -494,7 +497,7 @@ static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int jcat_recv(struct jcat_priv *priv)
|
||||
static int j1939cat_recv(struct j1939cat_priv *priv)
|
||||
{
|
||||
int ret = EXIT_SUCCESS;
|
||||
size_t buf_size;
|
||||
@@ -508,7 +511,7 @@ static int jcat_recv(struct jcat_priv *priv)
|
||||
}
|
||||
|
||||
while (priv->todo_recv) {
|
||||
ret = jcat_recv_one(priv, buf, buf_size);
|
||||
ret = j1939cat_recv_one(priv, buf, buf_size);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@@ -517,7 +520,7 @@ static int jcat_recv(struct jcat_priv *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int jcat_sock_prepare(struct jcat_priv *priv)
|
||||
static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
|
||||
{
|
||||
unsigned int sock_opt;
|
||||
int value;
|
||||
@@ -558,6 +561,16 @@ static int jcat_sock_prepare(struct jcat_priv *priv)
|
||||
(char *) &sock_opt, sizeof(sock_opt)))
|
||||
err(1, "setsockopt timestamping");
|
||||
|
||||
if (priv->todo_broadcast) {
|
||||
ret = setsockopt(priv->sock, SOL_SOCKET, SO_BROADCAST,
|
||||
&priv->todo_broadcast,
|
||||
sizeof(priv->todo_broadcast));
|
||||
if (ret < 0) {
|
||||
warn("setsockopt: filed to set broadcast");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bind(priv->sock, (void *)&priv->sockname, sizeof(priv->sockname));
|
||||
if (ret < 0) {
|
||||
warn("bind()");
|
||||
@@ -581,55 +594,62 @@ static int jcat_sock_prepare(struct jcat_priv *priv)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[])
|
||||
static int j1939cat_parse_args(struct j1939cat_priv *priv, int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
|
||||
/* argument parsing */
|
||||
while ((opt = getopt(argc, argv, optstring)) != -1)
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
priv->infile = open(optarg, O_RDONLY);
|
||||
if (priv->infile == -1)
|
||||
err(EXIT_FAILURE, "can't open input file");
|
||||
priv->todo_filesize = 1;
|
||||
break;
|
||||
case 's':
|
||||
priv->max_transfer = strtoul(optarg, NULL, 0);
|
||||
if (priv->max_transfer > J1939_MAX_ETP_PACKET_SIZE)
|
||||
err(EXIT_FAILURE, "used value (%zu) is bigger then allowed maximal size: %u.\n",
|
||||
priv->max_transfer, J1939_MAX_ETP_PACKET_SIZE);
|
||||
break;
|
||||
case 'r':
|
||||
priv->todo_recv = 1;
|
||||
break;
|
||||
case 'p':
|
||||
priv->todo_prio = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'P':
|
||||
priv->polltimeout = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'c':
|
||||
priv->todo_connect = 1;
|
||||
break;
|
||||
case 'R':
|
||||
priv->repeat = strtoul(optarg, NULL, 0);
|
||||
if (priv->repeat < 1)
|
||||
err(EXIT_FAILURE, "send/repeat count can't be less then 1\n");
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
priv->infile = open(optarg, O_RDONLY);
|
||||
if (priv->infile == -1)
|
||||
err(EXIT_FAILURE, "can't open input file");
|
||||
priv->todo_filesize = 1;
|
||||
break;
|
||||
case 's':
|
||||
priv->max_transfer = strtoul(optarg, NULL, 0);
|
||||
if (priv->max_transfer > J1939_MAX_ETP_PACKET_SIZE)
|
||||
err(EXIT_FAILURE,
|
||||
"used value (%zu) is bigger then allowed maximal size: %u.\n",
|
||||
priv->max_transfer,
|
||||
J1939_MAX_ETP_PACKET_SIZE);
|
||||
break;
|
||||
case 'r':
|
||||
priv->todo_recv = 1;
|
||||
break;
|
||||
case 'p':
|
||||
priv->todo_prio = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'P':
|
||||
priv->polltimeout = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'c':
|
||||
priv->todo_connect = 1;
|
||||
break;
|
||||
case 'R':
|
||||
priv->repeat = strtoul(optarg, NULL, 0);
|
||||
if (priv->repeat < 1)
|
||||
err(EXIT_FAILURE,
|
||||
"send/repeat count can't be less then 1\n");
|
||||
break;
|
||||
case 'B':
|
||||
priv->todo_broadcast = 1;
|
||||
break;
|
||||
case 'h': /*fallthrough*/
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind]))
|
||||
if (strcmp("-", argv[optind]) != 0)
|
||||
libj1939_parse_canaddr(argv[optind], &priv->sockname);
|
||||
optind++;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind])) {
|
||||
if (strcmp("-", argv[optind]) != 0) {
|
||||
libj1939_parse_canaddr(argv[optind], &priv->peername);
|
||||
priv->valid_peername = 1;
|
||||
}
|
||||
@@ -641,15 +661,13 @@ static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[])
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct jcat_priv *priv;
|
||||
int ret;
|
||||
struct j1939cat_priv *priv;
|
||||
int ret = 0;
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
priv = calloc(1, sizeof(*priv));
|
||||
if (!priv)
|
||||
err(EXIT_FAILURE, "can't allocate priv");
|
||||
|
||||
bzero(priv, sizeof(*priv));
|
||||
|
||||
priv->todo_prio = -1;
|
||||
priv->infile = STDIN_FILENO;
|
||||
priv->outfile = STDOUT_FILENO;
|
||||
@@ -657,25 +675,25 @@ int main(int argc, char *argv[])
|
||||
priv->polltimeout = 100000;
|
||||
priv->repeat = 1;
|
||||
|
||||
jcat_init_sockaddr_can(&priv->sockname);
|
||||
jcat_init_sockaddr_can(&priv->peername);
|
||||
j1939cat_init_sockaddr_can(&priv->sockname);
|
||||
j1939cat_init_sockaddr_can(&priv->peername);
|
||||
|
||||
ret = jcat_parse_args(priv, argc, argv);
|
||||
ret = j1939cat_parse_args(priv, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = jcat_sock_prepare(priv);
|
||||
ret = j1939cat_sock_prepare(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->todo_recv)
|
||||
ret = jcat_recv(priv);
|
||||
ret = j1939cat_recv(priv);
|
||||
else
|
||||
ret = jcat_send(priv);
|
||||
ret = j1939cat_send(priv);
|
||||
|
||||
close(priv->infile);
|
||||
close(priv->outfile);
|
||||
close(priv->sock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+38
-36
@@ -10,19 +10,19 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <err.h>
|
||||
#include <sys/socket.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
* getopt
|
||||
*/
|
||||
static const char help_msg[] =
|
||||
"jspy: An SAE J1939 spy utility" "\n"
|
||||
"Usage: jspy [OPTION...] [[IFACE:][NAME|SA][,PGN]]" "\n"
|
||||
"\n"
|
||||
"j1939spy: An SAE J1939 spy utility" "\n"
|
||||
"Usage: j1939spy [OPTION...] [[IFACE:][NAME|SA][,PGN]]" "\n"
|
||||
"Options:\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -P, --promisc Run in promiscuous mode" "\n"
|
||||
" (= receive traffic not for this ECU)" "\n"
|
||||
@@ -95,8 +95,8 @@ static uint8_t *buf;
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret, sock, j, opt;
|
||||
unsigned int len;
|
||||
int ret, sock, opt;
|
||||
unsigned int j, len;
|
||||
struct timeval tref, tdut, ttmp;
|
||||
struct sockaddr_can src;
|
||||
struct j1939_filter filt;
|
||||
@@ -107,30 +107,32 @@ int main(int argc, char **argv)
|
||||
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'b':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'P':
|
||||
++s.promisc;
|
||||
break;
|
||||
case 't':
|
||||
if (optarg) {
|
||||
if (!strchr("adzA", optarg[0]))
|
||||
err(1, "unknown time option '%c'", optarg[0]);
|
||||
s.time = optarg[0];
|
||||
} else {
|
||||
s.time = 'z';
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 'b':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'P':
|
||||
++s.promisc;
|
||||
break;
|
||||
case 't':
|
||||
if (optarg) {
|
||||
if (!strchr("adzA", optarg[0]))
|
||||
err(1, "unknown time option '%c'",
|
||||
optarg[0]);
|
||||
s.time = optarg[0];
|
||||
} else {
|
||||
s.time = 'z';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
optarg = argv[optind];
|
||||
ret = libj1939_str2addr(optarg, 0, &s.addr);
|
||||
@@ -287,7 +289,7 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("[%i%s]", len, (msg.msg_flags & MSG_TRUNC) ? "..." : "");
|
||||
for (j = 0; j < len; ) {
|
||||
int end = j + 4;
|
||||
unsigned int end = j + 4;
|
||||
if (end > len)
|
||||
end = len;
|
||||
printf(" ");
|
||||
+31
-31
@@ -10,20 +10,20 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
* getopt
|
||||
*/
|
||||
static const char help_msg[] =
|
||||
"jsr: An SAE J1939 send/recv utility" "\n"
|
||||
"Usage: jsr [OPTION...] SOURCE [DEST]" "\n"
|
||||
"\n"
|
||||
"j1939sr: An SAE J1939 send/recv utility" "\n"
|
||||
"Usage: j1939sr [OPTION...] SOURCE [DEST]" "\n"
|
||||
"Options:\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -p, --priority=VAL J1939 priority (0..7, default 6)" "\n"
|
||||
" -S, --serialize Strictly serialize outgoing packets" "\n"
|
||||
@@ -99,27 +99,27 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 's':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
if (!s.pkt_len)
|
||||
err(1, "packet size of %s", optarg);
|
||||
break;
|
||||
case 'p':
|
||||
s.priority = strtoul(optarg, 0, 0);
|
||||
s.defined |= DEF_PRIO;
|
||||
break;
|
||||
case 'S':
|
||||
s.sendflags |= MSG_SYN;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 's':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
if (!s.pkt_len)
|
||||
err(1, "packet size of %s", optarg);
|
||||
break;
|
||||
case 'p':
|
||||
s.priority = strtoul(optarg, 0, 0);
|
||||
s.defined |= DEF_PRIO;
|
||||
break;
|
||||
case 'S':
|
||||
s.sendflags |= MSG_SYN;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
optarg = argv[optind++];
|
||||
@@ -42,17 +42,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define CANID_DELIM '#'
|
||||
#define CC_DLC_DELIM '_'
|
||||
#define DATA_SEPERATOR '.'
|
||||
|
||||
const char hex_asc_upper[] = "0123456789ABCDEF";
|
||||
@@ -83,10 +84,10 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
|
||||
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
unsigned char can_dlc2len(unsigned char can_dlc)
|
||||
/* get data length from raw data length code (DLC) */
|
||||
unsigned char can_fd_dlc2len(unsigned char dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
return dlc2len[dlc & 0x0F];
|
||||
}
|
||||
|
||||
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
@@ -101,7 +102,7 @@ static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
unsigned char can_len2dlc(unsigned char len)
|
||||
unsigned char can_fd_len2dlc(unsigned char len)
|
||||
{
|
||||
if (len > 64)
|
||||
return 0xF;
|
||||
@@ -195,9 +196,19 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
|
||||
/* check for optional DLC value for CAN 2.0B frames */
|
||||
if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
|
||||
if(cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
|
||||
cf->len = tmp;
|
||||
|
||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||
tmp = asc2nibble(cs[idx]);
|
||||
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
ccf->len8_dlc = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -232,6 +243,17 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
||||
}
|
||||
cf->len = dlen;
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||
unsigned char dlc = asc2nibble(cs[idx]);
|
||||
|
||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
ccf->len8_dlc = dlc;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -270,9 +292,20 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
||||
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
|
||||
buf[offset++] = 'R';
|
||||
/* print a given CAN 2.0B DLC if it's not zero */
|
||||
if (cf->len && cf->len <= CAN_MAX_DLC)
|
||||
if (cf->len && cf->len <= CAN_MAX_DLEN) {
|
||||
buf[offset++] = hex_asc_upper_lo(cf->len);
|
||||
|
||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||
if (cf->len == CAN_MAX_DLEN) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) {
|
||||
buf[offset++] = CC_DLC_DELIM;
|
||||
buf[offset++] = hex_asc_upper_lo(ccf->len8_dlc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf[offset] = 0;
|
||||
return;
|
||||
}
|
||||
@@ -292,6 +325,17 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
||||
buf[offset++] = '.';
|
||||
}
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
unsigned char dlc = ccf->len8_dlc;
|
||||
|
||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
buf[offset++] = CC_DLC_DELIM;
|
||||
buf[offset++] = hex_asc_upper_lo(dlc);
|
||||
}
|
||||
}
|
||||
|
||||
buf[offset] = 0;
|
||||
}
|
||||
|
||||
@@ -337,9 +381,23 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||
|
||||
/* The len value is sanitized by maxdlen (see above) */
|
||||
if (maxdlen == CAN_MAX_DLEN) {
|
||||
buf[offset + 1] = '[';
|
||||
buf[offset + 2] = len + '0';
|
||||
buf[offset + 3] = ']';
|
||||
if (view & CANLIB_VIEW_LEN8_DLC) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
unsigned char dlc = ccf->len8_dlc;
|
||||
|
||||
/* fall back to len if we don't have a valid DLC > 8 */
|
||||
if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) &&
|
||||
(dlc <= CAN_MAX_RAW_DLC)))
|
||||
dlc = len;
|
||||
|
||||
buf[offset + 1] = '{';
|
||||
buf[offset + 2] = hex_asc_upper[dlc];
|
||||
buf[offset + 3] = '}';
|
||||
} else {
|
||||
buf[offset + 1] = '[';
|
||||
buf[offset + 2] = len + '0';
|
||||
buf[offset + 3] = ']';
|
||||
}
|
||||
|
||||
/* standard CAN frames may have RTR enabled */
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
@@ -583,12 +641,12 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||
if (!sep)
|
||||
sep = defsep;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(error_classes); i++) {
|
||||
for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
|
||||
mask = 1 << i;
|
||||
if (class & mask) {
|
||||
if (classes)
|
||||
n += snprintf(buf + n, len - n, "%s", sep);
|
||||
n += snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||
n += snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||
if (mask == CAN_ERR_LOSTARB)
|
||||
n += snprintf_error_lostarb(buf + n, len - n,
|
||||
cf);
|
||||
|
||||
@@ -61,11 +61,11 @@
|
||||
|
||||
/* CAN DLC to real data length conversion helpers especially for CAN FD */
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
unsigned char can_dlc2len(unsigned char can_dlc);
|
||||
/* get data length from raw data length code (DLC) */
|
||||
unsigned char can_fd_dlc2len(unsigned char dlc);
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
unsigned char can_len2dlc(unsigned char len);
|
||||
unsigned char can_fd_len2dlc(unsigned char len);
|
||||
|
||||
unsigned char asc2nibble(char c);
|
||||
/*
|
||||
@@ -99,10 +99,11 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
||||
/*
|
||||
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
|
||||
*
|
||||
* CAN 2.0 frames
|
||||
* - string layout <can_id>#{R{len}|data}
|
||||
* CAN 2.0 frames (aka Classical CAN)
|
||||
* - string layout <can_id>#{R{len}|data}{_len8_dlc}
|
||||
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
|
||||
* - {len} can take values from 0 to 8 and can be omitted if zero
|
||||
* - {_len8_dlc} can take hex values from '_9' to '_F' when len is CAN_MAX_DLEN
|
||||
* - return value on successful parsing: CAN_MTU
|
||||
*
|
||||
* CAN FD frames
|
||||
@@ -124,10 +125,12 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
||||
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||
* 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||
* 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
|
||||
* 123#R8_9 -> standard CAN-Id = 0x123, len = 8, dlc = 9, RTR-frame
|
||||
* 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
|
||||
*
|
||||
* 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
|
||||
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
|
||||
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14
|
||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
|
||||
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
|
||||
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
|
||||
@@ -155,10 +158,11 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
||||
* The CAN data[] is separated by '.' when sep != 0.
|
||||
*
|
||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
||||
* maxdlen = 8 -> CAN2.0 frame
|
||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
||||
* maxdlen = 64 -> CAN FD frame
|
||||
*
|
||||
* 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0
|
||||
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14, data, sep = 0
|
||||
* 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
|
||||
* 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
|
||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
|
||||
@@ -178,6 +182,7 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
||||
#define CANLIB_VIEW_SWAP 0x4
|
||||
#define CANLIB_VIEW_ERROR 0x8
|
||||
#define CANLIB_VIEW_INDENT_SFF 0x10
|
||||
#define CANLIB_VIEW_LEN8_DLC 0x20
|
||||
|
||||
#define SWAP_DELIMITER '`'
|
||||
|
||||
@@ -187,14 +192,15 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||
* Creates a CAN frame hexadecimal output in user readable format.
|
||||
*
|
||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
||||
* maxdlen = 8 -> CAN2.0 frame
|
||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
||||
* maxdlen = 64 -> CAN FD frame
|
||||
*
|
||||
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, dlc = 3, data
|
||||
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data
|
||||
* 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR
|
||||
* 14B0DC51 [8] 4A 94 E8 2A EC 58 55 62 'J..*.XUb' -> (with ASCII output)
|
||||
* 321 {B} 11 22 33 44 55 66 77 88 -> Classical CAN with raw '{DLC}' value B
|
||||
* 20001111 [7] C6 23 7B 32 69 98 3C ERRORFRAME -> (CAN_ERR_FLAG set)
|
||||
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, dlc = 3
|
||||
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, len = 3
|
||||
*
|
||||
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == 0
|
||||
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set
|
||||
@@ -204,7 +210,7 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||
* // CAN FD frame with eol to STDOUT
|
||||
* fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
|
||||
*
|
||||
* // CAN 2.0 frame without eol to STDERR
|
||||
* // Classical CAN 2.0 frame without eol to STDERR
|
||||
* fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN);
|
||||
*
|
||||
*/
|
||||
|
||||
+9
-9
@@ -10,16 +10,16 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
@@ -53,7 +53,7 @@ static const char *libj1939_ifnam(int ifindex)
|
||||
fetch_names();
|
||||
|
||||
for (lp = saved; lp->if_index; ++lp) {
|
||||
if (lp->if_index == ifindex)
|
||||
if (lp->if_index == (unsigned int)ifindex)
|
||||
return lp->if_name;
|
||||
}
|
||||
if (cached) {
|
||||
@@ -64,8 +64,8 @@ static const char *libj1939_ifnam(int ifindex)
|
||||
*/
|
||||
libj1939_cleanup();
|
||||
return libj1939_ifnam(ifindex);
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* retrieve index */
|
||||
@@ -88,8 +88,8 @@ static int libj1939_ifindex(const char *str)
|
||||
if (cached) {
|
||||
libj1939_cleanup();
|
||||
return libj1939_ifindex(str);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr)
|
||||
|
||||
@@ -42,15 +42,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/can.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
@@ -60,24 +60,129 @@ extern int optind, opterr, optopt;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [can-interfaces]\n", prg);
|
||||
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
|
||||
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
|
||||
fprintf(stderr, "%s - convert compact CAN frame logfile to ASC logfile.\n", prg);
|
||||
fprintf(stderr, "Usage: %s <options> [can-interfaces]\n", prg);
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -I <infile> (default stdin)\n");
|
||||
fprintf(stderr, " -O <outfile> (default stdout)\n");
|
||||
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
|
||||
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
|
||||
fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n");
|
||||
fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n");
|
||||
}
|
||||
|
||||
void can_asc(struct canfd_frame *cf, int devno, int nortrdlc, char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
|
||||
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
|
||||
|
||||
if (cf->can_id & CAN_ERR_FLAG)
|
||||
fprintf(outfile, "ErrorFrame");
|
||||
else {
|
||||
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
|
||||
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
|
||||
/* check for extra info */
|
||||
if (strlen(extra_info) > 0) {
|
||||
/* only the first char is defined so far */
|
||||
if (extra_info[0] == 'T')
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
fprintf(outfile, "%-15s %s ", id, dir);
|
||||
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
if (nortrdlc)
|
||||
fprintf(outfile, "r"); /* RTR frame */
|
||||
else
|
||||
fprintf(outfile, "r %d", cf->len); /* RTR frame */
|
||||
} else {
|
||||
fprintf(outfile, "d %d", cf->len); /* data frame */
|
||||
|
||||
for (i = 0; i < cf->len; i++) {
|
||||
fprintf(outfile, " %02X", cf->data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
unsigned int flags = 0;
|
||||
unsigned int dlen = cf->len;
|
||||
unsigned int dlc = can_fd_len2dlc(dlen);
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
#define ASC_F_FDF 0x00001000
|
||||
#define ASC_F_BRS 0x00002000
|
||||
#define ASC_F_ESI 0x00004000
|
||||
|
||||
/* check for extra info */
|
||||
if (strlen(extra_info) > 0) {
|
||||
/* only the first char is defined so far */
|
||||
if (extra_info[0] == 'T')
|
||||
dir = "Tx";
|
||||
}
|
||||
|
||||
fprintf(outfile, "CANFD %3d %s ", devno, dir); /* 3 column channel number right aligned */
|
||||
|
||||
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
|
||||
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
fprintf(outfile, "%11s ", id);
|
||||
fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0');
|
||||
fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0');
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((mtu == CAN_MTU) && (dlen == CAN_MAX_DLEN)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC))
|
||||
dlc = ccf->len8_dlc;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%x ", dlc);
|
||||
|
||||
if (mtu == CAN_MTU) {
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
/* no data length but dlc for RTR frames */
|
||||
dlen = 0;
|
||||
flags = ASC_F_RTR;
|
||||
}
|
||||
} else {
|
||||
flags = ASC_F_FDF;
|
||||
if (cf->flags & CANFD_BRS)
|
||||
flags |= ASC_F_BRS;
|
||||
if (cf->flags & CANFD_ESI)
|
||||
flags |= ASC_F_ESI;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%2d", dlen);
|
||||
|
||||
for (i = 0; i < (int)dlen; i++) {
|
||||
fprintf(outfile, " %02X", cf->data[i]);
|
||||
}
|
||||
|
||||
fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10];
|
||||
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], extra_info[BUFSZ];
|
||||
|
||||
struct canfd_frame cf;
|
||||
static struct timeval tv, start_tv;
|
||||
FILE *infile = stdin;
|
||||
FILE *outfile = stdout;
|
||||
static int maxdev, devno, i, crlf, d4, opt;
|
||||
static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:O:4n?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -99,6 +204,14 @@ int main(int argc, char **argv)
|
||||
crlf = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
fdfmt = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
nortrdlc = 1;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
d4 = 1;
|
||||
break;
|
||||
@@ -137,10 +250,17 @@ int main(int argc, char **argv)
|
||||
if (buf[0] != '(')
|
||||
continue;
|
||||
|
||||
if (sscanf(buf, "(%ld.%ld) %s %s", &tv.tv_sec, &tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s %s", &tv.tv_sec, &tv.tv_usec,
|
||||
device, ascframe, extra_info) != 5) {
|
||||
|
||||
/* do not evaluate the extra info */
|
||||
extra_info[0] = 0;
|
||||
|
||||
if (sscanf(buf, "(%lu.%lu) %s %s", &tv.tv_sec, &tv.tv_usec,
|
||||
device, ascframe) != 4) {
|
||||
fprintf(stderr, "incorrect line format in logfile\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!start_tv.tv_sec) { /* print banner */
|
||||
@@ -160,9 +280,14 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (devno) { /* only convert for selected CAN devices */
|
||||
if (parse_canframe(ascframe, &cf) != CAN_MTU) /* no CAN FD support so far */
|
||||
mtu = parse_canframe(ascframe, &cf);
|
||||
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU))
|
||||
return 1;
|
||||
|
||||
/* we don't support error message frames in CAN FD */
|
||||
if ((mtu == CANFD_MTU) && (cf.can_id & CAN_ERR_FLAG))
|
||||
continue;
|
||||
|
||||
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
|
||||
tv.tv_usec = tv.tv_usec - start_tv.tv_usec;
|
||||
if (tv.tv_usec < 0)
|
||||
@@ -171,29 +296,15 @@ int main(int argc, char **argv)
|
||||
tv.tv_sec = tv.tv_usec = 0;
|
||||
|
||||
if (d4)
|
||||
fprintf(outfile, "%4ld.%04ld ", tv.tv_sec, tv.tv_usec/100);
|
||||
fprintf(outfile, "%4lu.%04lu ", tv.tv_sec, tv.tv_usec/100);
|
||||
else
|
||||
fprintf(outfile, "%4ld.%06ld ", tv.tv_sec, tv.tv_usec);
|
||||
fprintf(outfile, "%4lu.%06lu ", tv.tv_sec, tv.tv_usec);
|
||||
|
||||
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
|
||||
if ((mtu == CAN_MTU) && (fdfmt == 0))
|
||||
can_asc(&cf, devno, nortrdlc, extra_info, outfile);
|
||||
else
|
||||
canfd_asc(&cf, devno, mtu, extra_info, outfile);
|
||||
|
||||
if (cf.can_id & CAN_ERR_FLAG)
|
||||
fprintf(outfile, "ErrorFrame");
|
||||
else {
|
||||
sprintf(id, "%X%c", cf.can_id & CAN_EFF_MASK,
|
||||
(cf.can_id & CAN_EFF_FLAG)?'x':' ');
|
||||
fprintf(outfile, "%-15s Rx ", id);
|
||||
|
||||
if (cf.can_id & CAN_RTR_FLAG)
|
||||
fprintf(outfile, "r"); /* RTR frame */
|
||||
else {
|
||||
fprintf(outfile, "d %d", cf.len); /* data frame */
|
||||
|
||||
for (i = 0; i < cf.len; i++) {
|
||||
fprintf(outfile, " %02X", cf.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (crlf)
|
||||
fprintf(outfile, "\r");
|
||||
fprintf(outfile, "\n");
|
||||
|
||||
+2
-2
@@ -44,15 +44,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/can.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define COMMENTSZ 200
|
||||
#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(void)
|
||||
{
|
||||
char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
|
||||
struct canfd_frame cf;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ACTION=="add", SUBSYSTEM=="devcoredump", RUN+="/usr/sbin/devcoredump"
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
timestamp=$(date +%+4Y%m%d-%H%M%S)
|
||||
filename=/var/log/devcoredump-${timestamp}.dump
|
||||
|
||||
cat /sys/${DEVPATH}/data > ${filename}
|
||||
echo 1 > /sys/${DEVPATH}/data
|
||||
|
||||
echo "devcoredump ${DEVPATH}" | logger
|
||||
@@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020, 2021 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
#define pr_err(fmt, args...) fprintf(stderr, fmt, ##args)
|
||||
#define pr_no(fmt, args...) while (0) { fprintf(stdout, fmt, ##args); }
|
||||
|
||||
#ifdef DEBUG
|
||||
#define pr_debug(fmt, args...) pr_err(fmt, ##args)
|
||||
#else
|
||||
#define pr_debug(fmt, args...) pr_no(fmt, ##args)
|
||||
#endif
|
||||
|
||||
|
||||
struct mcp251xfd_dump_iter {
|
||||
const void *start;
|
||||
const struct mcp251xfd_dump_object_header *hdr;
|
||||
const void *object_start;
|
||||
const void *object_end;
|
||||
};
|
||||
|
||||
static __attribute__((__unused__)) const char *
|
||||
get_object_type_str(enum mcp251xfd_dump_object_type object_type)
|
||||
{
|
||||
switch (object_type) {
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
|
||||
return "reg";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
|
||||
return "tef";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
|
||||
return "rx";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
|
||||
return "tx";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_END:
|
||||
return "end";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__((__unused__)) const char *
|
||||
get_ring_key_str(enum mcp251xfd_dump_object_ring_key key)
|
||||
{
|
||||
switch (key) {
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD:
|
||||
return "head";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL:
|
||||
return "tail";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE:
|
||||
return "base";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_NR:
|
||||
return "nr";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR:
|
||||
return "fifo-nr";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM:
|
||||
return "obj-num";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE:
|
||||
return "obj-size";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_dev_coredump_read_reg(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_iter *iter,
|
||||
struct mcp251xfd_mem *mem)
|
||||
{
|
||||
const struct mcp251xfd_dump_object_reg *object;
|
||||
|
||||
for (object = iter->object_start;
|
||||
(void *)(object + 1) <= iter->object_end;
|
||||
object++) {
|
||||
uint32_t reg, val;
|
||||
|
||||
reg = le32toh(object->reg);
|
||||
val = le32toh(object->val);
|
||||
|
||||
pr_debug("%s: object=0x%04zx reg=0x%04x - val=0x%08x\n",
|
||||
__func__,
|
||||
(void *)object - iter->start,
|
||||
reg, val);
|
||||
|
||||
if (reg > ARRAY_SIZE(mem->buf))
|
||||
return -EINVAL;
|
||||
|
||||
*(uint32_t *)(mem->buf + reg) = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_dev_coredump_read_ring(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_iter *iter,
|
||||
struct mcp251xfd_ring *ring)
|
||||
{
|
||||
const struct mcp251xfd_dump_object_reg *object;
|
||||
|
||||
for (object = iter->object_start;
|
||||
(void *)(object + 1) <= iter->object_end;
|
||||
object++) {
|
||||
enum mcp251xfd_dump_object_ring_key key;
|
||||
uint32_t val;
|
||||
|
||||
key = le32toh(object->reg);
|
||||
val = le32toh(object->val);
|
||||
|
||||
pr_debug("%s: reg=0x%04zx key=0x%02x: %8s - val=0x%08x\n",
|
||||
__func__,
|
||||
(void *)object - iter->start,
|
||||
key, get_ring_key_str(key), val);
|
||||
|
||||
switch (key) {
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD:
|
||||
ring->head = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL:
|
||||
ring->tail = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE:
|
||||
ring->base = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_NR:
|
||||
ring->nr = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR:
|
||||
ring->fifo_nr = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM:
|
||||
ring->obj_num = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE:
|
||||
ring->obj_size = val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const void *dump, size_t dump_len)
|
||||
{
|
||||
struct mcp251xfd_dump_iter iter[] = {
|
||||
{
|
||||
.start = dump,
|
||||
.hdr = dump,
|
||||
},
|
||||
};
|
||||
|
||||
while ((void *)(iter->hdr + 1) <= iter->start + dump_len &&
|
||||
le32toh(iter->hdr->magic) == MCP251XFD_DUMP_MAGIC) {
|
||||
const struct mcp251xfd_dump_object_header *hdr = iter->hdr;
|
||||
enum mcp251xfd_dump_object_type object_type;
|
||||
size_t object_offset, object_len;
|
||||
int err;
|
||||
|
||||
object_type = le32toh(hdr->type);
|
||||
object_offset = le32toh(hdr->offset);
|
||||
object_len = le32toh(hdr->len);
|
||||
|
||||
if (object_offset + object_len > dump_len)
|
||||
return -EFAULT;
|
||||
|
||||
iter->object_start = iter->start + object_offset;
|
||||
iter->object_end = iter->object_start + object_len;
|
||||
|
||||
pr_debug("%s: hdr=0x%04zx type=0x%08x: %8s - offset=0x%04zx len=0x%04zx end=0x%04zx\n",
|
||||
__func__,
|
||||
(void *)iter->hdr - iter->start,
|
||||
object_type, get_object_type_str(object_type),
|
||||
object_offset, object_len, object_offset + object_len);
|
||||
|
||||
switch (object_type) {
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
|
||||
err = do_dev_coredump_read_reg(priv, iter, mem);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
|
||||
err = do_dev_coredump_read_ring(priv, iter, priv->tef);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
|
||||
err = do_dev_coredump_read_ring(priv, iter, priv->rx);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
|
||||
err = do_dev_coredump_read_ring(priv, iter, priv->tx);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_END:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
iter->hdr++;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *dump_path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
size_t dump_len;
|
||||
void *dump;
|
||||
int fd, err;
|
||||
|
||||
fd = open(dump_path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
err = fstat(fd, &statbuf);
|
||||
if (err < 0) {
|
||||
err = -errno;
|
||||
goto out_close;
|
||||
}
|
||||
dump_len = statbuf.st_size;
|
||||
|
||||
dump = mmap(NULL, dump_len, PROT_READ, MAP_SHARED, fd, 0x0);
|
||||
if (dump == MAP_FAILED) {
|
||||
err = -errno;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = do_dev_coredump_read(priv, mem, dump, dump_len);
|
||||
|
||||
munmap(dump, dump_len);
|
||||
out_close:
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Microchip MCP251xFD Family CAN controller debug tool
|
||||
*
|
||||
* Copyright (c) 2019, 2020 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_DUMP_USERSPACE_H
|
||||
#define _MCP251XFD_DUMP_USERSPACE_H
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump.h"
|
||||
|
||||
#define MCP251XFD_TX_FIFO 1
|
||||
#define MCP251XFD_RX_FIFO(x) (MCP251XFD_TX_FIFO + 1 + (x))
|
||||
|
||||
struct mcp251xfd_mem {
|
||||
char buf[0x1000];
|
||||
};
|
||||
|
||||
struct mcp251xfd_ring {
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
|
||||
u16 base;
|
||||
u8 nr;
|
||||
u8 fifo_nr;
|
||||
u8 obj_num;
|
||||
u8 obj_size;
|
||||
};
|
||||
|
||||
struct mcp251xfd_priv {
|
||||
struct regmap *map;
|
||||
|
||||
struct mcp251xfd_ring tef[1];
|
||||
struct mcp251xfd_ring tx[1];
|
||||
struct mcp251xfd_ring rx[1];
|
||||
|
||||
u8 rx_ring_num;
|
||||
};
|
||||
|
||||
static inline u8 mcp251xfd_get_ring_head(const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return ring->head & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
static inline u8 mcp251xfd_get_ring_tail(const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return ring->tail & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
void mcp251xfd_dump(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path);
|
||||
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,863 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
struct mcp251xfd_dump_regs_fifo {
|
||||
u32 con;
|
||||
u32 sta;
|
||||
u32 ua;
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_regs_filter {
|
||||
u32 obj;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_regs {
|
||||
u32 con;
|
||||
u32 nbtcfg;
|
||||
u32 dbtcfg;
|
||||
u32 tdc;
|
||||
u32 tbc;
|
||||
u32 tscon;
|
||||
u32 vec;
|
||||
u32 intf;
|
||||
u32 rxif;
|
||||
u32 txif;
|
||||
u32 rxovif;
|
||||
u32 txatif;
|
||||
u32 txreq;
|
||||
u32 trec;
|
||||
u32 bdiag0;
|
||||
u32 bdiag1;
|
||||
union {
|
||||
struct {
|
||||
u32 tefcon;
|
||||
u32 tefsta;
|
||||
u32 tefua;
|
||||
};
|
||||
struct mcp251xfd_dump_regs_fifo tef;
|
||||
};
|
||||
u32 reserved0;
|
||||
union {
|
||||
struct {
|
||||
struct mcp251xfd_dump_regs_fifo txq;
|
||||
struct mcp251xfd_dump_regs_fifo tx_fifo;
|
||||
struct mcp251xfd_dump_regs_fifo rx_fifo;
|
||||
};
|
||||
struct mcp251xfd_dump_regs_fifo fifo[32];
|
||||
};
|
||||
u32 fltcon[8];
|
||||
struct mcp251xfd_dump_regs_filter filter[32];
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_ram {
|
||||
u8 ram[MCP251XFD_RAM_SIZE];
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_regs_mcp251xfd {
|
||||
u32 osc;
|
||||
u32 iocon;
|
||||
u32 crc;
|
||||
u32 ecccon;
|
||||
u32 eccstat;
|
||||
u32 devid;
|
||||
};
|
||||
|
||||
#define __dump_bit(val, prefix, bit, desc) \
|
||||
pr_info("%16s %s\t\t%s\n", __stringify(bit), \
|
||||
(val) & prefix##_##bit ? "x" : " ", desc)
|
||||
|
||||
#define __dump_mask(val, prefix, mask, fmt, desc) \
|
||||
pr_info("%16s = " fmt "\t\t%s\n", \
|
||||
__stringify(mask), \
|
||||
FIELD_GET(prefix##_##mask##_MASK, (val)), \
|
||||
desc)
|
||||
|
||||
static void mcp251xfd_dump_reg_con(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("CON: con(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_CON, TXBWS, "0x%02lx", "Transmit Bandwidth Sharing");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, ABAT, "Abort All Pending Transmissions");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, REQOP, "0x%02lx", "Request Operation Mode");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, OPMOD, "0x%02lx", "Operation Mode Status");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, TXQEN, "Enable Transmit Queue");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, STEF, "Store in Transmit Event FIFO");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, SERR2LOM, "Transition to Listen Only Mode on System Error");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, ESIGM, "Transmit ESI in Gateway Mode");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, RTXAT, "Restrict Retransmission Attempts");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, BRSDIS, "Bit Rate Switching Disable");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, BUSY, "CAN Module is Busy");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, WFT, "0x%02lx", "Selectable Wake-up Filter Time");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, WAKFIL, "Enable CAN Bus Line Wake-up Filter");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, PXEDIS, "Protocol Exception Event Detection Disabled");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, ISOCRCEN, "Enable ISO CRC in CAN FD Frames");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, DNCNT, "0x%02lx", "Device Net Filter Bit Number");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_nbtcfg(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("NBTCFG: nbtcfg(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, BRP, "%3lu", "Baud Rate Prescaler");
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, TSEG1, "%3lu", "Time Segment 1 (Propagation Segment + Phase Segment 1)");
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, TSEG2, "%3lu", "Time Segment 2 (Phase Segment 2)");
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, SJW, "%3lu", "Synchronization Jump Width");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_dbtcfg(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("DBTCFG: dbtcfg(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, BRP, "%3lu", "Baud Rate Prescaler");
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, TSEG1, "%3lu", "Time Segment 1 (Propagation Segment + Phase Segment 1)");
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, TSEG2, "%3lu", "Time Segment 2 (Phase Segment 2)");
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, SJW, "%3lu", "Synchronization Jump Width");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tdc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TDC: tdc(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_TDC, EDGFLTEN, "Enable Edge Filtering during Bus Integration state");
|
||||
__dump_bit(val, MCP251XFD_REG_TDC, SID11EN, "Enable 12-Bit SID in CAN FD Base Format Messages");
|
||||
__dump_mask(val, MCP251XFD_REG_TDC, TDCMOD, "0x%02lx", "Transmitter Delay Compensation Mode");
|
||||
__dump_mask(val, MCP251XFD_REG_TDC, TDCO, "0x%02lx", "Transmitter Delay Compensation Offset");
|
||||
__dump_mask(val, MCP251XFD_REG_TDC, TDCV, "0x%02lx", "Transmitter Delay Compensation Value");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tbc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TBC: tbc(0x%03x)=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_vec(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
u8 rx_code, tx_code, i_code;
|
||||
|
||||
pr_info("VEC: vec(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
rx_code = FIELD_GET(MCP251XFD_REG_VEC_RXCODE_MASK, val);
|
||||
tx_code = FIELD_GET(MCP251XFD_REG_VEC_TXCODE_MASK, val);
|
||||
i_code = FIELD_GET(MCP251XFD_REG_VEC_ICODE_MASK, val);
|
||||
|
||||
pr_info("\trxcode: ");
|
||||
if (rx_code == 0x40)
|
||||
pr_cont("No Interrupt");
|
||||
else if (rx_code < 0x20)
|
||||
pr_cont("FIFO %u", rx_code);
|
||||
else
|
||||
pr_cont("Reserved");
|
||||
pr_cont(" (0x%02x)\n", rx_code);
|
||||
|
||||
pr_info("\ttxcode: ");
|
||||
if (tx_code == 0x40)
|
||||
pr_cont("No Interrupt");
|
||||
else if (tx_code < 0x20)
|
||||
pr_cont("FIFO %u", tx_code);
|
||||
else
|
||||
pr_cont("Reserved");
|
||||
pr_cont(" (0x%02x)\n", tx_code);
|
||||
|
||||
pr_info("\ticode: ");
|
||||
if (i_code == 0x4a)
|
||||
pr_cont("Transmit Attempt Interrupt");
|
||||
else if (i_code == 0x49)
|
||||
pr_cont("Transmit Event FIFO Interrupt");
|
||||
else if (i_code == 0x48)
|
||||
pr_cont("Invalid Message Occurred");
|
||||
else if (i_code == 0x47)
|
||||
pr_cont("Operation Mode Changed");
|
||||
else if (i_code == 0x46)
|
||||
pr_cont("TBC Overflow");
|
||||
else if (i_code == 0x45)
|
||||
pr_cont("RX/TX MAB Overflow/Underflow");
|
||||
else if (i_code == 0x44)
|
||||
pr_cont("Address Error Interrupt");
|
||||
else if (i_code == 0x43)
|
||||
pr_cont("Receive FIFO Overflow Interrupt");
|
||||
else if (i_code == 0x42)
|
||||
pr_cont("Wake-up Interrupt");
|
||||
else if (i_code == 0x41)
|
||||
pr_cont("Error Interrupt");
|
||||
else if (i_code == 0x40)
|
||||
pr_cont("No Interrupt");
|
||||
else if (i_code < 0x20)
|
||||
pr_cont("FIFO %u", i_code);
|
||||
else
|
||||
pr_cont("Reserved");
|
||||
pr_cont(" (0x%02x)\n", i_code);
|
||||
}
|
||||
|
||||
#define __dump_int(val, bit, desc) \
|
||||
pr_info("\t" __stringify(bit) "\t%s\t%s\t%s\t%s\n", \
|
||||
(val) & MCP251XFD_REG_INT_##bit##E ? "x" : "", \
|
||||
(val) & MCP251XFD_REG_INT_##bit##F ? "x" : "", \
|
||||
FIELD_GET(MCP251XFD_REG_INT_IF_MASK, val) & \
|
||||
FIELD_GET(MCP251XFD_REG_INT_IE_MASK, val) & \
|
||||
MCP251XFD_REG_INT_##bit##F ? "x" : "", \
|
||||
desc)
|
||||
|
||||
static void mcp251xfd_dump_reg_intf(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("INT: intf(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
pr_info("\t\tIE\tIF\tIE & IF\n");
|
||||
__dump_int(val, IVMI, "Invalid Message Interrupt");
|
||||
__dump_int(val, WAKI, "Bus Wake Up Interrupt");
|
||||
__dump_int(val, CERRI, "CAN Bus Error Interrupt");
|
||||
__dump_int(val, SERRI, "System Error Interrupt");
|
||||
__dump_int(val, RXOVI, "Receive FIFO Overflow Interrupt");
|
||||
__dump_int(val, TXATI, "Transmit Attempt Interrupt");
|
||||
__dump_int(val, SPICRCI, "SPI CRC Error Interrupt");
|
||||
__dump_int(val, ECCI, "ECC Error Interrupt");
|
||||
__dump_int(val, TEFI, "Transmit Event FIFO Interrupt");
|
||||
__dump_int(val, MODI, "Mode Change Interrupt");
|
||||
__dump_int(val, TBCI, "Time Base Counter Interrupt");
|
||||
__dump_int(val, RXI, "Receive FIFO Interrupt");
|
||||
__dump_int(val, TXI, "Transmit FIFO Interrupt");
|
||||
}
|
||||
|
||||
#undef __dump_int
|
||||
|
||||
#define __create_dump_fifo_bitmask(fifo, name, description) \
|
||||
static void mcp251xfd_dump_reg_##fifo(const struct mcp251xfd_priv *priv, u32 val, u16 addr) \
|
||||
{ \
|
||||
int i; \
|
||||
\
|
||||
pr_info(__stringify(name) ": " __stringify(fifo) "(0x%03x)=0x%08x\n", addr, val); \
|
||||
pr_info(description ":\n"); \
|
||||
if (!val) { \
|
||||
pr_info("\t\t-none-\n"); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
pr_info("\t\t"); \
|
||||
for (i = 0; i < sizeof(val); i++) { \
|
||||
if (val & BIT(i)) \
|
||||
pr_cont("%d ", i); \
|
||||
} \
|
||||
\
|
||||
pr_cont("\n"); \
|
||||
}
|
||||
|
||||
__create_dump_fifo_bitmask(rxif, RXIF, "Receive FIFO Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(rxovif, RXOVIF, "Receive FIFO Overflow Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(txif, TXIF, "Transmit FIFO Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(txatif, TXATIF, "Transmit FIFO Attempt Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(txreq, TXREQ, "Message Send Request");
|
||||
|
||||
#undef __create_dump_fifo_bitmask
|
||||
|
||||
static void mcp251xfd_dump_reg_trec(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TREC: trec(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, TXBO, "Transmitter in Bus Off State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, TXBP, "Transmitter in Error Passive State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, RXBP, "Receiver in Error Passive State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, TXWARN, "Transmitter in Error Warning State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, RXWARN, "Receiver in Error Warning State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, EWARN, "Transmitter or Receiver is in Error Warning State");
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_TREC, TEC, "%3lu", "Transmit Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_TREC, REC, "%3lu", "Receive Error Counter");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_bdiag0(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("BDIAG0: bdiag0(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, DTERRCNT, "%3lu", "Data Bit Rate Transmit Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, DRERRCNT, "%3lu", "Data Bit Rate Receive Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, NTERRCNT, "%3lu", "Nominal Bit Rate Transmit Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, NRERRCNT, "%3lu", "Nominal Bit Rate Receive Error Counter");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_bdiag1(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("BDIAG1: bdiag1(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DLCMM, "DLC Mismatch");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, ESI, "ESI flag of a received CAN FD message was set");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DCRCERR, "Data CRC Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DSTUFERR, "Data Bit Stuffing Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DFORMERR, "Data Format Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DBIT1ERR, "Data BIT1 Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DBIT0ERR, "Data BIT0 Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, TXBOERR, "Device went to bus-off (and auto-recovered)");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NCRCERR, "CRC Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NSTUFERR, "Bit Stuffing Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NFORMERR, "Format Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NACKERR, "Transmitted message was not acknowledged");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NBIT1ERR, "Bit1 Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NBIT0ERR, "Bit0 Error");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG1, EFMSGCNT, "%3lu", "Error Free Message Counter");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_osc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("OSC: osc(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, SCLKRDY, "Synchronized SCLKDIV");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, OSCRDY, "Clock Ready");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, PLLRDY, "PLL Ready");
|
||||
__dump_mask(val, MCP251XFD_REG_OSC, CLKODIV, "0x%02lu", "Clock Output Divisor");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, SCLKDIV, "System Clock Divisor");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, LPMEN, "Low Power Mode (LPM) Enable (MCP2518FD only)");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, OSCDIS, "Clock (Oscillator) Disable");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, PLLEN, "PLL Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tefcon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TEFCON: tefcon(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_TEFCON, FSIZE, "%3lu", "FIFO Size");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, FRESET, "FIFO Reset");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, UINC, "Increment Tail");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFTSEN, "Transmit Event FIFO Time Stamp Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFOVIE, "Transmit Event FIFO Overflow Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFFIE, "Transmit Event FIFO Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFHIE, "Transmit Event FIFO Half Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFNEIE, "Transmit Event FIFO Not Empty Interrupt Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tefsta(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TEFSTA: tefsta(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFOVIF, "Transmit Event FIFO Overflow Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFFIF, "Transmit Event FIFO Full Interrupt Flag (0: not full)");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFHIF, "Transmit Event FIFO Half Full Interrupt Flag (0: < half full)");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFNEIF, "Transmit Event FIFO Not Empty Interrupt Flag (0: empty)");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tefua(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TEFUA: tefua(0x%03x)=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_fifocon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("FIFOCON: fifocon(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, PLSIZE, "%3lu", "Payload Size");
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, FSIZE, "%3lu", "FIFO Size");
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, TXAT, "%3lu", "Retransmission Attempts");
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, TXPRI, "%3lu", "Message Transmit Priority");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, FRESET, "FIFO Reset");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXREQ, "Message Send Request");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, UINC, "Increment Head/Tail");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXEN, "TX/RX FIFO Selection (0: RX, 1: TX)");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, RTREN, "Auto RTR Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, RXTSEN, "Received Message Time Stamp Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXATIE, "Transmit Attempts Exhausted Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, RXOVIE, "Overflow Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFERFFIE, "Transmit/Receive FIFO Empty/Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFHRFHIE, "Transmit/Receive FIFO Half Empty/Half Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFNRFNIE, "Transmit/Receive FIFO Not Full/Not Empty Interrupt Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_fifosta(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("FIFOSTA: fifosta(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOSTA, FIFOCI, "%3lu", "FIFO Message Index");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXABT, "Message Aborted Status (0: completed successfully, 1: aborted)");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXLARB, "Message Lost Arbitration Status");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXERR, "Error Detected During Transmission");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXATIF, "Transmit Attempts Exhausted Interrupt Pending");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, RXOVIF, "Receive FIFO Overflow Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFERFFIF, "Transmit/Receive FIFO Empty/Full Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFHRFHIF, "Transmit/Receive FIFO Half Empty/Half Full Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFNRFNIF, "Transmit/Receive FIFO Not Full/Not Empty Interrupt Flag");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_fifoua(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("FIFOUA: fifoua(0x%03x)=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
#define __dump_call(regs, val) \
|
||||
do { \
|
||||
mcp251xfd_dump_reg_##val(priv, (regs)->val, \
|
||||
(u16)(offsetof(typeof(*(regs)), val) + \
|
||||
(sizeof(*(regs)) == sizeof(struct mcp251xfd_dump_regs) ? \
|
||||
0 : MCP251XFD_REG_OSC))); \
|
||||
pr_info("\n"); \
|
||||
} while (0)
|
||||
|
||||
#define __dump_call_fifo(reg, val) \
|
||||
do { \
|
||||
mcp251xfd_dump_reg_##reg(priv, regs->val, (u16)offsetof(typeof(*regs), val)); \
|
||||
pr_info("\n"); \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_regs(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_regs_mcp251xfd *regs_mcp251xfd)
|
||||
{
|
||||
netdev_info(priv->ndev, "-------------------- register dump --------------------\n");
|
||||
__dump_call(regs, con);
|
||||
__dump_call(regs, nbtcfg);
|
||||
__dump_call(regs, dbtcfg);
|
||||
__dump_call(regs, tdc);
|
||||
__dump_call(regs, tbc);
|
||||
__dump_call(regs, vec);
|
||||
__dump_call(regs, intf);
|
||||
__dump_call(regs, rxif);
|
||||
__dump_call(regs, rxovif);
|
||||
__dump_call(regs, txif);
|
||||
__dump_call(regs, txatif);
|
||||
__dump_call(regs, txreq);
|
||||
__dump_call(regs, trec);
|
||||
__dump_call(regs, bdiag0);
|
||||
__dump_call(regs, bdiag1);
|
||||
__dump_call(regs_mcp251xfd, osc);
|
||||
pr_info("-------------------- TEF --------------------\n");
|
||||
__dump_call(regs, tefcon);
|
||||
__dump_call(regs, tefsta);
|
||||
__dump_call(regs, tefua);
|
||||
pr_info("-------------------- TX_FIFO --------------------\n");
|
||||
__dump_call_fifo(fifocon, fifo[MCP251XFD_TX_FIFO].con);
|
||||
__dump_call_fifo(fifosta, fifo[MCP251XFD_TX_FIFO].sta);
|
||||
__dump_call_fifo(fifoua, fifo[MCP251XFD_TX_FIFO].ua);
|
||||
pr_info(" -------------------- RX_FIFO --------------------\n");
|
||||
__dump_call_fifo(fifocon, fifo[MCP251XFD_RX_FIFO(0)].con);
|
||||
__dump_call_fifo(fifosta, fifo[MCP251XFD_RX_FIFO(0)].sta);
|
||||
__dump_call_fifo(fifoua, fifo[MCP251XFD_RX_FIFO(0)].ua);
|
||||
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
|
||||
}
|
||||
|
||||
#undef __dump_call
|
||||
#undef __dump_call_fifo
|
||||
|
||||
static u8 mcp251xfd_dump_get_fifo_size(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
|
||||
{
|
||||
u8 obj_size;
|
||||
|
||||
obj_size = FIELD_GET(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, fifo_con);
|
||||
switch (obj_size) {
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_8:
|
||||
return 8;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_12:
|
||||
return 12;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_16:
|
||||
return 16;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_20:
|
||||
return 20;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_24:
|
||||
return 24;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_32:
|
||||
return 32;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_48:
|
||||
return 48;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_64:
|
||||
return 64;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 mcp251xfd_dump_get_fifo_obj_num(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
|
||||
{
|
||||
u8 obj_num;
|
||||
|
||||
obj_num = FIELD_GET(MCP251XFD_REG_FIFOCON_FSIZE_MASK, fifo_con);
|
||||
|
||||
return obj_num + 1;
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_ram_fifo_obj_data(const struct mcp251xfd_priv *priv, const u8 *data, u8 dlc)
|
||||
{
|
||||
int i;
|
||||
u8 len;
|
||||
|
||||
len = can_dlc2len(get_canfd_dlc(dlc));
|
||||
|
||||
if (!len) {
|
||||
pr_info("%16s = -none-\n", "data");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i % 8) == 0) {
|
||||
if (i == 0)
|
||||
pr_info("%16s = %02x", "data", data[i]);
|
||||
else
|
||||
pr_info(" %02x", data[i]);
|
||||
} else if ((i % 4) == 0) {
|
||||
pr_cont(" %02x", data[i]);
|
||||
} else if ((i % 8) == 7) {
|
||||
pr_cont(" %02x\n", data[i]);
|
||||
} else {
|
||||
pr_cont(" %02x", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (i % 8)
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
/* TEF */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tef.con);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return regs->tefua / sizeof(struct mcp251xfd_hw_tef_obj);
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tef_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
u8 n)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tef_obj) * n;
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tef_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tef_obj_rel_addr(priv, n) +
|
||||
MCP251XFD_RAM_START;
|
||||
}
|
||||
|
||||
/* TX */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tx_obj_can) -
|
||||
sizeof_field(struct mcp251xfd_hw_tx_obj_can, data) +
|
||||
mcp251xfd_dump_get_fifo_size(priv, regs, regs->tx_fifo.con);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tx_fifo.con);
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tx_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tef_obj_rel_addr(priv, mcp251xfd_dump_get_tef_obj_num(priv, regs)) +
|
||||
mcp251xfd_dump_get_tx_obj_size(priv, regs) * n;
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tx_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs, u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, n) +
|
||||
MCP251XFD_RAM_START;
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return (regs->fifo[MCP251XFD_TX_FIFO].ua -
|
||||
mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, 0)) /
|
||||
mcp251xfd_dump_get_tx_obj_size(priv, regs);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_head(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK,
|
||||
regs->fifo[MCP251XFD_TX_FIFO].sta);
|
||||
}
|
||||
|
||||
/* RX */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_rx_obj_can) -
|
||||
sizeof_field(struct mcp251xfd_hw_rx_obj_can, data) +
|
||||
mcp251xfd_dump_get_fifo_size(priv, regs, regs->rx_fifo.con);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->rx_fifo.con);
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_rx_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs, u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, mcp251xfd_dump_get_tx_obj_num(priv, regs)) +
|
||||
mcp251xfd_dump_get_rx_obj_size(priv, regs) * n;
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_rx_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs, u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, n) + MCP251XFD_RAM_START;
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return (regs->fifo[MCP251XFD_RX_FIFO(0)].ua -
|
||||
mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, 0)) /
|
||||
mcp251xfd_dump_get_rx_obj_size(priv, regs);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_head(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, regs->fifo[MCP251XFD_RX_FIFO(0)].sta);
|
||||
}
|
||||
|
||||
/* dump TEF */
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tef_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_ring *tef,
|
||||
const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
|
||||
u8 n)
|
||||
{
|
||||
pr_info("TEF Object: 0x%02x (0x%03x)%s%s%s%s%s\n",
|
||||
n, mcp251xfd_dump_get_tef_obj_addr(priv, n),
|
||||
mcp251xfd_get_ring_head(tef) == n ? " priv-HEAD" : "",
|
||||
mcp251xfd_dump_get_tef_tail(priv, regs) == n ? " chip-TAIL" : "",
|
||||
mcp251xfd_get_ring_tail(tef) == n ? " priv-TAIL" : "",
|
||||
(mcp251xfd_dump_get_tef_tail(priv, regs) == n ?
|
||||
((regs->tef.sta & MCP251XFD_REG_TEFSTA_TEFFIF) ? " chip-FIFO-full" :
|
||||
!(regs->tef.sta & MCP251XFD_REG_TEFSTA_TEFNEIF) ? " chip-FIFO-empty" : "") :
|
||||
("")),
|
||||
(mcp251xfd_get_ring_head(tef) == mcp251xfd_get_ring_tail(tef) &&
|
||||
mcp251xfd_get_ring_tail(tef) == n ?
|
||||
(priv->tef->head == priv->tef->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
|
||||
("")));
|
||||
pr_info("%16s = 0x%08x\n", "id", hw_tef_obj->id);
|
||||
pr_info("%16s = 0x%08x\n", "flags", hw_tef_obj->flags);
|
||||
pr_info("%16s = 0x%08x\n", "ts", hw_tef_obj->ts);
|
||||
__dump_mask(hw_tef_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ, "0x%06lx", "Sequence");
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tef_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram,
|
||||
const struct mcp251xfd_ring *tef)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("\nTEF Overview:\n");
|
||||
pr_info("%16s = 0x%02x 0x%08x\n", "head (p)",
|
||||
mcp251xfd_get_ring_head(tef),
|
||||
tef->head);
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
|
||||
mcp251xfd_dump_get_tef_tail(priv, regs),
|
||||
mcp251xfd_get_ring_tail(tef),
|
||||
tef->tail);
|
||||
pr_info("\n");
|
||||
|
||||
for (i = 0; i < mcp251xfd_dump_get_tef_obj_num(priv, regs); i++) {
|
||||
const struct mcp251xfd_hw_tef_obj *hw_tef_obj;
|
||||
u16 hw_tef_obj_rel_addr;
|
||||
|
||||
hw_tef_obj_rel_addr = mcp251xfd_dump_get_tef_obj_rel_addr(priv, i);
|
||||
|
||||
hw_tef_obj = (const struct mcp251xfd_hw_tef_obj *)&ram->ram[hw_tef_obj_rel_addr];
|
||||
mcp251xfd_dump_ram_tef_obj_one(priv, regs, tef, hw_tef_obj, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* dump TX */
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tx_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_ring *tx,
|
||||
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj,
|
||||
u8 n)
|
||||
{
|
||||
pr_info("TX Object: 0x%02x (0x%03x)%s%s%s%s%s%s\n",
|
||||
n, mcp251xfd_dump_get_tx_obj_addr(priv, regs, n),
|
||||
mcp251xfd_dump_get_tx_head(priv, regs) == n ? " chip-HEAD" : "",
|
||||
mcp251xfd_get_ring_head(tx) == n ? " priv-HEAD" : "",
|
||||
mcp251xfd_dump_get_tx_tail(priv, regs) == n ? " chip-TAIL" : "",
|
||||
mcp251xfd_get_ring_tail(tx) == n ? " priv-TAIL" : "",
|
||||
mcp251xfd_dump_get_tx_tail(priv, regs) == n ?
|
||||
(!(regs->tx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF) ? " chip-FIFO-full" :
|
||||
(regs->tx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFERFFIF) ? " chip-FIFO-empty" : "") :
|
||||
(""),
|
||||
(mcp251xfd_get_ring_head(tx) == mcp251xfd_get_ring_tail(tx) &&
|
||||
mcp251xfd_get_ring_tail(tx) == n ?
|
||||
(tx->head == tx->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
|
||||
("")));
|
||||
pr_info("%16s = 0x%08x\n", "id", hw_tx_obj->id);
|
||||
pr_info("%16s = 0x%08x\n", "flags", hw_tx_obj->flags);
|
||||
__dump_mask(hw_tx_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ_MCP2517FD, "0x%06lx", "Sequence (MCP2517)");
|
||||
__dump_mask(hw_tx_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ_MCP2518FD, "0x%06lx", "Sequence (MCP2518)");
|
||||
mcp251xfd_dump_ram_fifo_obj_data(priv,
|
||||
hw_tx_obj->data,
|
||||
FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_tx_obj->flags));
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tx_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram,
|
||||
const struct mcp251xfd_ring *tx)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("\nTX Overview:\n");
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/p)",
|
||||
mcp251xfd_dump_get_tx_head(priv, regs),
|
||||
mcp251xfd_get_ring_head(tx),
|
||||
tx->head);
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
|
||||
mcp251xfd_dump_get_tx_tail(priv, regs),
|
||||
mcp251xfd_get_ring_tail(tx),
|
||||
tx->tail);
|
||||
pr_info("\n");
|
||||
|
||||
for (i = 0; i < mcp251xfd_dump_get_tx_obj_num(priv, regs); i++) {
|
||||
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj;
|
||||
u16 hw_tx_obj_rel_addr;
|
||||
|
||||
hw_tx_obj_rel_addr = mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, i);
|
||||
|
||||
hw_tx_obj = (const struct mcp251xfd_hw_tx_obj_canfd *)&ram->ram[hw_tx_obj_rel_addr];
|
||||
mcp251xfd_dump_ram_tx_obj_one(priv, regs, tx, hw_tx_obj, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* dump RX */
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_rx_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_ring *rx,
|
||||
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
|
||||
u8 n)
|
||||
{
|
||||
pr_info("RX Object: 0x%02x (0x%03x)%s%s%s%s%s%s\n",
|
||||
n, mcp251xfd_dump_get_rx_obj_addr(priv, regs, n),
|
||||
mcp251xfd_dump_get_rx_head(priv, regs) == n ? " chip-HEAD" : "",
|
||||
mcp251xfd_get_ring_head(rx) == n ? " priv-HEAD" : "",
|
||||
mcp251xfd_dump_get_rx_tail(priv, regs) == n ? " chip-TAIL" : "",
|
||||
mcp251xfd_get_ring_tail(rx) == n ? " priv-TAIL" : "",
|
||||
mcp251xfd_dump_get_rx_tail(priv, regs) == n ?
|
||||
((regs->rx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFERFFIF) ? " chip-FIFO-full" :
|
||||
!(regs->rx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF) ? " chip-FIFO-empty" : "") :
|
||||
(""),
|
||||
(mcp251xfd_get_ring_head(rx) == mcp251xfd_get_ring_tail(rx) &&
|
||||
mcp251xfd_get_ring_tail(rx) == n ?
|
||||
(priv->rx->head == priv->rx->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
|
||||
("")));
|
||||
pr_info("%16s = 0x%08x\n", "id", hw_rx_obj->id);
|
||||
pr_info("%16s = 0x%08x\n", "flags", hw_rx_obj->flags);
|
||||
pr_info("%16s = 0x%08x\n", "ts", hw_rx_obj->ts);
|
||||
mcp251xfd_dump_ram_fifo_obj_data(priv, hw_rx_obj->data, FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags));
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_rx_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram,
|
||||
const struct mcp251xfd_ring *rx)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("\nRX Overview:\n");
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/p)",
|
||||
mcp251xfd_dump_get_rx_head(priv, regs),
|
||||
mcp251xfd_get_ring_head(rx), rx->head);
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
|
||||
mcp251xfd_dump_get_rx_tail(priv, regs),
|
||||
mcp251xfd_get_ring_tail(rx), rx->tail);
|
||||
pr_info("\n");
|
||||
|
||||
for (i = 0; i < mcp251xfd_dump_get_rx_obj_num(priv, regs); i++) {
|
||||
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj;
|
||||
u16 hw_rx_obj_rel_addr;
|
||||
|
||||
hw_rx_obj_rel_addr = mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, i);
|
||||
hw_rx_obj = (const struct mcp251xfd_hw_rx_obj_canfd *)&ram->ram[hw_rx_obj_rel_addr];
|
||||
|
||||
mcp251xfd_dump_ram_rx_obj_one(priv, regs, rx, hw_rx_obj, i);
|
||||
}
|
||||
}
|
||||
|
||||
#undef __dump_mask
|
||||
#undef __dump_bit
|
||||
|
||||
static void mcp251xfd_dump_ram(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, const struct mcp251xfd_dump_ram *ram)
|
||||
{
|
||||
netdev_info(priv->ndev, "----------------------- RAM dump ----------------------\n");
|
||||
mcp251xfd_dump_ram_tef_obj(priv, regs, ram, priv->tef);
|
||||
mcp251xfd_dump_ram_tx_obj(priv, regs, ram, priv->tx);
|
||||
mcp251xfd_dump_ram_rx_obj(priv, regs, ram, priv->rx);
|
||||
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
|
||||
}
|
||||
|
||||
void mcp251xfd_dump(struct mcp251xfd_priv *priv)
|
||||
{
|
||||
struct mcp251xfd_dump_regs regs;
|
||||
struct mcp251xfd_dump_ram ram;
|
||||
struct mcp251xfd_dump_regs_mcp251xfd regs_mcp251xfd;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct mcp251xfd_dump_regs) !=
|
||||
MCP251XFD_REG_FIFOUA(31) - MCP251XFD_REG_CON + 4);
|
||||
|
||||
err = regmap_bulk_read(priv->map, MCP251XFD_REG_CON,
|
||||
®s, sizeof(regs) / sizeof(u32));
|
||||
if (err)
|
||||
return;
|
||||
|
||||
err = regmap_bulk_read(priv->map, MCP251XFD_RAM_START,
|
||||
&ram, sizeof(ram) / sizeof(u32));
|
||||
if (err)
|
||||
return;
|
||||
|
||||
err = regmap_bulk_read(priv->map, MCP251XFD_REG_OSC,
|
||||
®s_mcp251xfd, sizeof(regs_mcp251xfd) / sizeof(u32));
|
||||
if (err)
|
||||
return;
|
||||
|
||||
mcp251xfd_dump_regs(priv, ®s, ®s_mcp251xfd);
|
||||
mcp251xfd_dump_ram(priv, ®s, &ram);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
*
|
||||
* Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_DUMP_H
|
||||
#define _MCP251XFD_DUMP_H
|
||||
|
||||
#define MCP251XFD_DUMP_MAGIC 0x1825434d
|
||||
|
||||
enum mcp251xfd_dump_object_type {
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_REG,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_TEF,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_RX,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_TX,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_END = -1,
|
||||
};
|
||||
|
||||
enum mcp251xfd_dump_object_ring_key {
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
|
||||
__MCP251XFD_DUMP_OBJECT_RING_KEY_MAX,
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_object_header {
|
||||
__le32 magic;
|
||||
__le32 type;
|
||||
__le32 offset;
|
||||
__le32 len;
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_object_reg {
|
||||
__le32 reg;
|
||||
__le32 val;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020, 2021 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s - decode chip and driver state of mcp251xfd.\n"
|
||||
"\n"
|
||||
"Usage: %s [options] <file>\n"
|
||||
"\n"
|
||||
" <file> path to dev coredump file\n"
|
||||
" ('/var/log/devcoredump-19700101-234200.dump')\n"
|
||||
" path to regmap register file\n"
|
||||
" ('/sys/kernel/debug/regmap/spi1.0-crc/registers')\n"
|
||||
" shortcut to regmap register file\n"
|
||||
" ('spi0.0')\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help this help\n"
|
||||
"\n",
|
||||
prg, prg);
|
||||
}
|
||||
|
||||
int regmap_bulk_read(struct regmap *map, unsigned int reg,
|
||||
void *val, size_t val_count)
|
||||
{
|
||||
memcpy(val, map->mem->buf + reg,
|
||||
val_count * sizeof(uint32_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct mcp251xfd_mem mem = { };
|
||||
struct regmap map = {
|
||||
.mem = &mem,
|
||||
};
|
||||
struct mcp251xfd_priv priv = {
|
||||
.map = &map,
|
||||
};
|
||||
const char *file_path;
|
||||
int opt, err;
|
||||
|
||||
struct option long_options[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
file_path = argv[optind];
|
||||
|
||||
if (!file_path) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
err = mcp251xfd_dev_coredump_read(&priv, &mem, file_path);
|
||||
if (err)
|
||||
err = mcp251xfd_regmap_read(&priv, &mem, file_path);
|
||||
if (err) {
|
||||
fprintf(stderr, "Unable to read file: '%s'\n", file_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mcp251xfd_dump(&priv);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
static int
|
||||
do_mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path)
|
||||
{
|
||||
FILE *reg_file;
|
||||
uint16_t reg;
|
||||
uint32_t val;
|
||||
|
||||
reg_file = fopen(file_path, "r");
|
||||
if (!reg_file)
|
||||
return -errno;
|
||||
|
||||
while (fscanf(reg_file, "%hx: %x\n", ®, &val) == 2) {
|
||||
if (reg >= ARRAY_SIZE(mem->buf))
|
||||
return -EINVAL;
|
||||
|
||||
*(uint32_t *)(mem->buf + reg) = val;
|
||||
}
|
||||
|
||||
fclose(reg_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path)
|
||||
{
|
||||
char *tmp;
|
||||
int err;
|
||||
|
||||
err = do_mcp251xfd_regmap_read(priv, mem, file_path);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
/* maybe it's something like "spi0.0" */
|
||||
tmp = strchr(file_path, '/');
|
||||
if (tmp)
|
||||
return -ENOENT;
|
||||
|
||||
/* first try literally */
|
||||
err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s/registers", file_path);
|
||||
if (err == -1)
|
||||
return -errno;
|
||||
|
||||
err = do_mcp251xfd_regmap_read(priv, mem, tmp);
|
||||
free (tmp);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
/* then add "-crc" */
|
||||
err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s-crc/registers", file_path);
|
||||
if (err == -1)
|
||||
return -errno;
|
||||
|
||||
err = do_mcp251xfd_regmap_read(priv, mem, tmp);
|
||||
free (tmp);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
*
|
||||
* Copyright (c) 2019, 2020 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
* Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_H
|
||||
#define _MCP251XFD_H
|
||||
|
||||
/* MPC251x registers */
|
||||
|
||||
/* CAN FD Controller Module SFR */
|
||||
#define MCP251XFD_REG_CON 0x00
|
||||
#define MCP251XFD_REG_CON_TXBWS_MASK GENMASK(31, 28)
|
||||
#define MCP251XFD_REG_CON_ABAT BIT(27)
|
||||
#define MCP251XFD_REG_CON_REQOP_MASK GENMASK(26, 24)
|
||||
#define MCP251XFD_REG_CON_MODE_MIXED 0
|
||||
#define MCP251XFD_REG_CON_MODE_SLEEP 1
|
||||
#define MCP251XFD_REG_CON_MODE_INT_LOOPBACK 2
|
||||
#define MCP251XFD_REG_CON_MODE_LISTENONLY 3
|
||||
#define MCP251XFD_REG_CON_MODE_CONFIG 4
|
||||
#define MCP251XFD_REG_CON_MODE_EXT_LOOPBACK 5
|
||||
#define MCP251XFD_REG_CON_MODE_CAN2_0 6
|
||||
#define MCP251XFD_REG_CON_MODE_RESTRICTED 7
|
||||
#define MCP251XFD_REG_CON_OPMOD_MASK GENMASK(23, 21)
|
||||
#define MCP251XFD_REG_CON_TXQEN BIT(20)
|
||||
#define MCP251XFD_REG_CON_STEF BIT(19)
|
||||
#define MCP251XFD_REG_CON_SERR2LOM BIT(18)
|
||||
#define MCP251XFD_REG_CON_ESIGM BIT(17)
|
||||
#define MCP251XFD_REG_CON_RTXAT BIT(16)
|
||||
#define MCP251XFD_REG_CON_BRSDIS BIT(12)
|
||||
#define MCP251XFD_REG_CON_BUSY BIT(11)
|
||||
#define MCP251XFD_REG_CON_WFT_MASK GENMASK(10, 9)
|
||||
#define MCP251XFD_REG_CON_WFT_T00FILTER 0x0
|
||||
#define MCP251XFD_REG_CON_WFT_T01FILTER 0x1
|
||||
#define MCP251XFD_REG_CON_WFT_T10FILTER 0x2
|
||||
#define MCP251XFD_REG_CON_WFT_T11FILTER 0x3
|
||||
#define MCP251XFD_REG_CON_WAKFIL BIT(8)
|
||||
#define MCP251XFD_REG_CON_PXEDIS BIT(6)
|
||||
#define MCP251XFD_REG_CON_ISOCRCEN BIT(5)
|
||||
#define MCP251XFD_REG_CON_DNCNT_MASK GENMASK(4, 0)
|
||||
|
||||
#define MCP251XFD_REG_NBTCFG 0x04
|
||||
#define MCP251XFD_REG_NBTCFG_BRP_MASK GENMASK(31, 24)
|
||||
#define MCP251XFD_REG_NBTCFG_TSEG1_MASK GENMASK(23, 16)
|
||||
#define MCP251XFD_REG_NBTCFG_TSEG2_MASK GENMASK(14, 8)
|
||||
#define MCP251XFD_REG_NBTCFG_SJW_MASK GENMASK(6, 0)
|
||||
|
||||
#define MCP251XFD_REG_DBTCFG 0x08
|
||||
#define MCP251XFD_REG_DBTCFG_BRP_MASK GENMASK(31, 24)
|
||||
#define MCP251XFD_REG_DBTCFG_TSEG1_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_DBTCFG_TSEG2_MASK GENMASK(11, 8)
|
||||
#define MCP251XFD_REG_DBTCFG_SJW_MASK GENMASK(3, 0)
|
||||
|
||||
#define MCP251XFD_REG_TDC 0x0c
|
||||
#define MCP251XFD_REG_TDC_EDGFLTEN BIT(25)
|
||||
#define MCP251XFD_REG_TDC_SID11EN BIT(24)
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_MASK GENMASK(17, 16)
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_AUTO 2
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_MANUAL 1
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_DISABLED 0
|
||||
#define MCP251XFD_REG_TDC_TDCO_MASK GENMASK(14, 8)
|
||||
#define MCP251XFD_REG_TDC_TDCV_MASK GENMASK(5, 0)
|
||||
|
||||
#define MCP251XFD_REG_TBC 0x10
|
||||
|
||||
#define MCP251XFD_REG_TSCON 0x14
|
||||
#define MCP251XFD_REG_TSCON_TSRES BIT(18)
|
||||
#define MCP251XFD_REG_TSCON_TSEOF BIT(17)
|
||||
#define MCP251XFD_REG_TSCON_TBCEN BIT(16)
|
||||
#define MCP251XFD_REG_TSCON_TBCPRE_MASK GENMASK(9, 0)
|
||||
|
||||
#define MCP251XFD_REG_VEC 0x18
|
||||
#define MCP251XFD_REG_VEC_RXCODE_MASK GENMASK(30, 24)
|
||||
#define MCP251XFD_REG_VEC_TXCODE_MASK GENMASK(22, 16)
|
||||
#define MCP251XFD_REG_VEC_FILHIT_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_VEC_ICODE_MASK GENMASK(6, 0)
|
||||
|
||||
#define MCP251XFD_REG_INT 0x1c
|
||||
#define MCP251XFD_REG_INT_IF_MASK GENMASK(15, 0)
|
||||
#define MCP251XFD_REG_INT_IE_MASK GENMASK(31, 16)
|
||||
#define MCP251XFD_REG_INT_IVMIE BIT(31)
|
||||
#define MCP251XFD_REG_INT_WAKIE BIT(30)
|
||||
#define MCP251XFD_REG_INT_CERRIE BIT(29)
|
||||
#define MCP251XFD_REG_INT_SERRIE BIT(28)
|
||||
#define MCP251XFD_REG_INT_RXOVIE BIT(27)
|
||||
#define MCP251XFD_REG_INT_TXATIE BIT(26)
|
||||
#define MCP251XFD_REG_INT_SPICRCIE BIT(25)
|
||||
#define MCP251XFD_REG_INT_ECCIE BIT(24)
|
||||
#define MCP251XFD_REG_INT_TEFIE BIT(20)
|
||||
#define MCP251XFD_REG_INT_MODIE BIT(19)
|
||||
#define MCP251XFD_REG_INT_TBCIE BIT(18)
|
||||
#define MCP251XFD_REG_INT_RXIE BIT(17)
|
||||
#define MCP251XFD_REG_INT_TXIE BIT(16)
|
||||
#define MCP251XFD_REG_INT_IVMIF BIT(15)
|
||||
#define MCP251XFD_REG_INT_WAKIF BIT(14)
|
||||
#define MCP251XFD_REG_INT_CERRIF BIT(13)
|
||||
#define MCP251XFD_REG_INT_SERRIF BIT(12)
|
||||
#define MCP251XFD_REG_INT_RXOVIF BIT(11)
|
||||
#define MCP251XFD_REG_INT_TXATIF BIT(10)
|
||||
#define MCP251XFD_REG_INT_SPICRCIF BIT(9)
|
||||
#define MCP251XFD_REG_INT_ECCIF BIT(8)
|
||||
#define MCP251XFD_REG_INT_TEFIF BIT(4)
|
||||
#define MCP251XFD_REG_INT_MODIF BIT(3)
|
||||
#define MCP251XFD_REG_INT_TBCIF BIT(2)
|
||||
#define MCP251XFD_REG_INT_RXIF BIT(1)
|
||||
#define MCP251XFD_REG_INT_TXIF BIT(0)
|
||||
/* These IRQ flags must be cleared by SW in the CAN_INT register */
|
||||
#define MCP251XFD_REG_INT_IF_CLEARABLE_MASK \
|
||||
(MCP251XFD_REG_INT_IVMIF | MCP251XFD_REG_INT_WAKIF | \
|
||||
MCP251XFD_REG_INT_CERRIF | MCP251XFD_REG_INT_SERRIF | \
|
||||
MCP251XFD_REG_INT_MODIF)
|
||||
|
||||
#define MCP251XFD_REG_RXIF 0x20
|
||||
#define MCP251XFD_REG_TXIF 0x24
|
||||
#define MCP251XFD_REG_RXOVIF 0x28
|
||||
#define MCP251XFD_REG_TXATIF 0x2c
|
||||
#define MCP251XFD_REG_TXREQ 0x30
|
||||
|
||||
#define MCP251XFD_REG_TREC 0x34
|
||||
#define MCP251XFD_REG_TREC_TXBO BIT(21)
|
||||
#define MCP251XFD_REG_TREC_TXBP BIT(20)
|
||||
#define MCP251XFD_REG_TREC_RXBP BIT(19)
|
||||
#define MCP251XFD_REG_TREC_TXWARN BIT(18)
|
||||
#define MCP251XFD_REG_TREC_RXWARN BIT(17)
|
||||
#define MCP251XFD_REG_TREC_EWARN BIT(16)
|
||||
#define MCP251XFD_REG_TREC_TEC_MASK GENMASK(15, 8)
|
||||
#define MCP251XFD_REG_TREC_REC_MASK GENMASK(7, 0)
|
||||
|
||||
#define MCP251XFD_REG_BDIAG0 0x38
|
||||
#define MCP251XFD_REG_BDIAG0_DTERRCNT_MASK GENMASK(31, 24)
|
||||
#define MCP251XFD_REG_BDIAG0_DRERRCNT_MASK GENMASK(23, 16)
|
||||
#define MCP251XFD_REG_BDIAG0_NTERRCNT_MASK GENMASK(15, 8)
|
||||
#define MCP251XFD_REG_BDIAG0_NRERRCNT_MASK GENMASK(7, 0)
|
||||
|
||||
#define MCP251XFD_REG_BDIAG1 0x3c
|
||||
#define MCP251XFD_REG_BDIAG1_DLCMM BIT(31)
|
||||
#define MCP251XFD_REG_BDIAG1_ESI BIT(30)
|
||||
#define MCP251XFD_REG_BDIAG1_DCRCERR BIT(29)
|
||||
#define MCP251XFD_REG_BDIAG1_DSTUFERR BIT(28)
|
||||
#define MCP251XFD_REG_BDIAG1_DFORMERR BIT(27)
|
||||
#define MCP251XFD_REG_BDIAG1_DBIT1ERR BIT(25)
|
||||
#define MCP251XFD_REG_BDIAG1_DBIT0ERR BIT(24)
|
||||
#define MCP251XFD_REG_BDIAG1_TXBOERR BIT(23)
|
||||
#define MCP251XFD_REG_BDIAG1_NCRCERR BIT(21)
|
||||
#define MCP251XFD_REG_BDIAG1_NSTUFERR BIT(20)
|
||||
#define MCP251XFD_REG_BDIAG1_NFORMERR BIT(19)
|
||||
#define MCP251XFD_REG_BDIAG1_NACKERR BIT(18)
|
||||
#define MCP251XFD_REG_BDIAG1_NBIT1ERR BIT(17)
|
||||
#define MCP251XFD_REG_BDIAG1_NBIT0ERR BIT(16)
|
||||
#define MCP251XFD_REG_BDIAG1_BERR_MASK \
|
||||
(MCP251XFD_REG_BDIAG1_DLCMM | MCP251XFD_REG_BDIAG1_ESI | \
|
||||
MCP251XFD_REG_BDIAG1_DCRCERR | MCP251XFD_REG_BDIAG1_DSTUFERR | \
|
||||
MCP251XFD_REG_BDIAG1_DFORMERR | MCP251XFD_REG_BDIAG1_DBIT1ERR | \
|
||||
MCP251XFD_REG_BDIAG1_DBIT0ERR | MCP251XFD_REG_BDIAG1_TXBOERR | \
|
||||
MCP251XFD_REG_BDIAG1_NCRCERR | MCP251XFD_REG_BDIAG1_NSTUFERR | \
|
||||
MCP251XFD_REG_BDIAG1_NFORMERR | MCP251XFD_REG_BDIAG1_NACKERR | \
|
||||
MCP251XFD_REG_BDIAG1_NBIT1ERR | MCP251XFD_REG_BDIAG1_NBIT0ERR)
|
||||
#define MCP251XFD_REG_BDIAG1_EFMSGCNT_MASK GENMASK(15, 0)
|
||||
|
||||
#define MCP251XFD_REG_TEFCON 0x40
|
||||
#define MCP251XFD_REG_TEFCON_FSIZE_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_TEFCON_FRESET BIT(10)
|
||||
#define MCP251XFD_REG_TEFCON_UINC BIT(8)
|
||||
#define MCP251XFD_REG_TEFCON_TEFTSEN BIT(5)
|
||||
#define MCP251XFD_REG_TEFCON_TEFOVIE BIT(3)
|
||||
#define MCP251XFD_REG_TEFCON_TEFFIE BIT(2)
|
||||
#define MCP251XFD_REG_TEFCON_TEFHIE BIT(1)
|
||||
#define MCP251XFD_REG_TEFCON_TEFNEIE BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TEFSTA 0x44
|
||||
#define MCP251XFD_REG_TEFSTA_TEFOVIF BIT(3)
|
||||
#define MCP251XFD_REG_TEFSTA_TEFFIF BIT(2)
|
||||
#define MCP251XFD_REG_TEFSTA_TEFHIF BIT(1)
|
||||
#define MCP251XFD_REG_TEFSTA_TEFNEIF BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TEFUA 0x48
|
||||
|
||||
#define MCP251XFD_REG_TXQCON 0x50
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_MASK GENMASK(31, 29)
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_8 0
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_12 1
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_16 2
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_20 3
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_24 4
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_32 5
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_48 6
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_64 7
|
||||
#define MCP251XFD_REG_TXQCON_FSIZE_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_UNLIMITED 3
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_THREE_SHOT 1
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_ONE_SHOT 0
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_MASK GENMASK(22, 21)
|
||||
#define MCP251XFD_REG_TXQCON_TXPRI_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_TXQCON_FRESET BIT(10)
|
||||
#define MCP251XFD_REG_TXQCON_TXREQ BIT(9)
|
||||
#define MCP251XFD_REG_TXQCON_UINC BIT(8)
|
||||
#define MCP251XFD_REG_TXQCON_TXEN BIT(7)
|
||||
#define MCP251XFD_REG_TXQCON_TXATIE BIT(4)
|
||||
#define MCP251XFD_REG_TXQCON_TXQEIE BIT(2)
|
||||
#define MCP251XFD_REG_TXQCON_TXQNIE BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TXQSTA 0x54
|
||||
#define MCP251XFD_REG_TXQSTA_TXQCI_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_TXQSTA_TXABT BIT(7)
|
||||
#define MCP251XFD_REG_TXQSTA_TXLARB BIT(6)
|
||||
#define MCP251XFD_REG_TXQSTA_TXERR BIT(5)
|
||||
#define MCP251XFD_REG_TXQSTA_TXATIF BIT(4)
|
||||
#define MCP251XFD_REG_TXQSTA_TXQEIF BIT(2)
|
||||
#define MCP251XFD_REG_TXQSTA_TXQNIF BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TXQUA 0x58
|
||||
|
||||
#define MCP251XFD_REG_FIFOCON(x) (0x50 + 0xc * (x))
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_MASK GENMASK(31, 29)
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_8 0
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_12 1
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_16 2
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_20 3
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_24 4
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_32 5
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_48 6
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_64 7
|
||||
#define MCP251XFD_REG_FIFOCON_FSIZE_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_MASK GENMASK(22, 21)
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT 0
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_THREE_SHOT 1
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED 3
|
||||
#define MCP251XFD_REG_FIFOCON_TXPRI_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_FIFOCON_FRESET BIT(10)
|
||||
#define MCP251XFD_REG_FIFOCON_TXREQ BIT(9)
|
||||
#define MCP251XFD_REG_FIFOCON_UINC BIT(8)
|
||||
#define MCP251XFD_REG_FIFOCON_TXEN BIT(7)
|
||||
#define MCP251XFD_REG_FIFOCON_RTREN BIT(6)
|
||||
#define MCP251XFD_REG_FIFOCON_RXTSEN BIT(5)
|
||||
#define MCP251XFD_REG_FIFOCON_TXATIE BIT(4)
|
||||
#define MCP251XFD_REG_FIFOCON_RXOVIE BIT(3)
|
||||
#define MCP251XFD_REG_FIFOCON_TFERFFIE BIT(2)
|
||||
#define MCP251XFD_REG_FIFOCON_TFHRFHIE BIT(1)
|
||||
#define MCP251XFD_REG_FIFOCON_TFNRFNIE BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_FIFOSTA(x) (0x54 + 0xc * (x))
|
||||
#define MCP251XFD_REG_FIFOSTA_FIFOCI_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXABT BIT(7)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXLARB BIT(6)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXERR BIT(5)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXATIF BIT(4)
|
||||
#define MCP251XFD_REG_FIFOSTA_RXOVIF BIT(3)
|
||||
#define MCP251XFD_REG_FIFOSTA_TFERFFIF BIT(2)
|
||||
#define MCP251XFD_REG_FIFOSTA_TFHRFHIF BIT(1)
|
||||
#define MCP251XFD_REG_FIFOSTA_TFNRFNIF BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_FIFOUA(x) (0x58 + 0xc * (x))
|
||||
|
||||
#define MCP251XFD_REG_FLTCON(x) (0x1d0 + 0x4 * (x))
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN3 BIT(31)
|
||||
#define MCP251XFD_REG_FLTCON_F3BP_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN2 BIT(23)
|
||||
#define MCP251XFD_REG_FLTCON_F2BP_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN1 BIT(15)
|
||||
#define MCP251XFD_REG_FLTCON_F1BP_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN0 BIT(7)
|
||||
#define MCP251XFD_REG_FLTCON_F0BP_MASK GENMASK(4, 0)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN(x) (BIT(7) << 8 * ((x) & 0x3))
|
||||
#define MCP251XFD_REG_FLTCON_FLT_MASK(x) (GENMASK(7, 0) << (8 * ((x) & 0x3)))
|
||||
#define MCP251XFD_REG_FLTCON_FBP(x, fifo) ((fifo) << 8 * ((x) & 0x3))
|
||||
|
||||
#define MCP251XFD_REG_FLTOBJ(x) (0x1f0 + 0x8 * (x))
|
||||
#define MCP251XFD_REG_FLTOBJ_EXIDE BIT(30)
|
||||
#define MCP251XFD_REG_FLTOBJ_SID11 BIT(29)
|
||||
#define MCP251XFD_REG_FLTOBJ_EID_MASK GENMASK(28, 11)
|
||||
#define MCP251XFD_REG_FLTOBJ_SID_MASK GENMASK(10, 0)
|
||||
|
||||
#define MCP251XFD_REG_FLTMASK(x) (0x1f4 + 0x8 * (x))
|
||||
#define MCP251XFD_REG_MASK_MIDE BIT(30)
|
||||
#define MCP251XFD_REG_MASK_MSID11 BIT(29)
|
||||
#define MCP251XFD_REG_MASK_MEID_MASK GENMASK(28, 11)
|
||||
#define MCP251XFD_REG_MASK_MSID_MASK GENMASK(10, 0)
|
||||
|
||||
/* RAM */
|
||||
#define MCP251XFD_RAM_START 0x400
|
||||
#define MCP251XFD_RAM_SIZE SZ_2K
|
||||
|
||||
/* Message Object */
|
||||
#define MCP251XFD_OBJ_ID_SID11 BIT(29)
|
||||
#define MCP251XFD_OBJ_ID_EID_MASK GENMASK(28, 11)
|
||||
#define MCP251XFD_OBJ_ID_SID_MASK GENMASK(10, 0)
|
||||
#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK GENMASK(31, 9)
|
||||
#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK GENMASK(15, 9)
|
||||
#define MCP251XFD_OBJ_FLAGS_SEQ_MASK MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK
|
||||
#define MCP251XFD_OBJ_FLAGS_ESI BIT(8)
|
||||
#define MCP251XFD_OBJ_FLAGS_FDF BIT(7)
|
||||
#define MCP251XFD_OBJ_FLAGS_BRS BIT(6)
|
||||
#define MCP251XFD_OBJ_FLAGS_RTR BIT(5)
|
||||
#define MCP251XFD_OBJ_FLAGS_IDE BIT(4)
|
||||
#define MCP251XFD_OBJ_FLAGS_DLC GENMASK(3, 0)
|
||||
|
||||
#define MCP251XFD_REG_FRAME_EFF_SID_MASK GENMASK(28, 18)
|
||||
#define MCP251XFD_REG_FRAME_EFF_EID_MASK GENMASK(17, 0)
|
||||
|
||||
/* MCP2517/18FD SFR */
|
||||
#define MCP251XFD_REG_OSC 0xe00
|
||||
#define MCP251XFD_REG_OSC_SCLKRDY BIT(12)
|
||||
#define MCP251XFD_REG_OSC_OSCRDY BIT(10)
|
||||
#define MCP251XFD_REG_OSC_PLLRDY BIT(8)
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_10 3
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_4 2
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_2 1
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_1 0
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_MASK GENMASK(6, 5)
|
||||
#define MCP251XFD_REG_OSC_SCLKDIV BIT(4)
|
||||
#define MCP251XFD_REG_OSC_LPMEN BIT(3) /* MCP2518FD only */
|
||||
#define MCP251XFD_REG_OSC_OSCDIS BIT(2)
|
||||
#define MCP251XFD_REG_OSC_PLLEN BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_IOCON 0xe04
|
||||
#define MCP251XFD_REG_IOCON_INTOD BIT(30)
|
||||
#define MCP251XFD_REG_IOCON_SOF BIT(29)
|
||||
#define MCP251XFD_REG_IOCON_TXCANOD BIT(28)
|
||||
#define MCP251XFD_REG_IOCON_PM1 BIT(25)
|
||||
#define MCP251XFD_REG_IOCON_PM0 BIT(24)
|
||||
#define MCP251XFD_REG_IOCON_GPIO1 BIT(17)
|
||||
#define MCP251XFD_REG_IOCON_GPIO0 BIT(16)
|
||||
#define MCP251XFD_REG_IOCON_LAT1 BIT(9)
|
||||
#define MCP251XFD_REG_IOCON_LAT0 BIT(8)
|
||||
#define MCP251XFD_REG_IOCON_XSTBYEN BIT(6)
|
||||
#define MCP251XFD_REG_IOCON_TRIS1 BIT(1)
|
||||
#define MCP251XFD_REG_IOCON_TRIS0 BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_CRC 0xe08
|
||||
#define MCP251XFD_REG_CRC_FERRIE BIT(25)
|
||||
#define MCP251XFD_REG_CRC_CRCERRIE BIT(24)
|
||||
#define MCP251XFD_REG_CRC_FERRIF BIT(17)
|
||||
#define MCP251XFD_REG_CRC_CRCERRIF BIT(16)
|
||||
#define MCP251XFD_REG_CRC_IF_MASK GENMASK(17, 16)
|
||||
#define MCP251XFD_REG_CRC_MASK GENMASK(15, 0)
|
||||
|
||||
#define MCP251XFD_REG_ECCCON 0xe0c
|
||||
#define MCP251XFD_REG_ECCCON_PARITY_MASK GENMASK(14, 8)
|
||||
#define MCP251XFD_REG_ECCCON_DEDIE BIT(2)
|
||||
#define MCP251XFD_REG_ECCCON_SECIE BIT(1)
|
||||
#define MCP251XFD_REG_ECCCON_ECCEN BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_ECCSTAT 0xe10
|
||||
#define MCP251XFD_REG_ECCSTAT_ERRADDR_MASK GENMASK(27, 16)
|
||||
#define MCP251XFD_REG_ECCSTAT_IF_MASK GENMASK(2, 1)
|
||||
#define MCP251XFD_REG_ECCSTAT_DEDIF BIT(2)
|
||||
#define MCP251XFD_REG_ECCSTAT_SECIF BIT(1)
|
||||
|
||||
#define MCP251XFD_REG_DEVID 0xe14 /* MCP2518FD only */
|
||||
#define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4)
|
||||
#define MCP251XFD_REG_DEVID_REV_MASK GENMASK(3, 0)
|
||||
|
||||
struct mcp251xfd_hw_tef_obj {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u32 ts;
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_tx_obj_can {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u8 data[sizeof_field(struct can_frame, data)];
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_tx_obj_canfd {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u8 data[sizeof_field(struct canfd_frame, data)];
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_rx_obj_can {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u32 ts;
|
||||
u8 data[sizeof_field(struct can_frame, data)];
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_rx_obj_canfd {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u32 ts;
|
||||
u8 data[sizeof_field(struct canfd_frame, data)];
|
||||
};
|
||||
|
||||
#endif
|
||||
+37
-24
@@ -42,37 +42,50 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <termios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - userspace tool for serial line CAN interface driver SLCAN.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] tty\n\n", prg);
|
||||
fprintf(stderr, "Options: -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -d (only detach line discipline)\n");
|
||||
fprintf(stderr, " -w (attach - wait for keypess - detach)\n");
|
||||
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -d (only detach line discipline)\n");
|
||||
fprintf(stderr, " -w (attach - wait for keypess - detach)\n");
|
||||
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
|
||||
fprintf(stderr, "\n"
|
||||
" <speed> Bitrate\n"
|
||||
" 0 10 Kbit/s\n"
|
||||
" 1 20 Kbit/s\n"
|
||||
" 2 50 Kbit/s\n"
|
||||
" 3 100 Kbit/s\n"
|
||||
" 4 125 Kbit/s\n"
|
||||
" 5 250 Kbit/s\n"
|
||||
" 6 500 Kbit/s\n"
|
||||
" 7 800 Kbit/s\n"
|
||||
" 8 1000 Kbit/s\n"
|
||||
"\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "slcan_attach -w -o -f -s6 -c /dev/ttyS1\n");
|
||||
fprintf(stderr, "slcan_attach /dev/ttyS1\n");
|
||||
fprintf(stderr, "slcan_attach -d /dev/ttyS1\n");
|
||||
fprintf(stderr, "slcan_attach -w -n can15 /dev/ttyS1\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "slcan_attach -w -o -f -s6 -c /dev/ttyS1\n\n");
|
||||
fprintf(stderr, "slcan_attach /dev/ttyS1\n\n");
|
||||
fprintf(stderr, "slcan_attach -d /dev/ttyS1\n\n");
|
||||
fprintf(stderr, "slcan_attach -w -n can15 /dev/ttyS1\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -212,7 +225,7 @@ int main(int argc, char **argv)
|
||||
/* try to rename the created device if requested */
|
||||
if (name) {
|
||||
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
|
||||
printf("rename netdevice %s to %s ... ", buf, name);
|
||||
|
||||
if (s < 0)
|
||||
@@ -221,12 +234,12 @@ int main(int argc, char **argv)
|
||||
/* current slcan%d name is still in ifr.ifr_name */
|
||||
memset (ifr.ifr_newname, 0, sizeof(ifr.ifr_newname));
|
||||
strncpy (ifr.ifr_newname, name, sizeof(ifr.ifr_newname) - 1);
|
||||
|
||||
|
||||
if (ioctl(s, SIOCSIFNAME, &ifr) < 0)
|
||||
printf("failed!\n");
|
||||
else
|
||||
printf("ok.\n");
|
||||
|
||||
|
||||
close(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,25 +22,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <net/if.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <termios.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/serial.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Change this to whatever your daemon is called */
|
||||
#define DAEMON_NAME "slcand"
|
||||
@@ -72,22 +72,23 @@ static syslog_t syslogger = syslog;
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - userspace daemon for serial line CAN interface driver SLCAN.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <tty> [canif-name]\n\n", prg);
|
||||
fprintf(stderr, "Options: -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -S <speed> (set UART speed in baud)\n");
|
||||
fprintf(stderr, " -t <type> (set UART flow control type 'hw' or 'sw')\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -F (stay in foreground; no daemonize)\n");
|
||||
fprintf(stderr, " -h (show this help page)\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -o (send open command 'O\\r')\n");
|
||||
fprintf(stderr, " -c (send close command 'C\\r')\n");
|
||||
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
|
||||
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
|
||||
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
|
||||
fprintf(stderr, " -S <speed> (set UART speed in baud)\n");
|
||||
fprintf(stderr, " -t <type> (set UART flow control type 'hw' or 'sw')\n");
|
||||
fprintf(stderr, " -b <btr> (set bit time register value)\n");
|
||||
fprintf(stderr, " -F (stay in foreground; no daemonize)\n");
|
||||
fprintf(stderr, " -h (show this help page)\n");
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0 can0\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 /dev/ttyUSB0\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0\n\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0 can0\n\n");
|
||||
fprintf(stderr, "slcand -o -c -f -s6 /dev/ttyUSB0\n\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
+17
-11
@@ -1,6 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* slcanpty.c - creates a pty for applications using the slcan ASCII protocol
|
||||
* slcanpty: adapter for applications using the slcan ASCII protocol
|
||||
*
|
||||
* slcanpty.c - creates a pty for applications using the slcan ASCII protocol
|
||||
* and converts the ASCII data to a CAN network interface (and vice versa)
|
||||
*
|
||||
* Copyright (c)2009 Oliver Hartkopp
|
||||
@@ -22,16 +24,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -428,16 +432,18 @@ int main(int argc, char **argv)
|
||||
|
||||
/* check command line options */
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s creates a pty for applications using"
|
||||
" the slcan ASCII protocol and\n", argv[0]);
|
||||
fprintf(stderr, "%s: adapter for applications using"
|
||||
" the slcan ASCII protocol.\n", basename(argv[0]));
|
||||
fprintf(stderr, "\n%s creates a pty for applications using"
|
||||
" the slcan ASCII protocol and\n", basename(argv[0]));
|
||||
fprintf(stderr, "converts the ASCII data to a CAN network"
|
||||
" interface (and vice versa)\n\n");
|
||||
fprintf(stderr, "Usage: %s <pty> <can interface>\n", argv[0]);
|
||||
fprintf(stderr, "e.g. '%s /dev/ptyc0 can0' creates"
|
||||
" /dev/ttyc0 for the slcan application\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %s <pty> <can interface>\n", basename(argv[0]));
|
||||
fprintf(stderr, "\nExamples:\n");
|
||||
fprintf(stderr, "%s /dev/ptyc0 can0 - creates /dev/ttyc0 for the slcan application\n\n",
|
||||
basename(argv[0]));
|
||||
fprintf(stderr, "e.g. for pseudo-terminal '%s %s can0' creates"
|
||||
" /dev/pts/N\n", argv[0], DEVICE_NAME_PTMX);
|
||||
" /dev/pts/N\n", basename(argv[0]), DEVICE_NAME_PTMX);
|
||||
fprintf(stderr, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
+71
-68
@@ -10,26 +10,26 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <err.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <getopt.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
static const char help_msg[] =
|
||||
"testj1939: demonstrate j1939 use\n"
|
||||
"Usage: testj1939 FROM TO\n"
|
||||
"Usage: testj1939 [OPTIONS] FROM TO\n"
|
||||
" FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n"
|
||||
"Options:\n"
|
||||
" -v Print relevant API calls\n"
|
||||
@@ -46,7 +46,7 @@ static const char help_msg[] =
|
||||
" -n Emit 64bit NAMEs in output\n"
|
||||
" -w[TIME] Return after TIME (default 1) seconds\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
"Examples:\n"
|
||||
"testj1939 can1 20\n"
|
||||
"\n"
|
||||
;
|
||||
@@ -61,7 +61,7 @@ static void onsigalrm(int sig)
|
||||
|
||||
static void schedule_oneshot_itimer(double delay)
|
||||
{
|
||||
struct itimerval it = {};
|
||||
struct itimerval it = { 0 };
|
||||
|
||||
it.it_value.tv_sec = delay;
|
||||
it.it_value.tv_usec = (long)(delay * 1e6) % 1000000;
|
||||
@@ -72,7 +72,8 @@ static void schedule_oneshot_itimer(double delay)
|
||||
/* main */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret, sock, opt, j;
|
||||
int ret, sock, opt;
|
||||
unsigned int j;
|
||||
int verbose = 0;
|
||||
socklen_t peernamelen;
|
||||
struct sockaddr_can sockname = {
|
||||
@@ -92,62 +93,64 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
uint8_t dat[128];
|
||||
int valid_peername = 0;
|
||||
int todo_send = 0, todo_recv = 0, todo_echo = 0, todo_prio = -1;
|
||||
unsigned int todo_send = 0;
|
||||
int todo_recv = 0, todo_echo = 0, todo_prio = -1;
|
||||
int todo_connect = 0, todo_names = 0, todo_wait = 0, todo_rebind = 0;
|
||||
int todo_broadcast = 0, todo_promisc = 0;
|
||||
int no_bind = 0;
|
||||
|
||||
/* argument parsing */
|
||||
while ((opt = getopt(argc, argv, optstring)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 's':
|
||||
todo_send = strtoul(optarg ?: "8", NULL, 0);
|
||||
if (todo_send > sizeof(dat))
|
||||
err(1, "Unsupported size. max: %zu", sizeof(dat));
|
||||
break;
|
||||
case 'r':
|
||||
todo_recv = 1;
|
||||
break;
|
||||
case 'e':
|
||||
todo_echo = 1;
|
||||
break;
|
||||
case 'p':
|
||||
todo_prio = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'P':
|
||||
todo_promisc = 1;
|
||||
break;
|
||||
case 'c':
|
||||
todo_connect = 1;
|
||||
break;
|
||||
case 'n':
|
||||
todo_names = 1;
|
||||
break;
|
||||
case 'b':
|
||||
todo_rebind = 1;
|
||||
break;
|
||||
case 'B':
|
||||
todo_broadcast = 1;
|
||||
break;
|
||||
case 'o':
|
||||
no_bind = 1;
|
||||
break;
|
||||
case 'w':
|
||||
schedule_oneshot_itimer(strtod(optarg ?: "1", NULL));
|
||||
signal(SIGALRM, onsigalrm);
|
||||
todo_wait = 1;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 's':
|
||||
todo_send = strtoul(optarg ?: "8", NULL, 0);
|
||||
if (todo_send > sizeof(dat))
|
||||
err(1, "Unsupported size. max: %zu",
|
||||
sizeof(dat));
|
||||
break;
|
||||
case 'r':
|
||||
todo_recv = 1;
|
||||
break;
|
||||
case 'e':
|
||||
todo_echo = 1;
|
||||
break;
|
||||
case 'p':
|
||||
todo_prio = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'P':
|
||||
todo_promisc = 1;
|
||||
break;
|
||||
case 'c':
|
||||
todo_connect = 1;
|
||||
break;
|
||||
case 'n':
|
||||
todo_names = 1;
|
||||
break;
|
||||
case 'b':
|
||||
todo_rebind = 1;
|
||||
break;
|
||||
case 'B':
|
||||
todo_broadcast = 1;
|
||||
break;
|
||||
case 'o':
|
||||
no_bind = 1;
|
||||
break;
|
||||
case 'w':
|
||||
schedule_oneshot_itimer(strtod(optarg ?: "1", NULL));
|
||||
signal(SIGALRM, onsigalrm);
|
||||
todo_wait = 1;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind]))
|
||||
if (strcmp("-", argv[optind]) != 0)
|
||||
libj1939_parse_canaddr(argv[optind], &sockname);
|
||||
++optind;
|
||||
}
|
||||
@@ -156,7 +159,7 @@ int main(int argc, char *argv[])
|
||||
sockname.can_addr.j1939.addr++;
|
||||
|
||||
if (argv[optind]) {
|
||||
if (strcmp("-", argv[optind])) {
|
||||
if (strcmp("-", argv[optind]) != 0) {
|
||||
libj1939_parse_canaddr(argv[optind], &peername);
|
||||
valid_peername = 1;
|
||||
}
|
||||
@@ -289,18 +292,18 @@ int main(int argc, char *argv[])
|
||||
err(1, "sendto");
|
||||
}
|
||||
if (todo_recv) {
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
if (todo_names && peername.can_addr.j1939.name)
|
||||
printf("%016llx ", peername.can_addr.j1939.name);
|
||||
printf("%02x %05x:", peername.can_addr.j1939.addr,
|
||||
peername.can_addr.j1939.pgn);
|
||||
for (j = 0; j < ret; ++j, i++) {
|
||||
if (i == 8) {
|
||||
printf("\n%05x ", j);
|
||||
i = 0;
|
||||
for (i = 0, j = 0; i < ret; ++i, j++) {
|
||||
if (j == 8) {
|
||||
printf("\n%05x ", i);
|
||||
j = 0;
|
||||
}
|
||||
printf(" %02x", dat[j]);
|
||||
printf(" %02x", dat[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user