mirror of
https://github.com/linux-can/can-utils.git
synced 2026-09-20 23:12:09 +02:00
Compare commits
194
Commits
v2021.06.0
...
v2023.03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfe41963f3 | ||
|
|
999c650e87 | ||
|
|
2323d506d6 | ||
|
|
cdc617545f | ||
|
|
e409aa4c8c | ||
|
|
3b2248b48e | ||
|
|
fe3717948b | ||
|
|
e898c8a854 | ||
|
|
77ec9b3c2d | ||
|
|
5aa72c5e9e | ||
|
|
f3b35e8e80 | ||
|
|
b4042d0205 | ||
|
|
0847fb34b4 | ||
|
|
ceb9761544 | ||
|
|
088176e4e0 | ||
|
|
aadf98b49b | ||
|
|
92ae2b0e3d | ||
|
|
306254b950 | ||
|
|
34bd45861b | ||
|
|
578f42aac8 | ||
|
|
3c88cfc1ec | ||
|
|
40819fd038 | ||
|
|
12f1d94856 | ||
|
|
7d375df741 | ||
|
|
1969f943a2 | ||
|
|
1322afa6e4 | ||
|
|
f662b32082 | ||
|
|
5b5f1523c4 | ||
|
|
c6f2cf7c2f | ||
|
|
9dff4b6393 | ||
|
|
759524f02c | ||
|
|
f55ea38d14 | ||
|
|
df232c845a | ||
|
|
1ec8eb9ca1 | ||
|
|
96309409c2 | ||
|
|
7e8cfac0de | ||
|
|
0b84a782c2 | ||
|
|
abbd47bd09 | ||
|
|
b6a65b8105 | ||
|
|
99686af630 | ||
|
|
4b6f8d62dd | ||
|
|
8fb0e954b3 | ||
|
|
29b05de39d | ||
|
|
1f96d674c0 | ||
|
|
0f7c1aa23a | ||
|
|
a130ab5e8d | ||
|
|
11a0f19244 | ||
|
|
8d493edbbe | ||
|
|
59c87f149b | ||
|
|
ad638db75d | ||
|
|
1d55d085c9 | ||
|
|
77e785b022 | ||
|
|
144d77180e | ||
|
|
213a814da6 | ||
|
|
a18337b102 | ||
|
|
0b3112edf2 | ||
|
|
74897b69c3 | ||
|
|
9177294093 | ||
|
|
4764212483 | ||
|
|
8e45fc5158 | ||
|
|
0cfd56d613 | ||
|
|
21fb43532e | ||
|
|
f3ce3efe66 | ||
|
|
4c9f046615 | ||
|
|
71a0156bd5 | ||
|
|
e54d677999 | ||
|
|
2b3b5c498f | ||
|
|
8e66a0bae3 | ||
|
|
e602e391a5 | ||
|
|
2b5e93744b | ||
|
|
0d26ba9ea3 | ||
|
|
5736818292 | ||
|
|
3bb412e072 | ||
|
|
f020f563e7 | ||
|
|
e0945d867e | ||
|
|
f81ce85730 | ||
|
|
a44238c9e2 | ||
|
|
7e2010a1c0 | ||
|
|
0654d4e711 | ||
|
|
18eb0ab784 | ||
|
|
b777ce2e6d | ||
|
|
c1f5dc53ec | ||
|
|
ee2f48f33b | ||
|
|
a7062893da | ||
|
|
cfc3030080 | ||
|
|
9c38c16437 | ||
|
|
258f357814 | ||
|
|
ab2b11d9a8 | ||
|
|
710fc99961 | ||
|
|
104e3f97a0 | ||
|
|
2b2d38d06b | ||
|
|
75291c2a88 | ||
|
|
cad1cecf1c | ||
|
|
da0326ffc6 | ||
|
|
cfe13a4c7d | ||
|
|
b8af5a6031 | ||
|
|
5e06623b3d | ||
|
|
6d3bf51e0a | ||
|
|
2b0ed067dd | ||
|
|
ef853f5553 | ||
|
|
eb2b38790a | ||
|
|
bace2e7d73 | ||
|
|
d3bb67136f | ||
|
|
34732eddeb | ||
|
|
2b0ef5c330 | ||
|
|
6e7f845a68 | ||
|
|
d320a4a871 | ||
|
|
81e76a7a0d | ||
|
|
2bdb93924e | ||
|
|
afc6a324da | ||
|
|
901c9e519d | ||
|
|
26842295b8 | ||
|
|
24de626f33 | ||
|
|
c70d0a8e61 | ||
|
|
aa3f029925 | ||
|
|
dfb607c807 | ||
|
|
84d3294132 | ||
|
|
5e0895981b | ||
|
|
ad250a68dc | ||
|
|
ec6a573de1 | ||
|
|
acec220189 | ||
|
|
b38d2639ba | ||
|
|
0ccc3fed91 | ||
|
|
9f9f2ff721 | ||
|
|
00fbc5d536 | ||
|
|
2758f8eb62 | ||
|
|
2ac24b86fd | ||
|
|
a4d2ee75bc | ||
|
|
4984eb702e | ||
|
|
4bd649d73a | ||
|
|
25de6276e8 | ||
|
|
7af4264a13 | ||
|
|
3342eb42e7 | ||
|
|
c142ca63c9 | ||
|
|
4858b2b307 | ||
|
|
8ffcc187e9 | ||
|
|
c3129b678a | ||
|
|
540dcaa821 | ||
|
|
fb186ed6c8 | ||
|
|
66631a3e23 | ||
|
|
e7b5920b10 | ||
|
|
2636640aa7 | ||
|
|
f42e968bcf | ||
|
|
f9c9f6841b | ||
|
|
8d01589500 | ||
|
|
046d9f88ee | ||
|
|
36d76ba07a | ||
|
|
04123b3b36 | ||
|
|
2829512f9b | ||
|
|
7ec433f6a6 | ||
|
|
7bc81678bb | ||
|
|
927f70e588 | ||
|
|
9b63929974 | ||
|
|
258ea5a9ba | ||
|
|
4c07a11f81 | ||
|
|
3394e1fa18 | ||
|
|
9e5b6266b1 | ||
|
|
e370ad5256 | ||
|
|
fd1d61490c | ||
|
|
da642181a9 | ||
|
|
6bd7ced052 | ||
|
|
9ca68a12c7 | ||
|
|
eb9cfac954 | ||
|
|
7dd714907b | ||
|
|
a705182b28 | ||
|
|
0d84033fa4 | ||
|
|
ab9bd4f287 | ||
|
|
2dde06801a | ||
|
|
607b643e0f | ||
|
|
eb0eb78896 | ||
|
|
0edab8a402 | ||
|
|
622fcbb9b3 | ||
|
|
02e8b1ff39 | ||
|
|
9fd2b2e617 | ||
|
|
8bf57429fc | ||
|
|
93a6cd6dfb | ||
|
|
d9368a6003 | ||
|
|
c36bdc743f | ||
|
|
f7307b8290 | ||
|
|
5a3d1703d2 | ||
|
|
57cc73d413 | ||
|
|
4236614ab6 | ||
|
|
e03f3e1049 | ||
|
|
7b8457ce9f | ||
|
|
9f269db070 | ||
|
|
cc155d2f63 | ||
|
|
0107f07d83 | ||
|
|
3615bac17e | ||
|
|
6382765bf6 | ||
|
|
c1aae77740 | ||
|
|
37f316ebc3 | ||
|
|
e319afb10f | ||
|
|
e9a298ec21 | ||
|
|
e19b5abb5c |
@@ -0,0 +1,70 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '29 21 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -20,6 +20,7 @@ GNUmakefile.in
|
||||
/config/m4/ltsugar.m4
|
||||
/config/m4/ltversion.m4
|
||||
/config/m4/lt~obsolete.m4
|
||||
/calc-bit-timing/.dirstamp
|
||||
/mcp251xfd/.dirstamp
|
||||
|
||||
/asc2log
|
||||
|
||||
+1
-1
@@ -181,7 +181,7 @@ include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := can-calc-bit-timing.c
|
||||
LOCAL_SRC_FILES := calc-bit-timing/can-calc-bit-timing.c
|
||||
LOCAL_MODULE := can-calc-bit-timing
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
|
||||
|
||||
+9
-6
@@ -9,10 +9,7 @@ if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
|
||||
if(_GNU_SOURCE)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
endif()
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
|
||||
@@ -21,6 +18,9 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAF_CAN=PF_CAN")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DN_SLCAN=17")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TIMESTAMPING_OPT_STATS=54")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCLOCK_TAI=11")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_TXTIME=61")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSCM_TXTIME=SO_TXTIME")
|
||||
|
||||
include_directories (.)
|
||||
include_directories (./include)
|
||||
@@ -36,6 +36,7 @@ set(PROGRAMS_CANLIB
|
||||
cansequence
|
||||
log2asc
|
||||
log2long
|
||||
slcanpty
|
||||
)
|
||||
|
||||
set(PROGRAMS_J1939
|
||||
@@ -49,7 +50,6 @@ set(PROGRAMS_J1939
|
||||
set(PROGRAMS
|
||||
${PROGRAMS_CANLIB}
|
||||
bcmserver
|
||||
can-calc-bit-timing
|
||||
canfdtest
|
||||
cangw
|
||||
cansniffer
|
||||
@@ -62,7 +62,10 @@ set(PROGRAMS
|
||||
isotptun
|
||||
slcan_attach
|
||||
slcand
|
||||
slcanpty
|
||||
)
|
||||
|
||||
add_executable(can-calc-bit-timing
|
||||
calc-bit-timing/can-calc-bit-timing.c
|
||||
)
|
||||
|
||||
add_executable(mcp251xfd-dump
|
||||
|
||||
+27
-3
@@ -5,6 +5,8 @@ AM_CPPFLAGS = \
|
||||
-I$(top_builddir)/include \
|
||||
$(linux_CFLAGS)
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
# link every app against libcan, it's static so it wouldn't hurt
|
||||
LDADD = \
|
||||
libcan.la
|
||||
@@ -39,6 +41,16 @@ libcan_la_SOURCES = \
|
||||
libj1939_la_SOURCES = \
|
||||
libj1939.c
|
||||
|
||||
can_calc_bit_timing_SOURCES = \
|
||||
calc-bit-timing/can-calc-bit-timing.c
|
||||
|
||||
EXTRA_DIST += \
|
||||
calc-bit-timing/can-calc-bit-timing-v2_6_31.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v3_18.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v4_8.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v5_16.c \
|
||||
calc-bit-timing/can-calc-bit-timing-v5_19.c
|
||||
|
||||
mcp251xfd_dump_SOURCES = \
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c \
|
||||
mcp251xfd/mcp251xfd-dump-userspace.h \
|
||||
@@ -48,6 +60,19 @@ mcp251xfd_dump_SOURCES = \
|
||||
mcp251xfd/mcp251xfd-regmap.c \
|
||||
mcp251xfd/mcp251xfd.h
|
||||
|
||||
EXTRA_DIST += \
|
||||
mcp251xfd/99-devcoredump.rules \
|
||||
mcp251xfd/data/devcoredump-canfd-v5.15.dump \
|
||||
mcp251xfd/data/devcoredump-canfd.dump \
|
||||
mcp251xfd/data/devcoredump-classic-can-v5.15.dump \
|
||||
mcp251xfd/data/devcoredump-classic-can.dump \
|
||||
mcp251xfd/data/registers-canfd-v5.15.dump \
|
||||
mcp251xfd/data/registers-canfd.dump \
|
||||
mcp251xfd/data/registers-classic-can-v5.15.dump \
|
||||
mcp251xfd/data/registers-classic-can.dump \
|
||||
mcp251xfd/devcoredump \
|
||||
mcp251xfd/mcp251xfd-gen-testdata.sh
|
||||
|
||||
bin_PROGRAMS = \
|
||||
asc2log \
|
||||
bcmserver \
|
||||
@@ -87,15 +112,14 @@ j1939spy_LDADD = libj1939.la
|
||||
j1939sr_LDADD = libj1939.la
|
||||
testj1939_LDADD = libj1939.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
EXTRA_DIST += \
|
||||
.travis.yml \
|
||||
Android.mk \
|
||||
README.md \
|
||||
autogen.sh \
|
||||
can-j1939-kickstart.md \
|
||||
can-j1939.md \
|
||||
mcp251xfd/99-devcoredump.rules \
|
||||
mcp251xfd/devcoredump
|
||||
can-tc-init-etf.sh
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
configure \
|
||||
|
||||
@@ -46,11 +46,15 @@ MAKEFLAGS := -k
|
||||
CFLAGS := -O2 -Wall -Wno-parentheses
|
||||
|
||||
CPPFLAGS += \
|
||||
-I. \
|
||||
-Iinclude \
|
||||
-DAF_CAN=PF_CAN \
|
||||
-DPF_CAN=29 \
|
||||
-DSO_RXQ_OVFL=40 \
|
||||
-DSCM_TIMESTAMPING_OPT_STATS=54 \
|
||||
-DCLOCK_TAI=11 \
|
||||
-DSO_TXTIME=61 \
|
||||
-DSCM_TXTIME=SO_TXTIME \
|
||||
-D_FILE_OFFSET_BITS=64 \
|
||||
-D_GNU_SOURCE
|
||||
|
||||
@@ -102,25 +106,24 @@ PROGRAMS := \
|
||||
all: $(PROGRAMS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGRAMS) *.o
|
||||
rm -f $(PROGRAMS) *.o mcp251xfd/*.o
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f $(PROGRAMS) $(DESTDIR)$(PREFIX)/bin
|
||||
|
||||
distclean:
|
||||
rm -f $(PROGRAMS) $(LIBRARIES) *.o *~
|
||||
distclean: clean
|
||||
rm -f $(PROGRAMS) $(LIBRARIES) *~
|
||||
|
||||
asc2log.o: lib.h
|
||||
canbusload.o: lib.h
|
||||
candump.o: lib.h
|
||||
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
|
||||
slcanpty.o: lib.h
|
||||
j1939acd.o: libj1939.h
|
||||
j1939cat.o: libj1939.h
|
||||
j1939spy.o: libj1939.h
|
||||
@@ -137,6 +140,7 @@ cansend: cansend.o lib.o
|
||||
cansequence: cansequence.o lib.o
|
||||
log2asc: log2asc.o lib.o
|
||||
log2long: log2long.o lib.o
|
||||
slcanpty: slcanpty.o lib.o
|
||||
j1939acd: j1939acd.o libj1939.o
|
||||
j1939cat: j1939cat.o libj1939.o
|
||||
j1939spy: j1939spy.o libj1939.o
|
||||
@@ -144,5 +148,8 @@ 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
|
||||
can-calc-bit-timing: calc-bit-timing/can-calc-bit-timing.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
mcp251xfd-dump: mcp251xfd/mcp251xfd-dev-coredump.o mcp251xfd/mcp251xfd-dump.o mcp251xfd/mcp251xfd-main.o mcp251xfd/mcp251xfd-regmap.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/error.h>
|
||||
@@ -131,74 +132,15 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i
|
||||
static struct timeval tv; /* current frame timestamp */
|
||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
||||
struct canfd_frame cf;
|
||||
struct can_frame *ccf = (struct can_frame *)&cf; /* for len8_dlc */
|
||||
char rtr;
|
||||
int dlc = 0;
|
||||
int len = 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;
|
||||
}
|
||||
int i, items;
|
||||
|
||||
/* check for ErrorFrames */
|
||||
if (sscanf(buf, "%lu.%lu %d %s",
|
||||
@@ -215,8 +157,79 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i
|
||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
||||
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, "\n");
|
||||
fflush(outfile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
|
||||
|
||||
/* check for CAN frames with (hexa)decimal values */
|
||||
if (base == 'h')
|
||||
items = sscanf(buf, "%lu.%lu %d %s %2s %c %x %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]);
|
||||
else
|
||||
items = sscanf(buf, "%lu.%lu %d %s %2s %c %x %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 < 7 ) /* make sure we've read the dlc */
|
||||
return;
|
||||
|
||||
/* dlc is one character hex value 0..F */
|
||||
if (dlc > CAN_MAX_RAW_DLC)
|
||||
return;
|
||||
|
||||
/* retrieve real data length */
|
||||
if (dlc > CAN_MAX_DLC)
|
||||
len = CAN_MAX_DLEN;
|
||||
else
|
||||
len = dlc;
|
||||
|
||||
if ((items == len + 7 ) || /* data frame */
|
||||
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
|
||||
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
|
||||
|
||||
/* check for CAN ID with (hexa)decimal value */
|
||||
if (base == 'h')
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
else
|
||||
get_can_id(&cf, tmp1, 10);
|
||||
|
||||
/* dlc > 8 => len == CAN_MAX_DLEN => fill len8_dlc value */
|
||||
if (dlc > CAN_MAX_DLC)
|
||||
ccf->len8_dlc = dlc;
|
||||
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
extra_info = " T\n";
|
||||
|
||||
cf.len = len;
|
||||
if (rtr == 'r')
|
||||
cf.can_id |= CAN_RTR_FLAG;
|
||||
else
|
||||
for (i = 0; i < len; 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);
|
||||
}
|
||||
}
|
||||
|
||||
void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace, FILE *outfile) {
|
||||
@@ -264,6 +277,14 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace
|
||||
if (strlen(dir) != 2) /* "Rx" or "Tx" */
|
||||
return;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
|
||||
return;
|
||||
|
||||
/* check for signed integer overflow */
|
||||
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
|
||||
return;
|
||||
|
||||
if (dir[0] == 'R')
|
||||
extra_info = " R\n";
|
||||
else
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* imported from v2.6.31-rc1~330^2~376
|
||||
*
|
||||
* 39549eef3587 can: CAN Network device driver and Netlink interface
|
||||
*
|
||||
* cherry-picked for easier integration:
|
||||
* 61463a30f652 can: make function can_get_bittiming static
|
||||
* aabdfd6adb80 can: replace the dev_dbg/info/err/... with the new netdev_xxx macros
|
||||
* 08da7da41ea4 can: provide a separate bittiming_const parameter to bittiming functions
|
||||
* b25a437206ed can: dev: remove unused variable from can_calc_bittiming() function
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_update_spt(const struct can_bittiming_const *btc,
|
||||
int sampl_pt, int tseg, int *tseg1, int *tseg2)
|
||||
{
|
||||
*tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
|
||||
if (*tseg2 < btc->tseg2_min)
|
||||
*tseg2 = btc->tseg2_min;
|
||||
if (*tseg2 > btc->tseg2_max)
|
||||
*tseg2 = btc->tseg2_max;
|
||||
*tseg1 = tseg - *tseg2;
|
||||
if (*tseg1 > btc->tseg1_max) {
|
||||
*tseg1 = btc->tseg1_max;
|
||||
*tseg2 = tseg - *tseg1;
|
||||
}
|
||||
return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
|
||||
}
|
||||
|
||||
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
long best_error = 1000000000, error = 0;
|
||||
int best_tseg = 0, best_brp = 0, brp = 0;
|
||||
int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
|
||||
int spt_error = 1000, spt = 0, sampl_pt;
|
||||
long rate;
|
||||
u64 v64;
|
||||
|
||||
/* Use CIA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sampl_pt = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800000)
|
||||
sampl_pt = 750;
|
||||
else if (bt->bitrate > 500000)
|
||||
sampl_pt = 800;
|
||||
else
|
||||
sampl_pt = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = 1 + tseg / 2;
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
/* chose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if ((brp < btc->brp_min) || (brp > btc->brp_max))
|
||||
continue;
|
||||
rate = priv->clock.freq / (brp * tsegall);
|
||||
error = bt->bitrate - rate;
|
||||
/* tseg brp biterror */
|
||||
if (error < 0)
|
||||
error = -error;
|
||||
if (error > best_error)
|
||||
continue;
|
||||
best_error = error;
|
||||
if (error == 0) {
|
||||
spt = can_update_spt(btc, sampl_pt, tseg / 2,
|
||||
&tseg1, &tseg2);
|
||||
error = sampl_pt - spt;
|
||||
if (error < 0)
|
||||
error = -error;
|
||||
if (error > spt_error)
|
||||
continue;
|
||||
spt_error = error;
|
||||
}
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
if (error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
error = (best_error * 1000) / bt->bitrate;
|
||||
if (error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %ld.%ld%% too high\n",
|
||||
error / 10, error % 10);
|
||||
return -EDOM;
|
||||
} else {
|
||||
netdev_warn(dev, "bitrate error %ld.%ld%%\n",
|
||||
error / 10, error % 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg,
|
||||
&tseg1, &tseg2);
|
||||
|
||||
v64 = (u64)best_brp * 1000000000UL;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
bt->sjw = 1;
|
||||
bt->brp = best_brp;
|
||||
/* real bit-rate */
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* imported from v3.18-rc1~52^2~248^2~1
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_update_spt(const struct can_bittiming_const *btc,
|
||||
int sampl_pt, int tseg, int *tseg1, int *tseg2)
|
||||
{
|
||||
*tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
|
||||
if (*tseg2 < btc->tseg2_min)
|
||||
*tseg2 = btc->tseg2_min;
|
||||
if (*tseg2 > btc->tseg2_max)
|
||||
*tseg2 = btc->tseg2_max;
|
||||
*tseg1 = tseg - *tseg2;
|
||||
if (*tseg1 > btc->tseg1_max) {
|
||||
*tseg1 = btc->tseg1_max;
|
||||
*tseg2 = tseg - *tseg1;
|
||||
}
|
||||
return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
|
||||
}
|
||||
|
||||
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
long best_error = 1000000000, error = 0;
|
||||
int best_tseg = 0, best_brp = 0, brp = 0;
|
||||
int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
|
||||
int spt_error = 1000, spt = 0, sampl_pt;
|
||||
long rate;
|
||||
u64 v64;
|
||||
|
||||
/* Use CIA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sampl_pt = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800000)
|
||||
sampl_pt = 750;
|
||||
else if (bt->bitrate > 500000)
|
||||
sampl_pt = 800;
|
||||
else
|
||||
sampl_pt = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = 1 + tseg / 2;
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
/* chose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if ((brp < btc->brp_min) || (brp > btc->brp_max))
|
||||
continue;
|
||||
rate = priv->clock.freq / (brp * tsegall);
|
||||
error = bt->bitrate - rate;
|
||||
/* tseg brp biterror */
|
||||
if (error < 0)
|
||||
error = -error;
|
||||
if (error > best_error)
|
||||
continue;
|
||||
best_error = error;
|
||||
if (error == 0) {
|
||||
spt = can_update_spt(btc, sampl_pt, tseg / 2,
|
||||
&tseg1, &tseg2);
|
||||
error = sampl_pt - spt;
|
||||
if (error < 0)
|
||||
error = -error;
|
||||
if (error > spt_error)
|
||||
continue;
|
||||
spt_error = error;
|
||||
}
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
if (error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
error = (best_error * 1000) / bt->bitrate;
|
||||
if (error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %ld.%ld%% too high\n",
|
||||
error / 10, error % 10);
|
||||
return -EDOM;
|
||||
} else {
|
||||
netdev_warn(dev, "bitrate error %ld.%ld%%\n",
|
||||
error / 10, error % 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg,
|
||||
&tseg1, &tseg2);
|
||||
|
||||
v64 = (u64)best_brp * 1000000000UL;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max)
|
||||
bt->sjw = 1;
|
||||
else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
/* real bit-rate */
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* imported from v4.8-rc1~140^2~304^2~11
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
unsigned int sample_point_nominal, unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_CALC_SYNC_SEG - (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if ((sample_point <= sample_point_nominal) && (sample_point_error < best_sample_point_error)) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_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 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800000)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500000)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if ((brp < btc->brp_min) || (brp > btc->brp_max))
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error > best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal, best_tseg,
|
||||
&tseg1, &tseg2, NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* imported from v5.16-rc1~159^2~104^2~13
|
||||
*
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
/* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int
|
||||
can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
unsigned int sample_point_nominal, unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_SYNC_SEG -
|
||||
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
||||
1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
||||
(tseg + CAN_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if (sample_point <= sample_point_nominal &&
|
||||
sample_point_error < best_sample_point_error) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_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 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800 * CAN_KBPS)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500 * CAN_KBPS)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if (brp < btc->brp_min || brp > btc->brp_max)
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error > best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
||||
best_tseg, &tseg1, &tseg2,
|
||||
NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
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);
|
||||
unsigned int tseg1, alltseg;
|
||||
u64 brp64;
|
||||
|
||||
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;
|
||||
|
||||
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 = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* imported from v5.19-rc1~159^2~286^2~15
|
||||
*
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
/* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int
|
||||
can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
const unsigned int sample_point_nominal, const unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_SYNC_SEG -
|
||||
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
||||
1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
||||
(tseg + CAN_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if (sample_point <= sample_point_nominal &&
|
||||
sample_point_error < best_sample_point_error) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_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 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800 * KILO /* BPS */)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500 * KILO /* BPS */)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if (brp < btc->brp_min || brp > btc->brp_max)
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error >= best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
||||
best_tseg, &tseg1, &tseg2,
|
||||
NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_fixup_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
const struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int tseg1, alltseg;
|
||||
u64 brp64;
|
||||
|
||||
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;
|
||||
|
||||
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 = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,909 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
|
||||
*
|
||||
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
|
||||
* Copyright (C) 2016, 2021 Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
*
|
||||
* Derived from:
|
||||
* can_baud.c - CAN baudrate calculation
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email:pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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 */
|
||||
|
||||
/**
|
||||
* abs - return absolute value of an argument
|
||||
* @x: the value. If it is unsigned type, it is converted to signed type first.
|
||||
* char is treated as if it was signed (regardless of whether it really is)
|
||||
* but the macro's return type is preserved as char.
|
||||
*
|
||||
* Return: an absolute value of x.
|
||||
*/
|
||||
#define abs(x) __abs_choose_expr(x, long long, \
|
||||
__abs_choose_expr(x, long, \
|
||||
__abs_choose_expr(x, int, \
|
||||
__abs_choose_expr(x, short, \
|
||||
__abs_choose_expr(x, char, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(x), char), \
|
||||
(char)({ signed char __x = (x); __x<0?-__x:__x; }), \
|
||||
((void)0)))))))
|
||||
|
||||
#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(x), signed type) || \
|
||||
__builtin_types_compatible_p(typeof(x), unsigned type), \
|
||||
({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
|
||||
|
||||
/*
|
||||
* min()/max()/clamp() macros that also do
|
||||
* strict type-checking.. See the
|
||||
* "unnecessary" pointer comparison.
|
||||
*/
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
#define max(x, y) ({ \
|
||||
typeof(x) _max1 = (x); \
|
||||
typeof(y) _max2 = (y); \
|
||||
(void) (&_max1 == &_max2); \
|
||||
_max1 > _max2 ? _max1 : _max2; })
|
||||
|
||||
/**
|
||||
* clamp - return a value clamped to a given range with strict typechecking
|
||||
* @val: current value
|
||||
* @lo: lowest allowable value
|
||||
* @hi: highest allowable value
|
||||
*
|
||||
* This macro does strict typechecking of lo/hi to make sure they are of the
|
||||
* same type as val. See the unnecessary pointer comparisons.
|
||||
*/
|
||||
#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
|
||||
|
||||
# define do_div(n,base) ({ \
|
||||
uint32_t __base = (base); \
|
||||
uint32_t __rem; \
|
||||
__rem = ((uint64_t)(n)) % __base; \
|
||||
(n) = ((uint64_t)(n)) / __base; \
|
||||
__rem; \
|
||||
})
|
||||
|
||||
/* */
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
/* we don't want to see these prints */
|
||||
#define netdev_err(dev, format, arg...) do { } while (0)
|
||||
#define netdev_warn(dev, format, arg...) do { } while (0)
|
||||
|
||||
/* define in-kernel-types */
|
||||
typedef __u64 u64;
|
||||
typedef __u32 u32;
|
||||
|
||||
struct calc_ref_clk {
|
||||
__u32 clk; /* CAN system clock frequency in Hz */
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct calc_bittiming_const {
|
||||
struct can_bittiming_const bittiming_const;
|
||||
|
||||
const struct calc_ref_clk ref_clk[16];
|
||||
void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
||||
};
|
||||
|
||||
/*
|
||||
* minimal structs, just enough to be source level compatible
|
||||
*/
|
||||
struct can_priv {
|
||||
struct can_clock clock;
|
||||
};
|
||||
|
||||
struct net_device {
|
||||
struct can_priv priv;
|
||||
};
|
||||
|
||||
static inline void *netdev_priv(const struct net_device *dev)
|
||||
{
|
||||
return (void *)&dev->priv;
|
||||
}
|
||||
|
||||
static void print_usage(char *cmd)
|
||||
{
|
||||
printf("%s - calculate CAN bit timing parameters.\n", cmd);
|
||||
printf("Usage: %s [options] [<CAN-contoller-name>]\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"
|
||||
"\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);
|
||||
}
|
||||
|
||||
static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
uint8_t btr0, btr1;
|
||||
|
||||
if (hdr) {
|
||||
printf("BTR0 BTR1");
|
||||
} else {
|
||||
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
|
||||
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
|
||||
(((bt->phase_seg2 - 1) & 0x7) << 4);
|
||||
printf("0x%02x 0x%02x", btr0, btr1);
|
||||
}
|
||||
}
|
||||
|
||||
static void printf_btr_at91(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
if (hdr) {
|
||||
printf("%10s", "CAN_BR");
|
||||
} else {
|
||||
uint32_t br = ((bt->phase_seg2 - 1) |
|
||||
((bt->phase_seg1 - 1) << 4) |
|
||||
((bt->prop_seg - 1) << 8) |
|
||||
((bt->sjw - 1) << 12) |
|
||||
((bt->brp - 1) << 16));
|
||||
printf("0x%08x", br);
|
||||
}
|
||||
}
|
||||
|
||||
static void printf_btr_flexcan(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
if (hdr) {
|
||||
printf("%10s", "CAN_CTRL");
|
||||
} else {
|
||||
uint32_t ctrl = (((bt->brp - 1) << 24) |
|
||||
((bt->sjw - 1) << 22) |
|
||||
((bt->phase_seg1 - 1) << 19) |
|
||||
((bt->phase_seg2 - 1) << 16) |
|
||||
((bt->prop_seg - 1) << 0));
|
||||
|
||||
printf("0x%08x", ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
static void printf_btr_mcp251x(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
uint8_t cnf1, cnf2, cnf3;
|
||||
|
||||
if (hdr) {
|
||||
printf("CNF1 CNF2 CNF3");
|
||||
} else {
|
||||
cnf1 = ((bt->sjw - 1) << 6) | (bt->brp - 1);
|
||||
cnf2 = 0x80 | ((bt->phase_seg1 - 1) << 3) | (bt->prop_seg - 1);
|
||||
cnf3 = bt->phase_seg2 - 1;
|
||||
printf("0x%02x 0x%02x 0x%02x", cnf1, cnf2, cnf3);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
printf("%10s", "CANBTC");
|
||||
} else {
|
||||
uint32_t can_btc;
|
||||
|
||||
can_btc = (bt->phase_seg2 - 1) & 0x7;
|
||||
can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1)
|
||||
& 0xF) << 3;
|
||||
can_btc |= ((bt->sjw - 1) & 0x3) << 8;
|
||||
can_btc |= ((bt->brp - 1) & 0xFF) << 16;
|
||||
|
||||
printf("0x%08x", can_btc);
|
||||
}
|
||||
}
|
||||
|
||||
#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20)
|
||||
#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8)
|
||||
#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4)
|
||||
#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07)
|
||||
|
||||
static void printf_btr_rcar_can(struct can_bittiming *bt, bool hdr)
|
||||
{
|
||||
if (hdr) {
|
||||
printf("%10s", "CiBCR");
|
||||
} else {
|
||||
uint32_t bcr;
|
||||
|
||||
bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
|
||||
RCAR_CAN_BCR_BPR(bt->brp - 1) |
|
||||
RCAR_CAN_BCR_SJW(bt->sjw - 1) |
|
||||
RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1);
|
||||
|
||||
printf("0x%08x", bcr << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static struct calc_bittiming_const can_calc_consts[] = {
|
||||
{
|
||||
.bittiming_const = {
|
||||
.name = "sja1000",
|
||||
.tseg1_min = 1,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 1,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 64,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 8000000, },
|
||||
},
|
||||
.printf_btr = printf_btr_sja1000,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "mscan",
|
||||
.tseg1_min = 4,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 64,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 32000000, },
|
||||
{ .clk = 33000000, },
|
||||
{ .clk = 33300000, },
|
||||
{ .clk = 33333333, },
|
||||
{ .clk = 66660000, .name = "mpc5121", },
|
||||
{ .clk = 66666666, .name = "mpc5121" },
|
||||
},
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "at91",
|
||||
.tseg1_min = 4,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 2,
|
||||
.brp_max = 128,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 99532800, .name = "ronetix PM9263", },
|
||||
{ .clk = 100000000, },
|
||||
},
|
||||
.printf_btr = printf_btr_at91,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "flexcan",
|
||||
.tseg1_min = 4,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 256,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 24000000, .name = "mx28" },
|
||||
{ .clk = 30000000, .name = "mx6" },
|
||||
{ .clk = 49875000, },
|
||||
{ .clk = 66000000, },
|
||||
{ .clk = 66500000, },
|
||||
{ .clk = 66666666, },
|
||||
{ .clk = 83368421, .name = "vybrid" },
|
||||
},
|
||||
.printf_btr = printf_btr_flexcan,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "mcp251x",
|
||||
.tseg1_min = 3,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 64,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
/* 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",
|
||||
.tseg1_min = 1,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 1,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 256,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 13000000, },
|
||||
},
|
||||
.printf_btr = printf_btr_ti_hecc,
|
||||
}, {
|
||||
.bittiming_const = {
|
||||
.name = "rcar_can",
|
||||
.tseg1_min = 4,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 1024,
|
||||
.brp_inc = 1,
|
||||
},
|
||||
.ref_clk = {
|
||||
{ .clk = 65000000, },
|
||||
},
|
||||
.printf_btr = printf_btr_rcar_can,
|
||||
},
|
||||
};
|
||||
|
||||
static long common_bitrates[] = {
|
||||
1000000,
|
||||
800000,
|
||||
500000,
|
||||
250000,
|
||||
125000,
|
||||
100000,
|
||||
50000,
|
||||
20000,
|
||||
10000,
|
||||
};
|
||||
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
#define CAN_CALC_SYNC_SEG 1
|
||||
|
||||
/*
|
||||
* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_update_spt(const struct can_bittiming_const *btc,
|
||||
unsigned int spt_nominal, unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *spt_error_ptr)
|
||||
{
|
||||
unsigned int spt_error, best_spt_error = UINT_MAX;
|
||||
unsigned int spt, best_spt = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_CALC_SYNC_SEG - (spt_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
spt = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG);
|
||||
spt_error = abs(spt_nominal - spt);
|
||||
|
||||
if ((spt <= spt_nominal) && (spt_error < best_spt_error)) {
|
||||
best_spt = spt;
|
||||
best_spt_error = spt_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (spt_error_ptr)
|
||||
*spt_error_ptr = best_spt_error;
|
||||
|
||||
return best_spt;
|
||||
}
|
||||
|
||||
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int rate; /* current bitrate */
|
||||
unsigned int rate_error; /* difference between current and nominal value */
|
||||
unsigned int best_rate_error = UINT_MAX;
|
||||
unsigned int spt_error; /* difference between current and nominal value */
|
||||
unsigned int best_spt_error = UINT_MAX;
|
||||
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 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
spt_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800000)
|
||||
spt_nominal = 750;
|
||||
else if (bt->bitrate > 500000)
|
||||
spt_nominal = 800;
|
||||
else
|
||||
spt_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if ((brp < btc->brp_min) || (brp > btc->brp_max))
|
||||
continue;
|
||||
|
||||
rate = priv->clock.freq / (brp * tsegall);
|
||||
rate_error = abs(bt->bitrate - rate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (rate_error > best_rate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (rate_error < best_rate_error)
|
||||
best_spt_error = UINT_MAX;
|
||||
|
||||
can_update_spt(btc, spt_nominal, tseg / 2, &tseg1, &tseg2, &spt_error);
|
||||
if (spt_error > best_spt_error)
|
||||
continue;
|
||||
|
||||
best_spt_error = spt_error;
|
||||
best_rate_error = rate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (rate_error == 0 && spt_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_rate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
rate_error = (best_rate_error * 1000) / bt->bitrate;
|
||||
if (rate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %ld.%ld%% too high\n",
|
||||
rate_error / 10, rate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %ld.%ld%%\n",
|
||||
rate_error / 10, rate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_spt(btc, spt_nominal, best_tseg,
|
||||
&tseg1, &tseg2, NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bit-rate */
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
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;
|
||||
|
||||
if (bitrate > 800000)
|
||||
sampl_pt = 750;
|
||||
else if (bitrate > 500000)
|
||||
sampl_pt = 800;
|
||||
else
|
||||
sampl_pt = 875;
|
||||
|
||||
return sampl_pt;
|
||||
}
|
||||
|
||||
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,
|
||||
bool quiet)
|
||||
{
|
||||
struct net_device dev = {
|
||||
.priv.clock.freq = ref_clk->clk,
|
||||
};
|
||||
struct can_bittiming bt = {
|
||||
.bitrate = bitrate_nominal,
|
||||
.sample_point = spt_nominal,
|
||||
};
|
||||
long rate_error, spt_error;
|
||||
|
||||
if (!quiet) {
|
||||
printf("Bit timing parameters for %s%s%s%s with %.6f MHz ref clock\n"
|
||||
"nominal real Bitrt nom real SampP\n"
|
||||
"Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ",
|
||||
btc->bittiming_const.name,
|
||||
ref_clk->name ? " (" : "",
|
||||
ref_clk->name ? ref_clk->name : "",
|
||||
ref_clk->name ? ")" : "",
|
||||
ref_clk->clk / 1000000.0);
|
||||
|
||||
if (btc->printf_btr)
|
||||
btc->printf_btr(&bt, true);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
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 */
|
||||
if (!spt_nominal)
|
||||
spt_nominal = get_cia_sample_point(bitrate_nominal);
|
||||
|
||||
rate_error = abs(bitrate_nominal - bt.bitrate);
|
||||
spt_error = abs(spt_nominal - bt.sample_point);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
static void do_list(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++)
|
||||
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",
|
||||
};
|
||||
struct can_bittiming bt = { 0 };
|
||||
bool quiet = false, list = false;
|
||||
const char *name = NULL;
|
||||
int opt;
|
||||
|
||||
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_long(argc, argv, "b:c:lqs:?", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bitrate_nominal = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
opt_ref_clk.clk = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
list = true;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
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(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind + 1) {
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == optind + 1)
|
||||
name = argv[optind];
|
||||
|
||||
if (list) {
|
||||
do_list();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100)) {
|
||||
print_usage(argv[0]);
|
||||
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);
|
||||
}
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (C) 2022 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
#
|
||||
# This script requires a kernel compiled with the following options:
|
||||
#
|
||||
# CONFIG_NET_SCH_PRIO
|
||||
# CONFIG_NET_SCH_ETF
|
||||
# CONFIG_NET_CLS_BASIC
|
||||
# CONFIG_NET_CLS_FW
|
||||
# CONFIG_NET_EMATCH
|
||||
# CONFIG_NET_EMATCH_CANID
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
IFACE=${1:-can0}
|
||||
MARK=${2:-1}
|
||||
|
||||
clear() {
|
||||
tc -batch - <<EOF
|
||||
|
||||
qdisc replace dev ${IFACE} root pfifo_fast
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
show() {
|
||||
tc -batch - <<EOF
|
||||
|
||||
qdisc show dev ${IFACE}
|
||||
filter show dev ${IFACE}
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
prio_etf_mark() {
|
||||
tc -batch - <<EOF
|
||||
|
||||
qdisc replace dev ${IFACE} parent root handle 100 prio \
|
||||
bands 3
|
||||
|
||||
qdisc replace dev ${IFACE} handle 1001 parent 100:1 etf clockid CLOCK_TAI \
|
||||
delta 200000
|
||||
|
||||
qdisc replace dev ${IFACE} handle 1002 parent 100:3 pfifo_fast
|
||||
|
||||
filter add dev ${IFACE} parent 100: prio 1 \
|
||||
handle ${MARK} fw flowid 100:1
|
||||
|
||||
filter add dev ${IFACE} parent 100: prio 2 \
|
||||
basic match canid (sff 0x0:0x0 eff 0x0:0x0) flowid 100:2
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
clear
|
||||
prio_etf_mark
|
||||
show
|
||||
+27
-14
@@ -61,6 +61,7 @@
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "terminal.h"
|
||||
#include "canframelen.h"
|
||||
|
||||
@@ -74,9 +75,11 @@ extern int optind, opterr, optopt;
|
||||
static struct {
|
||||
char devname[IFNAMSIZ+1];
|
||||
unsigned int bitrate;
|
||||
unsigned int dbitrate;
|
||||
unsigned int recv_frames;
|
||||
unsigned int recv_bits_total;
|
||||
unsigned int recv_bits_payload;
|
||||
unsigned int recv_bits_dbitrate;
|
||||
} stat[MAXSOCK+1];
|
||||
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
@@ -103,7 +106,7 @@ void print_usage(char *prg)
|
||||
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");
|
||||
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>[,<dbitrate>]\n\n");
|
||||
fprintf(stderr, "The bitrate is mandatory as it is needed to know the CAN bus bitrate to\n");
|
||||
fprintf(stderr, "calculate the bus load percentage based on the received CAN frames.\n");
|
||||
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
|
||||
@@ -184,16 +187,18 @@ void printstats(int signo)
|
||||
}
|
||||
|
||||
if (stat[i].bitrate)
|
||||
percent = (stat[i].recv_bits_total*100)/stat[i].bitrate;
|
||||
percent = ((stat[i].recv_bits_total-stat[i].recv_bits_dbitrate) * 100) / stat[i].bitrate
|
||||
+ (stat[i].recv_bits_dbitrate * 100) / stat[i].dbitrate;
|
||||
else
|
||||
percent = 0;
|
||||
|
||||
printf(" %*s@%-*d %5d %7d %6d %3d%%",
|
||||
printf(" %*s@%-*d %5d %7d %6d %6d %3d%%",
|
||||
max_devname_len, stat[i].devname,
|
||||
max_bitrate_len, stat[i].bitrate,
|
||||
stat[i].recv_frames,
|
||||
stat[i].recv_bits_total,
|
||||
stat[i].recv_bits_payload,
|
||||
stat[i].recv_bits_dbitrate,
|
||||
percent);
|
||||
|
||||
if (bargraph) {
|
||||
@@ -220,6 +225,7 @@ void printstats(int signo)
|
||||
|
||||
stat[i].recv_frames = 0;
|
||||
stat[i].recv_bits_total = 0;
|
||||
stat[i].recv_bits_dbitrate = 0;
|
||||
stat[i].recv_bits_payload = 0;
|
||||
}
|
||||
|
||||
@@ -237,7 +243,7 @@ int main(int argc, char **argv)
|
||||
int opt;
|
||||
char *ptr, *nptr;
|
||||
struct sockaddr_can addr;
|
||||
struct can_frame frame;
|
||||
struct canfd_frame frame;
|
||||
int nbytes, i;
|
||||
struct ifreq ifr;
|
||||
sigset_t sigmask, savesigmask;
|
||||
@@ -305,9 +311,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("open %d '%s'.\n", i, ptr);
|
||||
#endif
|
||||
pr_debug("open %d '%s'.\n", i, ptr);
|
||||
|
||||
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (s[i] < 0) {
|
||||
@@ -336,7 +340,13 @@ int main(int argc, char **argv)
|
||||
if (nbytes > max_devname_len)
|
||||
max_devname_len = nbytes; /* for nice printing */
|
||||
|
||||
stat[i].bitrate = atoi(nptr+1); /* bitrate is placed behind the '@' */
|
||||
char *endp;
|
||||
stat[i].bitrate = strtol(nptr + 1, &endp, 0); /* bitrate is placed behind the '@' */
|
||||
if (*endp == ',')
|
||||
/* data bitrate is placed behind the ',' */
|
||||
stat[i].dbitrate = strtol(endp + 1, &endp, 0);
|
||||
else
|
||||
stat[i].dbitrate = stat[i].bitrate;
|
||||
|
||||
if (!stat[i].bitrate || stat[i].bitrate > 1000000) {
|
||||
printf("invalid bitrate for CAN device '%s'!\n", ptr);
|
||||
@@ -347,10 +357,11 @@ int main(int argc, char **argv)
|
||||
if (nbytes > max_bitrate_len)
|
||||
max_bitrate_len = nbytes; /* for nice printing */
|
||||
|
||||
pr_debug("using interface name '%s'.\n", ifr.ifr_name);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("using interface name '%s'.\n", ifr.ifr_name);
|
||||
#endif
|
||||
/* try to switch the socket into CAN FD mode */
|
||||
const int canfd_on = 1;
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
|
||||
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
@@ -402,9 +413,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
stat[i].recv_frames++;
|
||||
stat[i].recv_bits_payload += frame.can_dlc*8;
|
||||
stat[i].recv_bits_total += can_frame_length((struct canfd_frame*)&frame,
|
||||
mode, sizeof(frame));
|
||||
stat[i].recv_bits_payload += frame.len * 8;
|
||||
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
|
||||
&frame, mode, sizeof(frame));
|
||||
stat[i].recv_bits_total += can_frame_length(&frame,
|
||||
mode, nbytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include "lib.h"
|
||||
@@ -72,10 +73,6 @@
|
||||
#define SO_TIMESTAMPING 37
|
||||
#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 TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
|
||||
|
||||
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
|
||||
@@ -108,6 +105,7 @@ struct if_info { /* bundled information per open socket */
|
||||
};
|
||||
static struct if_info sock_info[MAXSOCK];
|
||||
|
||||
static char *progname;
|
||||
static char devname[MAXIFNAMES][IFNAMSIZ+1];
|
||||
static int dindex[MAXIFNAMES];
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
@@ -121,11 +119,11 @@ extern int optind, opterr, optopt;
|
||||
|
||||
static volatile int running = 1;
|
||||
|
||||
static void print_usage(char *prg)
|
||||
static void print_usage(void)
|
||||
{
|
||||
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, "%s - dump CAN bus traffic.\n", progname);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", progname);
|
||||
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", progname);
|
||||
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");
|
||||
@@ -135,10 +133,11 @@ static void print_usage(char *prg)
|
||||
fprintf(stderr, " -S (swap byte order in printed CAN data[] - marked with '%c' )\n", SWAP_DELIMITER);
|
||||
fprintf(stderr, " -s <level> (silent mode - %d: off (default) %d: animation %d: silent)\n", SILENT_OFF, SILENT_ANI, SILENT_ON);
|
||||
fprintf(stderr, " -l (log CAN-frames into file. Sets '-s %d' by default)\n", SILENT_ON);
|
||||
fprintf(stderr, " -f <fname> (log CAN-frames into file <fname>. Sets '-s %d' by default)\n", SILENT_ON);
|
||||
fprintf(stderr, " -L (use log file format on stdout)\n");
|
||||
fprintf(stderr, " -n <count> (terminate after reception of <count> CAN frames)\n");
|
||||
fprintf(stderr, " -r <size> (set socket receive buffer to <size>)\n");
|
||||
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
|
||||
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");
|
||||
@@ -158,12 +157,12 @@ static void print_usage(char *prg)
|
||||
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\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, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n\n", progname);
|
||||
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF\n (log only error frames but no(!) data frames)\n", progname);
|
||||
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF\n (log error frames and also all data frames)\n", progname);
|
||||
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF\n (match only for extended CAN ID 12345678)\n", progname);
|
||||
fprintf(stderr, "%s vcan2,123:7FF\n (matches CAN ID 123 - including EFF and RTR frames)\n", progname);
|
||||
fprintf(stderr, "%s vcan2,123:C00007FF\n (matches CAN ID 123 - only SFF and non-RTR frames)\n", progname);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -215,9 +214,7 @@ static int idx2dindex(int ifidx, int socket)
|
||||
|
||||
strcpy(devname[i], ifr.ifr_name);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("new index %d (%s)\n", i, devname[i]);
|
||||
#endif
|
||||
pr_debug("new index %d (%s)\n", i, devname[i]);
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -226,7 +223,6 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval *
|
||||
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;
|
||||
@@ -302,7 +298,9 @@ int main(int argc, char **argv)
|
||||
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)) +
|
||||
CMSG_SPACE(3 * sizeof(struct timespec)) +
|
||||
CMSG_SPACE(sizeof(__u32))];
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -314,6 +312,8 @@ int main(int argc, char **argv)
|
||||
struct timeval tv, last_tv;
|
||||
int timeout_ms = -1; /* default to no timeout */
|
||||
FILE *logfile = NULL;
|
||||
char fname[83]; /* suggested by -Wformat-overflow= */
|
||||
const char *logname = NULL;
|
||||
|
||||
signal(SIGTERM, sigterm);
|
||||
signal(SIGHUP, sigterm);
|
||||
@@ -322,7 +322,9 @@ int main(int argc, char **argv)
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_usec = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:he8T:?")) != -1) {
|
||||
progname = basename(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lf:Ln:r:Dde8xT:h?")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
timestamp = optarg[0];
|
||||
@@ -330,7 +332,7 @@ int main(int argc, char **argv)
|
||||
if ((timestamp != 'a') && (timestamp != 'A') &&
|
||||
(timestamp != 'd') && (timestamp != 'z')) {
|
||||
fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
|
||||
basename(argv[0]), optarg[0]);
|
||||
progname, optarg[0]);
|
||||
timestamp = 0;
|
||||
}
|
||||
if ((logtimestamp != 'a') && (logtimestamp != 'z')) {
|
||||
@@ -369,7 +371,7 @@ int main(int argc, char **argv)
|
||||
case 's':
|
||||
silent = atoi(optarg);
|
||||
if (silent > SILENT_ON) {
|
||||
print_usage(basename(argv[0]));
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
@@ -394,10 +396,15 @@ int main(int argc, char **argv)
|
||||
logfrmt = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
logname = optarg;
|
||||
log = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
count = atoi(optarg);
|
||||
if (count < 1) {
|
||||
print_usage(basename(argv[0]));
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
@@ -405,7 +412,7 @@ int main(int argc, char **argv)
|
||||
case 'r':
|
||||
rcvbuf_size = atoi(optarg);
|
||||
if (rcvbuf_size < 1) {
|
||||
print_usage(basename(argv[0]));
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
@@ -414,19 +421,19 @@ int main(int argc, char **argv)
|
||||
errno = 0;
|
||||
timeout_ms = strtol(optarg, NULL, 0);
|
||||
if (errno != 0) {
|
||||
print_usage(basename(argv[0]));
|
||||
print_usage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
print_usage();
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
print_usage(basename(argv[0]));
|
||||
print_usage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -435,6 +442,12 @@ int main(int argc, char **argv)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* "-f -" is equal to "-L" (print logfile format on stdout) */
|
||||
if (log && logname && strcmp("-", logname) == 0) {
|
||||
log = 0; /* no logging into a file */
|
||||
logfrmt = 1; /* print logformat output to stdout */
|
||||
}
|
||||
|
||||
if (silent == SILENT_INI) {
|
||||
if (log) {
|
||||
fprintf(stderr, "Disabled standard output while logging.\n");
|
||||
@@ -461,9 +474,7 @@ int main(int argc, char **argv)
|
||||
ptr = argv[optind+i];
|
||||
nptr = strchr(ptr, ',');
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("open %d '%s'.\n", i, ptr);
|
||||
#endif
|
||||
pr_debug("open %d '%s'.\n", i, ptr);
|
||||
|
||||
obj->s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (obj->s < 0) {
|
||||
@@ -497,9 +508,7 @@ int main(int argc, char **argv)
|
||||
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
|
||||
strncpy(ifr.ifr_name, ptr, nbytes);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("using interface name '%s'.\n", ifr.ifr_name);
|
||||
#endif
|
||||
pr_debug("using interface name '%s'.\n", ifr.ifr_name);
|
||||
|
||||
if (strcmp(ANYDEV, ifr.ifr_name) != 0) {
|
||||
if (ioctl(obj->s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
@@ -511,7 +520,6 @@ int main(int argc, char **argv)
|
||||
addr.can_ifindex = 0; /* any can interface */
|
||||
|
||||
if (nptr) {
|
||||
|
||||
/* found a ',' after the interface name => check for filters */
|
||||
|
||||
/* determine number of filters to alloc the filter space */
|
||||
@@ -589,9 +597,7 @@ int main(int argc, char **argv)
|
||||
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
|
||||
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
|
||||
pr_debug("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
|
||||
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
|
||||
perror("setsockopt SO_RCVBUF");
|
||||
@@ -651,31 +657,34 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (log) {
|
||||
time_t currtime;
|
||||
struct tm now;
|
||||
char fname[83]; /* suggested by -Wformat-overflow= */
|
||||
if (!logname) {
|
||||
time_t currtime;
|
||||
struct tm now;
|
||||
|
||||
if (time(&currtime) == (time_t)-1) {
|
||||
perror("time");
|
||||
return 1;
|
||||
if (time(&currtime) == (time_t)-1) {
|
||||
perror("time");
|
||||
return 1;
|
||||
}
|
||||
|
||||
localtime_r(&currtime, &now);
|
||||
|
||||
snprintf(fname, sizeof(fname), "candump-%04d-%02d-%02d_%02d%02d%02d.log",
|
||||
now.tm_year + 1900,
|
||||
now.tm_mon + 1,
|
||||
now.tm_mday,
|
||||
now.tm_hour,
|
||||
now.tm_min,
|
||||
now.tm_sec);
|
||||
|
||||
logname = fname;
|
||||
}
|
||||
|
||||
localtime_r(&currtime, &now);
|
||||
|
||||
sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
|
||||
now.tm_year + 1900,
|
||||
now.tm_mon + 1,
|
||||
now.tm_mday,
|
||||
now.tm_hour,
|
||||
now.tm_min,
|
||||
now.tm_sec);
|
||||
|
||||
if (silent != SILENT_ON)
|
||||
fprintf(stderr, "Warning: Console output active while logging!\n");
|
||||
|
||||
fprintf(stderr, "Enabling Logfile '%s'\n", fname);
|
||||
fprintf(stderr, "Enabling Logfile '%s'\n", logname);
|
||||
|
||||
logfile = fopen(fname, "w");
|
||||
logfile = fopen(logname, "w");
|
||||
if (!logfile) {
|
||||
perror("logfile");
|
||||
return 1;
|
||||
@@ -697,6 +706,12 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle timeout */
|
||||
if (!num_events && timeout_ms >= 0) {
|
||||
running = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_events; i++) { /* check waiting CAN RAW sockets */
|
||||
struct if_info* obj = events_pending[i].data.ptr;
|
||||
int idx;
|
||||
@@ -738,7 +753,6 @@ int main(int argc, char **argv)
|
||||
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);
|
||||
|
||||
/*
|
||||
@@ -749,22 +763,22 @@ int main(int argc, char **argv)
|
||||
* 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)
|
||||
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",
|
||||
printf("DROPCOUNT: dropped %u CAN frame%s on '%s' socket (total drops %u)\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",
|
||||
fprintf(logfile, "DROPCOUNT: dropped %u CAN frame%s on '%s' socket (total drops %u)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
|
||||
|
||||
obj->last_dropcnt = obj->dropcnt;
|
||||
@@ -794,7 +808,7 @@ int main(int argc, char **argv)
|
||||
extra_info);
|
||||
}
|
||||
|
||||
if ((logfrmt) && (silent == SILENT_OFF)){
|
||||
if ((logfrmt) && (silent == SILENT_OFF)) {
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* print CAN frame in log file style to stdout */
|
||||
@@ -807,7 +821,7 @@ int main(int argc, char **argv)
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
if (silent != SILENT_OFF){
|
||||
if (silent != SILENT_OFF) {
|
||||
if (silent == SILENT_ANI) {
|
||||
printf("%c\b", anichar[silentani %= MAXANI]);
|
||||
silentani++;
|
||||
@@ -821,7 +835,6 @@ int main(int argc, char **argv)
|
||||
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
|
||||
|
||||
+200
-59
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* (C) 2009 by Vladislav Gribov, IXXAT Automation GmbH, <gribov@ixxat.de>
|
||||
* (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
* (C) 2021 Jean Gressmann, IAV GmbH, <jean.steven.gressmann@iav.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the version 2 of the GNU General Public License
|
||||
@@ -39,7 +40,8 @@
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#define CAN_MSG_ID 0x77
|
||||
#define CAN_MSG_ID_PING 0x77
|
||||
#define CAN_MSG_ID_PONG 0x78
|
||||
#define CAN_MSG_LEN 8
|
||||
#define CAN_MSG_COUNT 50
|
||||
#define CAN_MSG_WAIT 27
|
||||
@@ -50,6 +52,13 @@ static int sockfd;
|
||||
static int test_loops;
|
||||
static int exit_sig;
|
||||
static int inflight_count = CAN_MSG_COUNT;
|
||||
static canid_t can_id_ping = CAN_MSG_ID_PING;
|
||||
static canid_t can_id_pong = CAN_MSG_ID_PONG;
|
||||
static int has_pong_id = 0;
|
||||
static int is_can_fd = 0;
|
||||
static int bit_rate_switch = 0;
|
||||
static int msg_len = CAN_MSG_LEN;
|
||||
static int is_extended_frame_format = 0;
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
@@ -58,11 +67,18 @@ static void print_usage(char *prg)
|
||||
"Usage: %s [options] <can-interface>\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -b (enable CAN FD Bit Rate Switch)\n"
|
||||
" -d (use CAN FD frames instead of classic CAN)\n"
|
||||
" -e (use 29-bit extended frame format instead of classic 11-bit one)\n"
|
||||
" -f COUNT (number of frames in flight, default: %d)\n"
|
||||
" -g (generate messages)\n"
|
||||
" -i ID (CAN ID to use for frames to DUT (ping), default %x)\n"
|
||||
" -l COUNT (test loop count)\n"
|
||||
" -o ID (CAN ID to use for frames to host (pong), default %x)\n"
|
||||
" -s SIZE (frame payload size in bytes)\n"
|
||||
" -v (low verbosity)\n"
|
||||
" -vv (high verbosity)\n"
|
||||
" -x (ignore other frames on bus)\n"
|
||||
"\n"
|
||||
"With the option '-g' CAN messages are generated and checked\n"
|
||||
"on <can-interface>, otherwise all messages received on the\n"
|
||||
@@ -74,56 +90,70 @@ static void print_usage(char *prg)
|
||||
"%s -v can0\n"
|
||||
"\ton Host:\n"
|
||||
"%s -g -v can2\n",
|
||||
prg, prg, CAN_MSG_COUNT, prg, prg);
|
||||
prg, prg, CAN_MSG_COUNT, CAN_MSG_ID_PING, CAN_MSG_ID_PONG, prg, prg);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void print_frame(const struct can_frame *frame, int inc)
|
||||
static void print_frame(canid_t id, const uint8_t *data, int dlc, int inc_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("%04x: ", frame->can_id + inc);
|
||||
if (frame->can_id & CAN_RTR_FLAG) {
|
||||
printf("%04x: ", id);
|
||||
if (id & CAN_RTR_FLAG) {
|
||||
printf("remote request");
|
||||
} else {
|
||||
printf("[%d]", frame->can_dlc);
|
||||
for (i = 0; i < frame->can_dlc; i++)
|
||||
printf(" %02x", (uint8_t)(frame->data[i] + inc));
|
||||
printf("[%d]", dlc);
|
||||
for (i = 0; i < dlc; i++)
|
||||
printf(" %02x", (uint8_t)(data[i] + inc_data));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_compare(const struct can_frame *exp, const struct can_frame *rec, int inc)
|
||||
static void print_compare(
|
||||
canid_t exp_id,
|
||||
const uint8_t *exp_data,
|
||||
uint8_t exp_dlc,
|
||||
canid_t rec_id,
|
||||
const uint8_t *rec_data,
|
||||
uint8_t rec_dlc,
|
||||
int inc)
|
||||
{
|
||||
printf("expected: ");
|
||||
print_frame(exp, inc);
|
||||
print_frame(exp_id, exp_data, exp_dlc, inc);
|
||||
printf("received: ");
|
||||
print_frame(rec, 0);
|
||||
print_frame(rec_id, rec_data, rec_dlc, 0);
|
||||
}
|
||||
|
||||
static void compare_frame(struct can_frame *exp, struct can_frame *rec, int inc)
|
||||
static int compare_frame(const struct canfd_frame *exp, const struct canfd_frame *rec, int inc)
|
||||
{
|
||||
int i;
|
||||
int i, err = 0;
|
||||
const canid_t expected_can_id = inc ? can_id_pong : can_id_ping;
|
||||
|
||||
if (rec->can_id != exp->can_id + inc) {
|
||||
if (rec->can_id != expected_can_id) {
|
||||
printf("Message ID mismatch!\n");
|
||||
print_compare(exp, rec, inc);
|
||||
print_compare(expected_can_id, exp->data, exp->len,
|
||||
rec->can_id, rec->data, rec->len, inc);
|
||||
running = 0;
|
||||
} else if (rec->can_dlc != exp->can_dlc) {
|
||||
err = -1;
|
||||
} else if (rec->len != exp->len) {
|
||||
printf("Message length mismatch!\n");
|
||||
print_compare(exp, rec, inc);
|
||||
print_compare(expected_can_id, exp->data, exp->len,
|
||||
rec->can_id, rec->data, rec->len, inc);
|
||||
running = 0;
|
||||
err = -1;
|
||||
} else {
|
||||
for (i = 0; i < rec->can_dlc; i++) {
|
||||
for (i = 0; i < rec->len; i++) {
|
||||
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
|
||||
printf("Databyte %x mismatch!\n", i);
|
||||
print_compare(exp,
|
||||
rec, inc);
|
||||
print_compare(expected_can_id, exp->data, exp->len,
|
||||
rec->can_id, rec->data, rec->len, inc);
|
||||
running = 0;
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void millisleep(int msecs)
|
||||
@@ -160,29 +190,41 @@ static void signal_handler(int signo)
|
||||
exit_sig = signo;
|
||||
}
|
||||
|
||||
static int recv_frame(struct can_frame *frame)
|
||||
static int recv_frame(struct canfd_frame *frame)
|
||||
{
|
||||
int ret;
|
||||
ssize_t ret, len;
|
||||
|
||||
ret = recv(sockfd, frame, sizeof(*frame), 0);
|
||||
if (ret != sizeof(*frame)) {
|
||||
if (is_can_fd)
|
||||
len = sizeof(struct canfd_frame);
|
||||
else
|
||||
len = sizeof(struct can_frame);
|
||||
|
||||
ret = recv(sockfd, frame, len, 0);
|
||||
if (ret != len) {
|
||||
if (ret < 0)
|
||||
perror("recv failed");
|
||||
else
|
||||
fprintf(stderr, "recv returned %d", ret);
|
||||
fprintf(stderr, "recv returned %zd", ret);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_frame(struct can_frame *frame)
|
||||
static int send_frame(struct canfd_frame *frame)
|
||||
{
|
||||
int ret;
|
||||
ssize_t ret, len;
|
||||
|
||||
while ((ret = send(sockfd, frame, sizeof(*frame), 0))
|
||||
!= sizeof(*frame)) {
|
||||
if (is_can_fd)
|
||||
len = sizeof(struct canfd_frame);
|
||||
else
|
||||
len = sizeof(struct can_frame);
|
||||
|
||||
if (bit_rate_switch)
|
||||
frame->flags |= CANFD_BRS;
|
||||
|
||||
while ((ret = send(sockfd, frame, len, 0)) != len) {
|
||||
if (ret >= 0) {
|
||||
fprintf(stderr, "send returned %d", ret);
|
||||
fprintf(stderr, "send returned %zd", ret);
|
||||
return -1;
|
||||
}
|
||||
if (errno != ENOBUFS) {
|
||||
@@ -197,25 +239,25 @@ static int send_frame(struct can_frame *frame)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_frame(const struct can_frame *frame)
|
||||
static int check_frame(const struct canfd_frame *frame)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
if (frame->can_id != CAN_MSG_ID) {
|
||||
printf("unexpected Message ID 0x%04x!\n", frame->can_id);
|
||||
if (frame->can_id != can_id_ping) {
|
||||
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);
|
||||
if (frame->len != msg_len) {
|
||||
printf("Unexpected Message length %d!\n", frame->len);
|
||||
err = -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < frame->can_dlc; i++) {
|
||||
for (i = 1; i < frame->len; i++) {
|
||||
if (frame->data[i] != (uint8_t)(frame->data[i-1] + 1)) {
|
||||
printf("Frame inconsistent!\n");
|
||||
print_frame(frame, 0);
|
||||
print_frame(frame->can_id, frame->data, frame->len, 0);
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -225,19 +267,24 @@ static int check_frame(const struct can_frame *frame)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void inc_frame(struct can_frame *frame)
|
||||
static void inc_frame(struct canfd_frame *frame)
|
||||
{
|
||||
int i;
|
||||
|
||||
frame->can_id++;
|
||||
for (i = 0; i < frame->can_dlc; i++)
|
||||
if (has_pong_id)
|
||||
frame->can_id = can_id_pong;
|
||||
else
|
||||
frame->can_id++;
|
||||
|
||||
for (i = 0; i < frame->len; i++)
|
||||
frame->data[i]++;
|
||||
}
|
||||
|
||||
static int can_echo_dut(void)
|
||||
{
|
||||
unsigned int frame_count = 0;
|
||||
struct can_frame frame;
|
||||
struct canfd_frame frame;
|
||||
int err = 0;
|
||||
|
||||
while (running) {
|
||||
if (recv_frame(&frame))
|
||||
@@ -246,10 +293,10 @@ static int can_echo_dut(void)
|
||||
if (verbose == 1) {
|
||||
echo_progress(frame.data[0]);
|
||||
} else if (verbose > 1) {
|
||||
print_frame(&frame, 0);
|
||||
print_frame(frame.can_id, frame.data, frame.len, 0);
|
||||
}
|
||||
|
||||
check_frame(&frame);
|
||||
err = check_frame(&frame);
|
||||
inc_frame(&frame);
|
||||
if (send_frame(&frame))
|
||||
return -1;
|
||||
@@ -264,14 +311,14 @@ static int can_echo_dut(void)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int can_echo_gen(void)
|
||||
{
|
||||
struct can_frame *tx_frames;
|
||||
struct canfd_frame *tx_frames;
|
||||
int *recv_tx;
|
||||
struct can_frame rx_frame;
|
||||
struct canfd_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;
|
||||
@@ -290,11 +337,11 @@ static int can_echo_gen(void)
|
||||
while (running) {
|
||||
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;
|
||||
tx_frames[send_pos].len = msg_len;
|
||||
tx_frames[send_pos].can_id = can_id_ping;
|
||||
recv_tx[send_pos] = 0;
|
||||
|
||||
for (i = 0; i < CAN_MSG_LEN; i++)
|
||||
for (i = 0; i < msg_len; i++)
|
||||
tx_frames[send_pos].data[i] = counter + i;
|
||||
if (send_frame(&tx_frames[send_pos])) {
|
||||
err = -1;
|
||||
@@ -320,11 +367,11 @@ static int can_echo_gen(void)
|
||||
}
|
||||
|
||||
if (verbose > 1)
|
||||
print_frame(&rx_frame, 0);
|
||||
print_frame(rx_frame.can_id, rx_frame.data, rx_frame.len, 0);
|
||||
|
||||
/* own frame */
|
||||
if (rx_frame.can_id == CAN_MSG_ID) {
|
||||
compare_frame(&tx_frames[recv_tx_pos], &rx_frame, 0);
|
||||
if (rx_frame.can_id == can_id_ping) {
|
||||
err = compare_frame(&tx_frames[recv_tx_pos], &rx_frame, 0);
|
||||
recv_tx[recv_tx_pos] = 1;
|
||||
recv_tx_pos++;
|
||||
if (recv_tx_pos == inflight_count)
|
||||
@@ -334,11 +381,11 @@ static int can_echo_gen(void)
|
||||
|
||||
if (!recv_tx[recv_rx_pos]) {
|
||||
printf("RX before TX!\n");
|
||||
print_frame(&rx_frame, 0);
|
||||
print_frame(rx_frame.can_id, rx_frame.data, rx_frame.len, 0);
|
||||
running = 0;
|
||||
}
|
||||
/* compare with expected */
|
||||
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
|
||||
err = compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
|
||||
recv_rx_pos++;
|
||||
if (recv_rx_pos == inflight_count)
|
||||
recv_rx_pos = 0;
|
||||
@@ -368,14 +415,27 @@ int main(int argc, char *argv[])
|
||||
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
|
||||
int echo_gen = 0;
|
||||
int opt, err;
|
||||
int recv_own_msgs = 1;
|
||||
int enable_socket_option = 1;
|
||||
int filter = 0;
|
||||
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
while ((opt = getopt(argc, argv, "f:gl:v?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "bdef:gi:l:o:s:vx?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bit_rate_switch = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
is_can_fd = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
is_extended_frame_format = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
inflight_count = atoi(optarg);
|
||||
break;
|
||||
@@ -384,14 +444,31 @@ int main(int argc, char *argv[])
|
||||
echo_gen = 1;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
can_id_ping = strtoul(optarg, NULL, 16);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
test_loops = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
can_id_pong = strtoul(optarg, NULL, 16);
|
||||
has_pong_id = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
msg_len = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
|
||||
case 'x':
|
||||
filter = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
@@ -399,6 +476,39 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* BRS can be enabled only if CAN FD is enabled */
|
||||
if (bit_rate_switch && !is_can_fd) {
|
||||
printf("Bit rate switch (-b) needs CAN FD (-d) to be enabled\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make sure the message length is valid */
|
||||
if (msg_len <= 0) {
|
||||
printf("Message length must > 0\n");
|
||||
return 1;
|
||||
}
|
||||
if (is_can_fd) {
|
||||
if (msg_len > CANFD_MAX_DLEN) {
|
||||
printf("Message length must be <= %d bytes for CAN FD\n", CANFD_MAX_DLEN);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (msg_len > CAN_MAX_DLEN) {
|
||||
printf("Message length must be <= %d bytes for CAN 2.0B\n", CAN_MAX_DLEN);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_extended_frame_format) {
|
||||
can_id_ping &= CAN_EFF_MASK;
|
||||
can_id_ping |= CAN_EFF_FLAG;
|
||||
can_id_pong &= CAN_EFF_MASK;
|
||||
can_id_pong |= CAN_EFF_FLAG;
|
||||
} else {
|
||||
can_id_ping &= CAN_SFF_MASK;
|
||||
can_id_pong &= CAN_SFF_MASK;
|
||||
}
|
||||
|
||||
if ((argc - optind) != 1)
|
||||
print_usage(basename(argv[0]));
|
||||
intf_name = argv[optind];
|
||||
@@ -413,8 +523,16 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (echo_gen) {
|
||||
if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
|
||||
&recv_own_msgs, sizeof(recv_own_msgs)) == -1) {
|
||||
perror("setsockopt");
|
||||
&enable_socket_option, sizeof(enable_socket_option)) == -1) {
|
||||
perror("setsockopt CAN_RAW_RECV_OWN_MSGS");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_can_fd) {
|
||||
if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||
&enable_socket_option, sizeof(enable_socket_option)) == -1) {
|
||||
perror("setsockopt CAN_RAW_FD_FRAMES");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -433,6 +551,29 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!has_pong_id)
|
||||
can_id_pong = can_id_ping + 1;
|
||||
|
||||
if (filter) {
|
||||
const struct can_filter filters[] = {
|
||||
{
|
||||
.can_id = can_id_ping,
|
||||
.can_mask = CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK,
|
||||
},
|
||||
{
|
||||
.can_id = can_id_pong,
|
||||
.can_mask = CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, filters,
|
||||
sizeof(struct can_filter) * (1 + echo_gen))) {
|
||||
perror("setsockopt()");
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (echo_gen)
|
||||
err = can_echo_gen();
|
||||
else
|
||||
|
||||
+29
-2
@@ -236,13 +236,40 @@ static unsigned cfl_exact(struct can_frame *frame)
|
||||
3; /* IFS */
|
||||
}
|
||||
|
||||
unsigned can_frame_dbitrate_length(struct canfd_frame *frame, enum cfl_mode mode, int mtu)
|
||||
{
|
||||
if (mtu != CANFD_MTU || !(frame->flags & CANFD_BRS))
|
||||
return 0;
|
||||
switch (mode) {
|
||||
case CFL_NO_BITSTUFFING:
|
||||
return 1 /* brs/crcdel */ + 1 /* esi */ + 4 /* dlc */ +
|
||||
((frame->len >= 16) ? 21 : 17) +
|
||||
frame->len * 8;
|
||||
case CFL_WORSTCASE:
|
||||
return can_frame_dbitrate_length(frame, CFL_NO_BITSTUFFING, mtu) * 5 / 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned can_frame_length(struct canfd_frame *frame, enum cfl_mode mode, int mtu)
|
||||
{
|
||||
int eff = (frame->can_id & CAN_EFF_FLAG);
|
||||
|
||||
if (mtu != CAN_MTU)
|
||||
return 0; /* CANFD is not supported yet */
|
||||
if (mtu == CANFD_MTU)
|
||||
/* not correct, but close ? */
|
||||
switch (mode) {
|
||||
case CFL_NO_BITSTUFFING:
|
||||
return 1 + (eff ? 29 : 11) + ((frame->len >= 16) ? 21 : 17) +
|
||||
5 /* r1, ide, edl, r0, brs/crcdel, */ + 12 /* trail */ +
|
||||
frame->len * 8;
|
||||
case CFL_WORSTCASE:
|
||||
return can_frame_length(frame, CFL_NO_BITSTUFFING, mtu) * 5 / 4;
|
||||
case CFL_EXACT:
|
||||
return 0; /* exact bittiming for CANFD not supported yet */
|
||||
}
|
||||
else if (mtu != CAN_MTU)
|
||||
return 0; /* Only CAN2.0 and CANFD supported now */
|
||||
|
||||
switch (mode) {
|
||||
case CFL_NO_BITSTUFFING:
|
||||
|
||||
@@ -80,5 +80,6 @@ enum cfl_mode {
|
||||
* Mode determines how to deal with stuffed bits.
|
||||
*/
|
||||
unsigned can_frame_length(struct canfd_frame *frame, enum cfl_mode mode, int mtu);
|
||||
unsigned can_frame_dbitrate_length(struct canfd_frame *frame, enum cfl_mode mode, int mtu);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
/*
|
||||
* cangen.c - CAN frames generator
|
||||
*
|
||||
* Copyright (c) 2022 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -44,9 +46,12 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#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>
|
||||
@@ -63,66 +68,135 @@
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define DEFAULT_GAP 200 /* ms */
|
||||
#define DEFAULT_BURST_COUNT 1
|
||||
#define DEFAULT_SO_MARK_VAL 1
|
||||
|
||||
#define MODE_RANDOM 0
|
||||
#define MODE_INCREMENT 1
|
||||
#define MODE_FIX 2
|
||||
#define MODE_RANDOM_EVEN 3
|
||||
#define MODE_RANDOM_ODD 4
|
||||
#define MODE_RANDOM 0
|
||||
#define MODE_INCREMENT 1
|
||||
#define MODE_FIX 2
|
||||
#define MODE_RANDOM_EVEN 3
|
||||
#define MODE_RANDOM_ODD 4
|
||||
#define MODE_RANDOM_FIX 5
|
||||
|
||||
#define NIBBLE_H 1
|
||||
#define NIBBLE_L 2
|
||||
|
||||
#define CHAR_RANDOM 'x'
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static volatile int running = 1;
|
||||
static unsigned long long enobufs_count;
|
||||
static bool ignore_enobufs;
|
||||
static bool use_so_txtime;
|
||||
|
||||
void print_usage(char *prg)
|
||||
static int clockid = CLOCK_TAI;
|
||||
static int clock_nanosleep_flags;
|
||||
static struct timespec ts, ts_gap;
|
||||
static int so_mark_val = DEFAULT_SO_MARK_VAL;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000LL
|
||||
|
||||
static struct timespec timespec_normalise(struct timespec ts)
|
||||
{
|
||||
while (ts.tv_nsec >= NSEC_PER_SEC) {
|
||||
++(ts.tv_sec);
|
||||
ts.tv_nsec -= NSEC_PER_SEC;
|
||||
}
|
||||
|
||||
while (ts.tv_nsec <= -NSEC_PER_SEC) {
|
||||
--(ts.tv_sec);
|
||||
ts.tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
|
||||
if (ts.tv_nsec < 0) {
|
||||
/*
|
||||
* Negative nanoseconds isn't valid according to
|
||||
* POSIX. Decrement tv_sec and roll tv_nsec over.
|
||||
*/
|
||||
|
||||
--(ts.tv_sec);
|
||||
ts.tv_nsec = (NSEC_PER_SEC + ts.tv_nsec);
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
static struct timespec timespec_add(struct timespec ts1, struct timespec ts2)
|
||||
{
|
||||
/*
|
||||
* Normalize inputs to prevent tv_nsec rollover if
|
||||
* whole-second values are packed in it.
|
||||
*/
|
||||
ts1 = timespec_normalise(ts1);
|
||||
ts2 = timespec_normalise(ts2);
|
||||
|
||||
ts1.tv_sec += ts2.tv_sec;
|
||||
ts1.tv_nsec += ts2.tv_nsec;
|
||||
|
||||
return timespec_normalise(ts1);
|
||||
}
|
||||
|
||||
struct timespec double_to_timespec(double s)
|
||||
{
|
||||
struct timespec ts = {
|
||||
.tv_sec = s,
|
||||
.tv_nsec = (s - (long)(s)) * NSEC_PER_SEC,
|
||||
};
|
||||
|
||||
return timespec_normalise(ts);
|
||||
}
|
||||
|
||||
static struct timespec ns_to_timespec(int64_t ns)
|
||||
{
|
||||
struct timespec ts = {
|
||||
.tv_sec = ns / NSEC_PER_SEC,
|
||||
.tv_nsec = ns % NSEC_PER_SEC,
|
||||
};
|
||||
|
||||
return timespec_normalise(ts);
|
||||
}
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - CAN frames generator.\n\n", prg);
|
||||
fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
|
||||
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, " -g <ms> (gap in milli seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -a (use absolute time for gap)\n");
|
||||
fprintf(stderr, " -t (use SO_TXTIME)\n");
|
||||
fprintf(stderr, " --start <ns> (start time (UTC nanoseconds))\n");
|
||||
fprintf(stderr, " --mark <id> (set SO_MARK to <id>, default %u)\n", DEFAULT_SO_MARK_VAL);
|
||||
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, " -E (generate CAN FD CAN frames"
|
||||
" with error state (ESI))\n");
|
||||
fprintf(stderr, " -b (generate CAN FD CAN frames with bitrate switch (BRS))\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)"
|
||||
" generation mode - see below)\n");
|
||||
fprintf(stderr, " -D <mode> (CAN data (payload)"
|
||||
" generation mode - see below)\n");
|
||||
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames"
|
||||
" with <timeout> ms)\n");
|
||||
fprintf(stderr, " -n <count> (terminate after <count> CAN frames "
|
||||
"- default infinite)\n");
|
||||
fprintf(stderr, " -i (ignore -ENOBUFS return values on"
|
||||
" write() syscalls)\n");
|
||||
fprintf(stderr, " -x (disable local loopback of "
|
||||
"generated CAN frames)\n");
|
||||
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, " -I <mode> (CAN ID generation mode - see below)\n");
|
||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
|
||||
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
||||
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
|
||||
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
|
||||
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
|
||||
fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n");
|
||||
fprintf(stderr, " -c <count> (number of messages to send in burst, default %u)\n", DEFAULT_BURST_COUNT);
|
||||
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, " '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, " <value> => fixed value (in hexadecimal for -I and -D)\n");
|
||||
fprintf(stderr, " => nibbles written as '%c' are randomized (only -D)\n\n", CHAR_RANDOM);
|
||||
fprintf(stderr, "The gap value (in milliseconds) may have decimal places, e.g. '-g 4.73'\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\n", prg);
|
||||
@@ -131,6 +205,10 @@ void print_usage(char *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 -D 11%c%c3344DEADBEEF -L 8\n", prg, CHAR_RANDOM, CHAR_RANDOM);
|
||||
fprintf(stderr, "\t(fixed CAN data payload where 2. byte is randomized, fixed length)\n");
|
||||
fprintf(stderr, "%s vcan0 -I 555 -D CCCCCCCCCCCCCCCC -L 8 -g 3.75\n", prg);
|
||||
fprintf(stderr, "\t(generate a fix busload without bit-stuffing effects)\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);
|
||||
@@ -139,17 +217,227 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, "\t(my favourite default :)\n\n");
|
||||
}
|
||||
|
||||
void sigterm(int signo)
|
||||
static void sigterm(int signo)
|
||||
{
|
||||
running = 0;
|
||||
}
|
||||
|
||||
static int setsockopt_txtime(int fd)
|
||||
{
|
||||
const struct sock_txtime so_txtime_val = {
|
||||
.clockid = clockid,
|
||||
.flags = SOF_TXTIME_REPORT_ERRORS,
|
||||
};
|
||||
struct sock_txtime so_txtime_val_read;
|
||||
int so_mark_val_read;
|
||||
socklen_t vallen;
|
||||
int ret;
|
||||
|
||||
/* SO_TXTIME */
|
||||
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_TXTIME,
|
||||
&so_txtime_val, sizeof(so_txtime_val));
|
||||
if (ret) {
|
||||
int err = errno;
|
||||
|
||||
perror("setsockopt() SO_TXTIME");
|
||||
if (err == EPERM)
|
||||
fprintf(stderr, "Run with CAP_NET_ADMIN or as root.\n");
|
||||
|
||||
return -err;
|
||||
};
|
||||
|
||||
vallen = sizeof(so_txtime_val_read);
|
||||
ret = getsockopt(fd, SOL_SOCKET, SO_TXTIME,
|
||||
&so_txtime_val_read, &vallen);
|
||||
if (ret) {
|
||||
perror("getsockopt() SO_TXTIME");
|
||||
return -errno;
|
||||
};
|
||||
|
||||
if (vallen != sizeof(so_txtime_val) ||
|
||||
memcmp(&so_txtime_val, &so_txtime_val_read, vallen)) {
|
||||
perror("getsockopt() SO_TXTIME: mismatch");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* SO_MARK */
|
||||
|
||||
ret = setsockopt(fd, SOL_SOCKET, SO_MARK, &so_mark_val, sizeof(so_mark_val));
|
||||
if (ret) {
|
||||
int err = errno;
|
||||
|
||||
perror("setsockopt() SO_MARK");
|
||||
if (err == EPERM)
|
||||
fprintf(stderr, "Run with CAP_NET_ADMIN or as root.\n");
|
||||
|
||||
return -err;
|
||||
};
|
||||
|
||||
vallen = sizeof(so_mark_val_read);
|
||||
ret = getsockopt(fd, SOL_SOCKET, SO_MARK,
|
||||
&so_mark_val_read, &vallen);
|
||||
if (ret) {
|
||||
perror("getsockopt() SO_MARK");
|
||||
return -errno;
|
||||
};
|
||||
|
||||
if (vallen != sizeof(so_mark_val) ||
|
||||
memcmp(&so_mark_val, &so_mark_val_read, vallen)) {
|
||||
perror("getsockopt() SO_MARK: mismatch");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_send_one(int fd, void *buf, size_t len, int timeout)
|
||||
{
|
||||
uint8_t control[CMSG_SPACE(sizeof(uint64_t))] = { 0 };
|
||||
struct iovec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = len,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
ssize_t nbytes;
|
||||
int ret;
|
||||
|
||||
if (use_so_txtime) {
|
||||
struct cmsghdr *cm;
|
||||
uint64_t tdeliver;
|
||||
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = sizeof(control);
|
||||
|
||||
tdeliver = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
|
||||
ts = timespec_add(ts, ts_gap);
|
||||
|
||||
cm = CMSG_FIRSTHDR(&msg);
|
||||
cm->cmsg_level = SOL_SOCKET;
|
||||
cm->cmsg_type = SCM_TXTIME;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(tdeliver));
|
||||
memcpy(CMSG_DATA(cm), &tdeliver, sizeof(tdeliver));
|
||||
}
|
||||
|
||||
resend:
|
||||
nbytes = sendmsg(fd, &msg, 0);
|
||||
if (nbytes < 0) {
|
||||
ret = -errno;
|
||||
if (ret != -ENOBUFS) {
|
||||
perror("write");
|
||||
return ret;
|
||||
}
|
||||
if (!ignore_enobufs && !timeout) {
|
||||
perror("write");
|
||||
return ret;
|
||||
}
|
||||
if (timeout) {
|
||||
struct pollfd fds = {
|
||||
.fd = fd,
|
||||
.events = POLLOUT,
|
||||
};
|
||||
|
||||
/* wait for the write socket (with timeout) */
|
||||
ret = poll(&fds, 1, timeout);
|
||||
if (ret == 0 || (ret == -1 && errno != EINTR)) {
|
||||
ret = -errno;
|
||||
perror("poll");
|
||||
return ret;
|
||||
}
|
||||
goto resend;
|
||||
} else {
|
||||
enobufs_count++;
|
||||
}
|
||||
|
||||
} else if (nbytes < (ssize_t)len) {
|
||||
fprintf(stderr, "write: incomplete CAN frame\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_time(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (use_so_txtime) {
|
||||
/* start time is defined */
|
||||
if (ts.tv_sec || ts.tv_nsec)
|
||||
return 0;
|
||||
|
||||
/* start time is now .... */
|
||||
ret = clock_gettime(clockid, &ts);
|
||||
if (ret) {
|
||||
perror("clock_gettime");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ... + gap */
|
||||
ts = timespec_add(ts, ts_gap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ts.tv_sec || ts.tv_nsec) {
|
||||
ret = clock_nanosleep(clockid, TIMER_ABSTIME, &ts, NULL);
|
||||
if (ret != 0 && ret != EINTR) {
|
||||
perror("clock_nanosleep");
|
||||
return ret;
|
||||
}
|
||||
} else if (clock_nanosleep_flags == TIMER_ABSTIME) {
|
||||
ret = clock_gettime(clockid, &ts);
|
||||
if (ret)
|
||||
perror("clock_gettime");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (clock_nanosleep_flags != TIMER_ABSTIME)
|
||||
ts = ts_gap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
OPT_MARK = UCHAR_MAX + 1,
|
||||
OPT_START = UCHAR_MAX + 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Search for CHAR_RANDOM in dataoptarg, save its position, replace it with 0.
|
||||
* Return 1 if at least one CHAR_RANDOM found.
|
||||
*/
|
||||
static int parse_dataoptarg(char *dataoptarg, unsigned char *rand_position)
|
||||
{
|
||||
int mode_format_selected = MODE_FIX;
|
||||
int arglen = strlen(dataoptarg);
|
||||
|
||||
/* Mark nibbles with * as fuzzable */
|
||||
for (int i = 0; i < CANFD_MAX_DLEN && i < arglen / 2; i++) {
|
||||
if (optarg[2 * i] == CHAR_RANDOM) {
|
||||
optarg[2 * i] = '0';
|
||||
rand_position[i] += NIBBLE_H;
|
||||
mode_format_selected = MODE_RANDOM_FIX;
|
||||
}
|
||||
if (optarg[2 * i + 1] == CHAR_RANDOM) {
|
||||
optarg[2 * i + 1] = '0';
|
||||
rand_position[i] += NIBBLE_L;
|
||||
mode_format_selected = MODE_RANDOM_FIX;
|
||||
}
|
||||
}
|
||||
|
||||
return mode_format_selected;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -169,20 +457,19 @@ int main(int argc, char **argv)
|
||||
int incdlc = 0;
|
||||
unsigned long rnd;
|
||||
unsigned char fixdata[CANFD_MAX_DLEN];
|
||||
unsigned char rand_position[CANFD_MAX_DLEN] = {0};
|
||||
|
||||
int opt;
|
||||
int s; /* socket */
|
||||
struct pollfd fds;
|
||||
|
||||
struct sockaddr_can addr;
|
||||
struct sockaddr_can addr = { 0 };
|
||||
static struct canfd_frame frame;
|
||||
struct can_frame *ccf = (struct can_frame *)&frame;
|
||||
int nbytes;
|
||||
int i;
|
||||
struct ifreq ifr;
|
||||
|
||||
struct timespec ts;
|
||||
struct timeval now;
|
||||
int ret;
|
||||
|
||||
/* set seed value for pseudo random numbers */
|
||||
gettimeofday(&now, NULL);
|
||||
@@ -192,17 +479,39 @@ int main(int argc, char **argv)
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vR8h?")) != -1) {
|
||||
switch (opt) {
|
||||
const struct option long_options[] = {
|
||||
{ "mark", required_argument, 0, OPT_MARK, },
|
||||
{ "start", required_argument, 0, OPT_START, },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
case 'i':
|
||||
ignore_enobufs = 1;
|
||||
break;
|
||||
while ((opt = getopt_long(argc, argv, "g:atefbER8mI:L:D:p:n:ixc:vh?", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
|
||||
case 'g':
|
||||
gap = strtod(optarg, NULL);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
clock_nanosleep_flags = TIMER_ABSTIME;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
clock_nanosleep_flags = TIMER_ABSTIME;
|
||||
use_so_txtime = true;
|
||||
break;
|
||||
|
||||
case OPT_START: {
|
||||
int64_t start_time_ns;
|
||||
|
||||
start_time_ns = strtoll(optarg, NULL, 0);
|
||||
ts = ns_to_timespec(start_time_ns);
|
||||
|
||||
break;
|
||||
}
|
||||
case OPT_MARK:
|
||||
so_mark_val = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'e':
|
||||
extended = 1;
|
||||
break;
|
||||
@@ -221,6 +530,14 @@ int main(int argc, char **argv)
|
||||
canfd = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
rtr_frame = 1;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
len8_dlc = 1;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
mix = 1;
|
||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||
@@ -258,34 +575,15 @@ int main(int argc, char **argv)
|
||||
} else if (optarg[0] == 'i') {
|
||||
data_mode = MODE_INCREMENT;
|
||||
} else {
|
||||
data_mode = MODE_FIX;
|
||||
data_mode = parse_dataoptarg(optarg, rand_position);
|
||||
|
||||
if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) {
|
||||
printf ("wrong fix data definition\n");
|
||||
printf("wrong fix data definition\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
burst_count = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
loopback_disable = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
rtr_frame = 1;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
len8_dlc = 1;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
polltimeout = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
@@ -298,12 +596,27 @@ int main(int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
ignore_enobufs = true;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
loopback_disable = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
burst_count = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,13 +625,11 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ts.tv_sec = gap / 1000;
|
||||
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000LL);
|
||||
ts_gap = double_to_timespec(gap / 1000);
|
||||
|
||||
/* recognize obviously missing commandline option */
|
||||
if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) {
|
||||
printf("The given CAN-ID is greater than 0x7FF and "
|
||||
"the '-e' option is not set.\n");
|
||||
printf("The given CAN-ID is greater than 0x7FF and the '-e' option is not set.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -327,7 +638,8 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
@@ -341,21 +653,23 @@ int main(int argc, char **argv)
|
||||
}
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
/* disable default receive filter on this RAW socket */
|
||||
/* This is obsolete as we do not read from the socket at all, but for */
|
||||
/* this reason we can remove the receive list in the Kernel to save a */
|
||||
/* little (really a very little!) CPU usage. */
|
||||
/*
|
||||
* disable default receive filter on this RAW socket
|
||||
* This is obsolete as we do not read from the socket at all, but for
|
||||
* this reason we can remove the receive list in the Kernel to save a
|
||||
* little (really a very little!) CPU usage.
|
||||
*/
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
||||
|
||||
if (loopback_disable) {
|
||||
int loopback = 0;
|
||||
const int loopback = 0;
|
||||
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
||||
&loopback, sizeof(loopback));
|
||||
}
|
||||
|
||||
if (canfd) {
|
||||
int enable_canfd = 1;
|
||||
const int enable_canfd = 1;
|
||||
|
||||
/* check if the frame fits into the CAN netdevice */
|
||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||
@@ -369,7 +683,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))){
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))) {
|
||||
printf("error when enabling CAN FD support\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -395,18 +709,23 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (polltimeout) {
|
||||
fds.fd = s;
|
||||
fds.events = POLLOUT;
|
||||
if (use_so_txtime) {
|
||||
ret = setsockopt_txtime(s);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = setup_time();
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
while (running) {
|
||||
frame.flags = 0;
|
||||
|
||||
if (count && (--count == 0))
|
||||
running = 0;
|
||||
|
||||
if (canfd){
|
||||
if (canfd) {
|
||||
mtu = CANFD_MTU;
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
if (brs)
|
||||
@@ -435,7 +754,6 @@ int main(int argc, char **argv)
|
||||
frame.can_id |= CAN_RTR_FLAG;
|
||||
|
||||
if (dlc_mode == MODE_RANDOM) {
|
||||
|
||||
if (canfd)
|
||||
frame.len = can_fd_dlc2len(random() & 0xF);
|
||||
else {
|
||||
@@ -457,7 +775,6 @@ int main(int argc, char **argv)
|
||||
frame.len = 1; /* min dlc value for incr. data */
|
||||
|
||||
if (data_mode == MODE_RANDOM) {
|
||||
|
||||
rnd = random();
|
||||
memcpy(&frame.data[0], &rnd, 4);
|
||||
rnd = random();
|
||||
@@ -471,6 +788,20 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (data_mode == MODE_RANDOM_FIX) {
|
||||
memcpy(frame.data, fixdata, CANFD_MAX_DLEN);
|
||||
|
||||
for (int i = 0; i < frame.len; i++) {
|
||||
if (rand_position[i] == (NIBBLE_H | NIBBLE_L)) {
|
||||
frame.data[i] = random();
|
||||
} else if (rand_position[i] == NIBBLE_H) {
|
||||
frame.data[i] = (frame.data[i] & 0x0f) | (random() & 0xf0);
|
||||
} else if (rand_position[i] == NIBBLE_L) {
|
||||
frame.data[i] = (frame.data[i] & 0xf0) | (random() & 0x0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data_mode == MODE_FIX)
|
||||
memcpy(frame.data, fixdata, CANFD_MAX_DLEN);
|
||||
|
||||
@@ -478,55 +809,40 @@ int main(int argc, char **argv)
|
||||
if (frame.len < maxdlen)
|
||||
memset(&frame.data[frame.len], 0, maxdlen - frame.len);
|
||||
|
||||
if (verbose) {
|
||||
if (!use_so_txtime &&
|
||||
(ts.tv_sec || ts.tv_nsec) &&
|
||||
burst_sent_count >= burst_count) {
|
||||
if (clock_nanosleep_flags == TIMER_ABSTIME)
|
||||
ts = timespec_add(ts, ts_gap);
|
||||
|
||||
ret = clock_nanosleep(clockid, clock_nanosleep_flags, &ts, NULL);
|
||||
if (ret != 0 && ret != EINTR) {
|
||||
perror("clock_nanosleep");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf(" %s ", argv[optind]);
|
||||
|
||||
if (verbose > 1)
|
||||
fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0, maxdlen);
|
||||
fprint_long_canframe(stdout, &frame, "\n", (verbose > 2) ? 1 : 0, maxdlen);
|
||||
else
|
||||
fprint_canframe(stdout, &frame, "\n", 1, maxdlen);
|
||||
}
|
||||
|
||||
resend:
|
||||
nbytes = write(s, &frame, mtu);
|
||||
if (nbytes < 0) {
|
||||
if (errno != ENOBUFS) {
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
if (!ignore_enobufs && !polltimeout) {
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
if (polltimeout) {
|
||||
/* wait for the write socket (with timeout) */
|
||||
if (poll(&fds, 1, polltimeout) < 0) {
|
||||
perror("poll");
|
||||
return 1;
|
||||
}
|
||||
goto resend;
|
||||
} else
|
||||
enobufs_count++;
|
||||
|
||||
} else if (nbytes < mtu) {
|
||||
fprintf(stderr, "write: incomplete CAN frame\n");
|
||||
ret = do_send_one(s, &frame, mtu, polltimeout);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
burst_sent_count++;
|
||||
|
||||
if (id_mode == MODE_INCREMENT)
|
||||
frame.can_id++;
|
||||
|
||||
if (dlc_mode == MODE_INCREMENT) {
|
||||
|
||||
incdlc++;
|
||||
incdlc %= CAN_MAX_RAW_DLC + 1;
|
||||
|
||||
@@ -547,22 +863,21 @@ resend:
|
||||
}
|
||||
|
||||
if (data_mode == MODE_INCREMENT) {
|
||||
|
||||
incdata++;
|
||||
|
||||
for (i=0; i<8 ;i++)
|
||||
frame.data[i] = (incdata >> i*8) & 0xFFULL;
|
||||
for (i = 0; i < 8; i++)
|
||||
frame.data[i] = incdata >> i * 8;
|
||||
}
|
||||
|
||||
if (mix) {
|
||||
i = random();
|
||||
extended = i&1;
|
||||
canfd = i&2;
|
||||
extended = i & 1;
|
||||
canfd = i & 2;
|
||||
if (canfd) {
|
||||
brs = i&4;
|
||||
esi = i&8;
|
||||
brs = i & 4;
|
||||
esi = i & 8;
|
||||
}
|
||||
rtr_frame = ((i&24) == 24); /* reduce RTR frames to 1/4 */
|
||||
rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -743,10 +743,18 @@ int main(int argc, char **argv)
|
||||
|
||||
case 's':
|
||||
src_ifindex = if_nametoindex(optarg);
|
||||
if (!src_ifindex) {
|
||||
perror("src if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dst_ifindex = if_nametoindex(optarg);
|
||||
if (!dst_ifindex) {
|
||||
perror("dst if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
@@ -766,7 +774,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
uid = strtoul(optarg, (char **)NULL, 16);
|
||||
uid = strtoul(optarg, NULL, 16);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
+4
-8
@@ -145,9 +145,7 @@ int idx2dindex(int ifidx, int socket)
|
||||
|
||||
strcpy(devname[i], ifr.ifr_name);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("new index %d (%s)\n", i, devname[i]);
|
||||
#endif
|
||||
pr_debug("new index %d (%s)\n", i, devname[i]);
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -310,11 +308,9 @@ int main(int argc, char **argv)
|
||||
|
||||
for (i=0; i<currmax; i++) {
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("open %d '%s' m%08X v%08X i%d e%d.\n",
|
||||
i, argv[optind+i], mask[i], value[i],
|
||||
inv_filter[i], err_mask[i]);
|
||||
#endif
|
||||
pr_debug("open %d '%s' m%08X v%08X i%d e%d.\n",
|
||||
i, argv[optind+i], mask[i], value[i],
|
||||
inv_filter[i], err_mask[i]);
|
||||
|
||||
if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
||||
perror("socket");
|
||||
|
||||
+15
-1
@@ -89,6 +89,8 @@ void print_usage(char *prg)
|
||||
"send frames immediately)\n");
|
||||
fprintf(stderr, " -i (interactive - wait "
|
||||
"for ENTER key to process next frame)\n");
|
||||
fprintf(stderr, " -n <count> (terminate after "
|
||||
"processing <count> CAN frames)\n");
|
||||
fprintf(stderr, " -g <ms> (gap in milli "
|
||||
"seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||
fprintf(stderr, " -s <s> (skip gaps in "
|
||||
@@ -247,6 +249,7 @@ int main(int argc, char **argv)
|
||||
unsigned long gap = DEFAULT_GAP;
|
||||
int use_timestamps = 1;
|
||||
int interactive = 0; /* wait for ENTER keypress to process next frame */
|
||||
int count = 0; /* end replay after sending count frames. 0 = disabled */
|
||||
static int verbose, opt, delay_loops;
|
||||
static unsigned long skipgap;
|
||||
static int loopback_disable = 0;
|
||||
@@ -257,7 +260,7 @@ int main(int argc, char **argv)
|
||||
int eof, txmtu, i, j;
|
||||
char *fret;
|
||||
|
||||
while ((opt = getopt(argc, argv, "I:l:tig:s:xv?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "I:l:tin:g:s:xv?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'I':
|
||||
infile = fopen(optarg, "r");
|
||||
@@ -285,6 +288,14 @@ int main(int argc, char **argv)
|
||||
interactive = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
count = atoi(optarg);
|
||||
if (count < 1) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
gap = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
@@ -476,6 +487,9 @@ int main(int argc, char **argv)
|
||||
else
|
||||
fprint_long_canframe(stdout, &frame, "\n", CANLIB_VIEW_INDENT_SFF, CANFD_MAX_DLEN);
|
||||
}
|
||||
|
||||
if (count && (--count == 0))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read next non-comment frame from logfile */
|
||||
|
||||
+13
-9
@@ -92,7 +92,7 @@ static void do_receive()
|
||||
unsigned int sequence_wrap = 0;
|
||||
uint32_t sequence_mask = 0xff;
|
||||
uint32_t sequence_rx = 0;
|
||||
uint32_t sequence_delta = 0;
|
||||
uint8_t sequence_delta = 0;
|
||||
uint32_t sequence = 0;
|
||||
unsigned int overflow_old = 0;
|
||||
can_err_mask_t err_mask = CAN_ERR_MASK;
|
||||
@@ -143,7 +143,7 @@ static void do_receive()
|
||||
sequence = sequence_rx;
|
||||
}
|
||||
|
||||
sequence_delta = (sequence_rx - sequence) & sequence_mask;
|
||||
sequence_delta = sequence_rx - (uint8_t)sequence;
|
||||
if (sequence_delta) {
|
||||
struct cmsghdr *cmsg;
|
||||
uint32_t overflow = 0;
|
||||
@@ -163,12 +163,16 @@ static void do_receive()
|
||||
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);
|
||||
"sequence CNT: 0x%07x RX: 0x%02x expected: 0x%02x missing: %4u skt overflow delta: %4u absolute: %4u hw - skt: %5d incident: %4u %s%s\n",
|
||||
sequence, sequence_rx, /* CNT, RX */
|
||||
sequence & sequence_mask, sequence_delta, /* expected, missing */
|
||||
overflow_delta, overflow, /* skb overflow delta, absolute */
|
||||
sequence_delta - overflow_delta, /* hw - skb */
|
||||
drop_count, /* incident */
|
||||
overflow_delta ? "[SOCKET]" : "",
|
||||
overflow_delta != sequence_delta ?
|
||||
((overflow_delta - sequence_delta > 0 && (overflow_delta - sequence_delta) & 0xff) ?
|
||||
"[HARDWARE]" : "[HARDWARE?]") : "");
|
||||
|
||||
if (drop_count == drop_until_quit)
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -216,7 +220,7 @@ static void do_send()
|
||||
}
|
||||
|
||||
err = poll(fds, 1, 1000);
|
||||
if (err == -1 && errno != -EINTR) {
|
||||
if (err == 0 || (err == -1 && errno != -EINTR)) {
|
||||
perror("poll()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+230
-116
@@ -69,9 +69,16 @@
|
||||
#include "terminal.h"
|
||||
|
||||
#define SETFNAME "sniffset."
|
||||
#define SETFDFNAME "sniffset_fd."
|
||||
#define FNAME_MAX_LEN 40
|
||||
|
||||
#define ANYDEV "any"
|
||||
#define MAX_SLOTS 2048
|
||||
|
||||
#define CANFD_OFF 0 /* set to OFF */
|
||||
#define CANFD_ON 1 /* set to ON */
|
||||
#define CANFD_AUTO 2 /* unspecified => check for first received frame */
|
||||
|
||||
/* flags */
|
||||
|
||||
#define ENABLE 1 /* by filter or user */
|
||||
@@ -98,16 +105,19 @@
|
||||
#define LDL " | " /* long delimiter */
|
||||
#define SDL "|" /* short delimiter for binary on 80 chars terminal */
|
||||
|
||||
#define CC_SEP '#' /* interface name separator for Classical CAN */
|
||||
#define FD_SEP '*' /* interface name separator for CAN FD */
|
||||
|
||||
static struct snif {
|
||||
int flags;
|
||||
long hold;
|
||||
long timeout;
|
||||
struct timeval laststamp;
|
||||
struct timeval currstamp;
|
||||
struct can_frame last;
|
||||
struct can_frame current;
|
||||
struct can_frame marker;
|
||||
struct can_frame notch;
|
||||
struct canfd_frame last;
|
||||
struct canfd_frame current;
|
||||
struct canfd_frame marker;
|
||||
struct canfd_frame notch;
|
||||
} sniftab[MAX_SLOTS];
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
@@ -116,14 +126,18 @@ static int idx;
|
||||
static int running = 1;
|
||||
static int clearscreen = 1;
|
||||
static int print_eff;
|
||||
static int print_ascii = 1;
|
||||
static int notch;
|
||||
static int max_dlen = CAN_MAX_DLEN;
|
||||
static long timeout = TIMEOUT;
|
||||
static long hold = HOLD;
|
||||
static long loop = LOOP;
|
||||
static long canfd_mode = CANFD_AUTO;
|
||||
static unsigned char binary;
|
||||
static unsigned char binary8;
|
||||
static unsigned char binary_gap;
|
||||
static unsigned char color;
|
||||
static unsigned char name_sep = CC_SEP;
|
||||
static char *interface;
|
||||
static char *vdl = LDL; /* variable delimiter */
|
||||
static char *ldl = LDL; /* long delimiter */
|
||||
@@ -132,7 +146,7 @@ void print_snifline(int slot);
|
||||
int handle_keyb(void);
|
||||
int handle_frame(int fd, long currcms);
|
||||
int handle_timeo(long currcms);
|
||||
void writesettings(char* name);
|
||||
int writesettings(char* name);
|
||||
int readsettings(char* name);
|
||||
int sniftab_index(canid_t id);
|
||||
|
||||
@@ -166,6 +180,7 @@ void print_usage(char *prg)
|
||||
" 8<ENTER> - toggle binary / HEX-ASCII output (small for EFF on 80 chars)\n"
|
||||
" B<ENTER> - toggle binary with gap / HEX-ASCII output (exceeds 80 chars!)\n"
|
||||
" c<ENTER> - toggle color mode\n"
|
||||
" @<ENTER> - toggle ASCII output (disabled for CAN FD by default)\n"
|
||||
" <SPACE><ENTER> - force a clear screen\n"
|
||||
" #<ENTER> - notch currently marked/changed bits (can be used repeatedly)\n"
|
||||
" *<ENTER> - clear notched marked\n"
|
||||
@@ -215,6 +230,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " -8 (start with binary mode - for EFF on 80 chars)\n");
|
||||
fprintf(stderr, " -B (start with binary mode with gap - exceeds 80 chars!)\n");
|
||||
fprintf(stderr, " -c (color changes)\n");
|
||||
fprintf(stderr, " -f <mode> (CAN FD mode: 0 = OFF, 1 = ON, 2 = auto detect, default: %d)\n", CANFD_AUTO);
|
||||
fprintf(stderr, " -t <time> (timeout for ID display [x10ms] default: %d, 0 = OFF)\n", TIMEOUT);
|
||||
fprintf(stderr, " -h <time> (hold marker on changes [x10ms] default: %d)\n", HOLD);
|
||||
fprintf(stderr, " -l <time> (loop time (display) [x10ms] default: %d)\n", LOOP);
|
||||
@@ -236,7 +252,7 @@ int main(int argc, char **argv)
|
||||
long currcms = 0;
|
||||
long lastcms = 0;
|
||||
unsigned char quiet = 0;
|
||||
int opt, ret;
|
||||
int opt, ret = 0;
|
||||
struct timeval timeo, start_tv, tv;
|
||||
struct sockaddr_can addr;
|
||||
int i;
|
||||
@@ -248,7 +264,7 @@ int main(int argc, char **argv)
|
||||
for (i = 0; i < MAX_SLOTS ;i++) /* default: enable all slots */
|
||||
do_set(i, ENABLE);
|
||||
|
||||
while ((opt = getopt(argc, argv, "r:t:h:l:qeb8Bc?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "r:t:h:l:f:qeb8Bc?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'r':
|
||||
if (readsettings(optarg) < 0) {
|
||||
@@ -269,6 +285,12 @@ int main(int argc, char **argv)
|
||||
sscanf(optarg, "%ld", &loop);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
sscanf(optarg, "%ld", &canfd_mode);
|
||||
if ((canfd_mode != CANFD_ON) && (canfd_mode != CANFD_OFF))
|
||||
canfd_mode = CANFD_AUTO;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
@@ -313,7 +335,7 @@ int main(int argc, char **argv)
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
if (quiet)
|
||||
for (i = 0; i < MAX_SLOTS; i++)
|
||||
do_clr(i, ENABLE);
|
||||
@@ -332,15 +354,38 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = 0; /* 'any' CAN interface */
|
||||
|
||||
if (strcmp(ANYDEV, argv[optind]) != 0)
|
||||
/* check for specific CAN interface */
|
||||
if (strcmp(ANYDEV, argv[optind]) != 0) {
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
else
|
||||
addr.can_ifindex = 0; /* any can interface */
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("connect");
|
||||
return 1;
|
||||
/* enable CAN FD if not disabled by command line option */
|
||||
if (canfd_mode != CANFD_OFF) {
|
||||
const int enable_canfd = 1;
|
||||
|
||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||
&enable_canfd, sizeof(enable_canfd))){
|
||||
printf("error when enabling CAN FD support\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* might be changed in CANFD_AUTO mode */
|
||||
max_dlen = CANFD_MAX_DLEN;
|
||||
name_sep = FD_SEP;
|
||||
print_ascii = 0; /* don't print ASCII for CAN FD by default */
|
||||
}
|
||||
|
||||
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
close(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gettimeofday(&start_tv, NULL);
|
||||
@@ -357,11 +402,13 @@ int main(int argc, char **argv)
|
||||
timeo.tv_sec = 0;
|
||||
timeo.tv_usec = 10000 * loop;
|
||||
|
||||
if ((ret = select(s+1, &rdfs, NULL, NULL, &timeo)) < 0) {
|
||||
ret = select(s+1, &rdfs, NULL, NULL, &timeo);
|
||||
if (ret < 0) {
|
||||
//perror("select");
|
||||
running = 0;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
currcms = (tv.tv_sec - start_tv.tv_sec) * 100 + (tv.tv_usec / 10000);
|
||||
@@ -381,7 +428,7 @@ int main(int argc, char **argv)
|
||||
printf("%s", CSR_SHOW); /* show cursor */
|
||||
|
||||
close(s);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void do_modify_sniftab(unsigned int value, unsigned int mask, char cmd)
|
||||
@@ -436,7 +483,7 @@ int handle_keyb(void)
|
||||
}
|
||||
|
||||
/* check for single SFF/EFF CAN ID length */
|
||||
if (!((clen == 3) || (clen == 8)))
|
||||
if (clen != 3 && clen != 8)
|
||||
break;
|
||||
|
||||
/* enable/disable single SFF/EFF CAN ID */
|
||||
@@ -480,17 +527,24 @@ int handle_keyb(void)
|
||||
break;
|
||||
|
||||
case 'w' :
|
||||
writesettings(&cmd[1]);
|
||||
if (writesettings(&cmd[1]))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'r' :
|
||||
readsettings(&cmd[1]); /* don't care about success */
|
||||
if (readsettings(&cmd[1]) < 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 'q' :
|
||||
running = 0;
|
||||
break;
|
||||
|
||||
case '@' :
|
||||
/* toggle ASCII output */
|
||||
print_ascii ^= 1;
|
||||
break;
|
||||
|
||||
case 'B' :
|
||||
binary_gap = 1;
|
||||
switchvdl(LDL);
|
||||
@@ -534,7 +588,7 @@ int handle_keyb(void)
|
||||
|
||||
case '*' :
|
||||
for (i = 0; i < idx; i++)
|
||||
memset(&sniftab[i].notch.data, 0, 8);
|
||||
memset(&sniftab[i].notch.data, 0, max_dlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -551,18 +605,40 @@ int handle_frame(int fd, long currcms)
|
||||
bool rx_changed = false;
|
||||
bool run_qsort = false;
|
||||
int nbytes, i, pos;
|
||||
struct can_frame cf;
|
||||
struct canfd_frame cf;
|
||||
|
||||
if ((nbytes = read(fd, &cf, sizeof(cf))) < 0) {
|
||||
nbytes = read(fd, &cf, sizeof(cf));
|
||||
if (nbytes < 0) {
|
||||
perror("raw read");
|
||||
return 0; /* quit */
|
||||
}
|
||||
|
||||
if (nbytes != CAN_MTU) {
|
||||
if ((nbytes != CAN_MTU) && (nbytes != CANFD_MTU)) {
|
||||
printf("received strange frame data length %d!\n", nbytes);
|
||||
return 0; /* quit */
|
||||
}
|
||||
|
||||
/* CAN FD auto mode: switch based on first reception */
|
||||
if (canfd_mode == CANFD_AUTO) {
|
||||
if (nbytes == CAN_MTU) {
|
||||
canfd_mode = CANFD_OFF;
|
||||
/* change back auto defaults for Classical CAN */
|
||||
max_dlen = CAN_MAX_DLEN;
|
||||
name_sep = CC_SEP;
|
||||
print_ascii = 1;
|
||||
} else {
|
||||
canfd_mode = CANFD_ON;
|
||||
}
|
||||
}
|
||||
|
||||
/* filter for Classical CAN */
|
||||
if ((canfd_mode == CANFD_OFF) && (nbytes == CANFD_MTU))
|
||||
return 1; /* skip handling */
|
||||
|
||||
/* filter for CAN FD */
|
||||
if ((canfd_mode == CANFD_ON) && (nbytes == CAN_MTU))
|
||||
return 1; /* skip handling */
|
||||
|
||||
if (!print_eff && (cf.can_id & CAN_EFF_FLAG)) {
|
||||
print_eff = 1;
|
||||
clearscreen = 1;
|
||||
@@ -571,20 +647,19 @@ int handle_frame(int fd, long currcms)
|
||||
pos = sniftab_index(cf.can_id);
|
||||
if (pos < 0) {
|
||||
/* CAN ID not existing */
|
||||
if (idx < MAX_SLOTS) {
|
||||
/* assign new slot */
|
||||
pos = idx++;
|
||||
rx_changed = true;
|
||||
run_qsort = true;
|
||||
} else {
|
||||
if (idx >= MAX_SLOTS) {
|
||||
/* informative exit */
|
||||
perror("number of different CAN IDs exceeded MAX_SLOTS");
|
||||
return 0; /* quit */
|
||||
}
|
||||
/* assign new slot */
|
||||
pos = idx++;
|
||||
rx_changed = true;
|
||||
run_qsort = true;
|
||||
}
|
||||
else {
|
||||
if (cf.can_dlc == sniftab[pos].current.can_dlc)
|
||||
for (i = 0; i < cf.can_dlc; i++) {
|
||||
if (cf.len == sniftab[pos].current.len)
|
||||
for (i = 0; i < cf.len; i++) {
|
||||
if (cf.data[i] != sniftab[pos].current.data[i] ) {
|
||||
rx_changed = true;
|
||||
break;
|
||||
@@ -603,7 +678,7 @@ int handle_frame(int fd, long currcms)
|
||||
ioctl(fd, SIOCGSTAMP, &sniftab[pos].currstamp);
|
||||
|
||||
sniftab[pos].current = cf;
|
||||
for (i = 0; i < 8; i++)
|
||||
for (i = 0; i < max_dlen; i++)
|
||||
sniftab[pos].marker.data[i] |= sniftab[pos].current.data[i] ^ sniftab[pos].last.data[i];
|
||||
|
||||
sniftab[pos].timeout = (timeout)?(currcms + timeout):0;
|
||||
@@ -629,11 +704,11 @@ int handle_timeo(long currcms)
|
||||
|
||||
if (clearscreen) {
|
||||
if (print_eff)
|
||||
printf("%s%sXX|ms%s-- ID --%sdata ... < %s # l=%ld h=%ld t=%ld slots=%d >",
|
||||
CLR_SCREEN, CSR_HOME, vdl, vdl, interface, loop, hold, timeout, idx);
|
||||
printf("%s%sXX|ms%s-- ID --%sdata ... < %s %c l=%ld h=%ld t=%ld slots=%d >",
|
||||
CLR_SCREEN, CSR_HOME, vdl, vdl, interface, name_sep, loop, hold, timeout, idx);
|
||||
else
|
||||
printf("%s%sXX|ms%sID %sdata ... < %s # l=%ld h=%ld t=%ld slots=%d >",
|
||||
CLR_SCREEN, CSR_HOME, ldl, ldl, interface, loop, hold, timeout, idx);
|
||||
printf("%s%sXX|ms%sID %sdata ... < %s %c l=%ld h=%ld t=%ld slots=%d >",
|
||||
CLR_SCREEN, CSR_HOME, ldl, ldl, interface, name_sep, loop, hold, timeout, idx);
|
||||
|
||||
force_redraw = 1;
|
||||
clearscreen = 0;
|
||||
@@ -641,7 +716,7 @@ int handle_timeo(long currcms)
|
||||
|
||||
if (notch) {
|
||||
for (i = 0; i < idx; i++) {
|
||||
for (j = 0; j < 8; j++)
|
||||
for (j = 0; j < max_dlen; j++)
|
||||
sniftab[i].notch.data[j] |= sniftab[i].marker.data[j];
|
||||
}
|
||||
notch = 0;
|
||||
@@ -660,7 +735,7 @@ int handle_timeo(long currcms)
|
||||
do_clr(i, UPDATE);
|
||||
}
|
||||
else if ((sniftab[i].hold) && (sniftab[i].hold < currcms)) {
|
||||
memset(&sniftab[i].marker.data, 0, 8);
|
||||
memset(&sniftab[i].marker.data, 0, max_dlen);
|
||||
print_snifline(i);
|
||||
sniftab[i].hold = 0; /* disable update by hold */
|
||||
}
|
||||
@@ -684,7 +759,7 @@ void print_snifline(int slot)
|
||||
{
|
||||
long diffsec = sniftab[slot].currstamp.tv_sec - sniftab[slot].laststamp.tv_sec;
|
||||
long diffusec = sniftab[slot].currstamp.tv_usec - sniftab[slot].laststamp.tv_usec;
|
||||
int dlc_diff = sniftab[slot].last.can_dlc - sniftab[slot].current.can_dlc;
|
||||
int dlc_diff = sniftab[slot].last.len - sniftab[slot].current.len;
|
||||
canid_t cid = sniftab[slot].current.can_id;
|
||||
int i,j;
|
||||
|
||||
@@ -705,7 +780,7 @@ void print_snifline(int slot)
|
||||
printf("%02ld%03ld%s%03X%s", diffsec, diffusec/1000, ldl, cid & CAN_SFF_MASK, ldl);
|
||||
|
||||
if (binary) {
|
||||
for (i = 0; i < sniftab[slot].current.can_dlc; i++) {
|
||||
for (i = 0; i < sniftab[slot].current.len; i++) {
|
||||
for (j=7; j >= 0; j--) {
|
||||
if ((color) && (sniftab[slot].marker.data[i] & 1<<j) &&
|
||||
(!(sniftab[slot].notch.data[i] & 1<<j)))
|
||||
@@ -724,7 +799,7 @@ void print_snifline(int slot)
|
||||
}
|
||||
|
||||
/*
|
||||
* when the can_dlc decreased (dlc_diff > 0),
|
||||
* when the len decreased (dlc_diff > 0),
|
||||
* we need to blank the former data printout
|
||||
*/
|
||||
for (i = 0; i < dlc_diff; i++) {
|
||||
@@ -732,111 +807,150 @@ void print_snifline(int slot)
|
||||
if (binary_gap)
|
||||
putchar(' ');
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < sniftab[slot].current.can_dlc; i++)
|
||||
|
||||
} else { /* not binary -> hex data and ASCII output */
|
||||
|
||||
for (i = 0; i < sniftab[slot].current.len; i++)
|
||||
if ((color) && (sniftab[slot].marker.data[i] & ~sniftab[slot].notch.data[i]))
|
||||
printf("%s%02X%s ", ATTCOLOR, sniftab[slot].current.data[i], ATTRESET);
|
||||
else
|
||||
printf("%02X ", sniftab[slot].current.data[i]);
|
||||
|
||||
if (sniftab[slot].current.can_dlc < 8)
|
||||
printf("%*s", (8 - sniftab[slot].current.can_dlc) * 3, "");
|
||||
if (print_ascii) {
|
||||
/* jump to common start for ASCII output */
|
||||
if (sniftab[slot].current.len < max_dlen)
|
||||
printf("%*s", (max_dlen - sniftab[slot].current.len) * 3, "");
|
||||
|
||||
for (i = 0; i<sniftab[slot].current.can_dlc; i++)
|
||||
if ((sniftab[slot].current.data[i] > 0x1F) &&
|
||||
(sniftab[slot].current.data[i] < 0x7F))
|
||||
if ((color) && (sniftab[slot].marker.data[i] & ~sniftab[slot].notch.data[i]))
|
||||
printf("%s%c%s", ATTCOLOR, sniftab[slot].current.data[i], ATTRESET);
|
||||
for (i = 0; i < sniftab[slot].current.len; i++)
|
||||
if ((sniftab[slot].current.data[i] > 0x1F) &&
|
||||
(sniftab[slot].current.data[i] < 0x7F))
|
||||
if ((color) && (sniftab[slot].marker.data[i] & ~sniftab[slot].notch.data[i]))
|
||||
printf("%s%c%s", ATTCOLOR, sniftab[slot].current.data[i], ATTRESET);
|
||||
else
|
||||
putchar(sniftab[slot].current.data[i]);
|
||||
else
|
||||
putchar(sniftab[slot].current.data[i]);
|
||||
else
|
||||
putchar('.');
|
||||
putchar('.');
|
||||
|
||||
/*
|
||||
* when the can_dlc decreased (dlc_diff > 0),
|
||||
* we need to blank the former data printout
|
||||
*/
|
||||
for (i = 0; i < dlc_diff; i++)
|
||||
putchar(' ');
|
||||
/*
|
||||
* when the len decreased (dlc_diff > 0),
|
||||
* we need to blank the former data printout
|
||||
*/
|
||||
for (i = 0; i < dlc_diff; i++)
|
||||
putchar(' ');
|
||||
} else {
|
||||
/*
|
||||
* when the len decreased (dlc_diff > 0),
|
||||
* we need to blank the former data printout
|
||||
*/
|
||||
for (i = 0; i < dlc_diff; i++)
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
|
||||
memset(&sniftab[slot].marker.data, 0, 8);
|
||||
memset(&sniftab[slot].marker.data, 0, max_dlen);
|
||||
}
|
||||
|
||||
void writesettings(char* name)
|
||||
int writesettings(char* name)
|
||||
{
|
||||
int fd;
|
||||
char fname[30] = SETFNAME;
|
||||
char fname[FNAME_MAX_LEN + 1];
|
||||
int i,j;
|
||||
char buf[13]= {0};
|
||||
|
||||
strncat(fname, name, 29 - strlen(fname));
|
||||
fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
|
||||
if (fd > 0) {
|
||||
for (i = 0; i < idx ;i++) {
|
||||
sprintf(buf, "<%08X>%c.", sniftab[i].current.can_id, (is_set(i, ENABLE))?'1':'0');
|
||||
if (write(fd, buf, 12) < 0)
|
||||
perror("write");
|
||||
for (j = 0; j < 8 ; j++) {
|
||||
sprintf(buf, "%02X", sniftab[i].notch.data[j]);
|
||||
if (write(fd, buf, 2) < 0)
|
||||
perror("write");
|
||||
}
|
||||
if (write(fd, "\n", 1) < 0)
|
||||
perror("write");
|
||||
/* 12 + 16 + 1 = 29 bytes per entry */
|
||||
}
|
||||
close(fd);
|
||||
if (canfd_mode == CANFD_OFF)
|
||||
strcpy(fname, SETFNAME);
|
||||
else if (canfd_mode == CANFD_ON)
|
||||
strcpy(fname, SETFDFNAME);
|
||||
else {
|
||||
printf("writesettings failed due to unspecified CAN FD mode\n");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
||||
strncat(fname, name, FNAME_MAX_LEN - strlen(fname));
|
||||
fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (fd <= 0) {
|
||||
printf("unable to write setting file '%s'!\n", fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < idx ;i++) {
|
||||
sprintf(buf, "<%08X>%c.", sniftab[i].current.can_id, (is_set(i, ENABLE))?'1':'0');
|
||||
if (write(fd, buf, 12) < 0) {
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
for (j = 0; j < max_dlen ; j++) {
|
||||
sprintf(buf, "%02X", sniftab[i].notch.data[j]);
|
||||
if (write(fd, buf, 2) < 0) {
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (write(fd, "\n", 1) < 0) {
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
/* Classical CAN: 12 + 16 + 1 = 29 bytes per entry */
|
||||
/* CAN FD: 12 + 128 + 1 = 141 bytes per entry */
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readsettings(char* name)
|
||||
{
|
||||
int fd;
|
||||
char fname[30] = SETFNAME;
|
||||
char buf[30] = {0};
|
||||
char fname[FNAME_MAX_LEN + 1];
|
||||
char buf[142] = {0};
|
||||
int entrylen;
|
||||
int j;
|
||||
bool done = false;
|
||||
|
||||
strncat(fname, name, 29 - strlen(fname));
|
||||
fd = open(fname, O_RDONLY);
|
||||
|
||||
if (fd > 0) {
|
||||
idx = 0;
|
||||
while (!done) {
|
||||
if (read(fd, &buf, 29) == 29) {
|
||||
unsigned long id = strtoul(&buf[1], (char **)NULL, 16);
|
||||
|
||||
sniftab[idx].current.can_id = id;
|
||||
|
||||
if (buf[10] & 1)
|
||||
do_set(idx, ENABLE);
|
||||
else
|
||||
do_clr(idx, ENABLE);
|
||||
|
||||
for (j = 7; j >= 0 ; j--) {
|
||||
sniftab[idx].notch.data[j] =
|
||||
(__u8) strtoul(&buf[2*j+12], (char **)NULL, 16) & 0xFF;
|
||||
buf[2*j+12] = 0; /* cut off each time */
|
||||
}
|
||||
|
||||
if (++idx >= MAX_SLOTS)
|
||||
break;
|
||||
}
|
||||
else
|
||||
done = true;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
if (canfd_mode == CANFD_OFF) {
|
||||
entrylen = 29;
|
||||
strcpy(fname, SETFNAME);
|
||||
} else if (canfd_mode == CANFD_ON) {
|
||||
entrylen = 141;
|
||||
strcpy(fname, SETFDFNAME);
|
||||
} else {
|
||||
printf("readsettings failed due to unspecified CAN FD mode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncat(fname, name, FNAME_MAX_LEN - strlen(fname));
|
||||
fd = open(fname, O_RDONLY);
|
||||
|
||||
if (fd <= 0) {
|
||||
return -1;
|
||||
}
|
||||
idx = 0;
|
||||
while (!done) {
|
||||
if (read(fd, &buf, entrylen) != entrylen) {
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
unsigned long id = strtoul(&buf[1], NULL, 16);
|
||||
|
||||
sniftab[idx].current.can_id = id;
|
||||
|
||||
if (buf[10] & 1)
|
||||
do_set(idx, ENABLE);
|
||||
else
|
||||
do_clr(idx, ENABLE);
|
||||
|
||||
for (j = max_dlen - 1; j >= 0 ; j--) {
|
||||
sniftab[idx].notch.data[j] =
|
||||
(__u8) strtoul(&buf[2*j+12], NULL, 16) & 0xFF;
|
||||
buf[2*j+12] = 0; /* cut off each time */
|
||||
}
|
||||
|
||||
if (++idx >= MAX_SLOTS)
|
||||
break;
|
||||
|
||||
}
|
||||
close(fd);
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
+25
-6
@@ -9,6 +9,9 @@ AC_CONFIG_AUX_DIR([config/autoconf])
|
||||
AC_CANONICAL_BUILD
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
# If possible, enable extensions to Posix
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
#AM_MAINTAINER_MODE
|
||||
|
||||
CFLAGS="${CFLAGS} -Wall"
|
||||
@@ -77,21 +80,37 @@ AC_CHECK_FUNCS([ \
|
||||
AC_SEARCH_LIBS([clock_nanosleep], [rt])
|
||||
|
||||
AC_CHECK_DECL(SO_RXQ_OVFL,,
|
||||
[AC_DEFINE([SO_RXQ_OVFL], [40], [SO_RXQ_OVFL])]
|
||||
[AC_DEFINE([SO_RXQ_OVFL], [40], [SO_RXQ_OVFL])],
|
||||
[[#include <linux/net.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(PF_CAN,,
|
||||
[AC_DEFINE([PF_CAN], [29], [PF_CAN])]
|
||||
[AC_DEFINE([PF_CAN], [29], [PF_CAN])],
|
||||
[[#include <net/if.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(AF_CAN,,
|
||||
[AC_DEFINE([AF_CAN], [PF_CAN], [AF_CAN])]
|
||||
[AC_DEFINE([AF_CAN], [PF_CAN], [AF_CAN])],
|
||||
[[#include <net/if.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(N_SLCAN,,
|
||||
[AC_DEFINE([N_SLCAN], [17], [N_SLCAN])]
|
||||
[AC_DEFINE([N_SLCAN], [17], [N_SLCAN])],
|
||||
[[#include <linux/tty.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(SCM_TIMESTAMPING_OPT_STATS,,
|
||||
[AC_DEFINE([SCM_TIMESTAMPING_OPT_STATS], [54], [SCM_TIMESTAMPING_OPT_STATS])]
|
||||
[AC_DEFINE([SCM_TIMESTAMPING_OPT_STATS], [54], [SCM_TIMESTAMPING_OPT_STATS])],
|
||||
[[#include <linux/net.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(CLOCK_TAI,,
|
||||
[AC_DEFINE([CLOCK_TAI], [11], [CLOCK_TAI])],
|
||||
[[#include <time.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(SO_TXTIME,,
|
||||
[AC_DEFINE([SO_TXTIME], [61], [SO_TXTIME])],
|
||||
[[#include <sys/socket.h>]]
|
||||
)
|
||||
AC_CHECK_DECL(SCM_TXTIME,,
|
||||
[AC_DEFINE([SCM_TXTIME], [SO_TXTIME], [SCM_TXTIME])],
|
||||
[[#include <sys/socket.h>]]
|
||||
)
|
||||
AC_DEFINE(_GNU_SOURCE)
|
||||
|
||||
|
||||
#
|
||||
|
||||
+53
-2
@@ -48,6 +48,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/stddef.h> /* for offsetof */
|
||||
|
||||
/* controller area network (CAN) kernel definitions */
|
||||
|
||||
@@ -60,6 +61,7 @@
|
||||
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
|
||||
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
|
||||
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
|
||||
#define CANXL_PRIO_MASK CAN_SFF_MASK /* 11 bit priority mask */
|
||||
|
||||
/*
|
||||
* Controller Area Network Identifier structure
|
||||
@@ -73,6 +75,7 @@ typedef __u32 canid_t;
|
||||
|
||||
#define CAN_SFF_ID_BITS 11
|
||||
#define CAN_EFF_ID_BITS 29
|
||||
#define CANXL_PRIO_BITS CAN_SFF_ID_BITS
|
||||
|
||||
/*
|
||||
* Controller Area Network Error Message Frame Mask structure
|
||||
@@ -91,6 +94,16 @@ typedef __u32 can_err_mask_t;
|
||||
#define CANFD_MAX_DLC 15
|
||||
#define CANFD_MAX_DLEN 64
|
||||
|
||||
/*
|
||||
* CAN XL payload length and DLC definitions according to ISO 11898-1
|
||||
* CAN XL DLC ranges from 0 .. 2047 => data length from 1 .. 2048 byte
|
||||
*/
|
||||
#define CANXL_MIN_DLC 0
|
||||
#define CANXL_MAX_DLC 2047
|
||||
#define CANXL_MAX_DLC_MASK 0x07FF
|
||||
#define CANXL_MIN_DLEN 1
|
||||
#define CANXL_MAX_DLEN 2048
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -141,8 +154,8 @@ struct can_frame {
|
||||
* 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.
|
||||
* Since the introduction of CAN XL the CANFD_FDF flag is set in all CAN FD
|
||||
* frame structures provided by the CAN subsystem of the Linux kernel.
|
||||
*/
|
||||
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
|
||||
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
|
||||
@@ -166,8 +179,46 @@ struct canfd_frame {
|
||||
__u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
* defined bits for canxl_frame.flags
|
||||
*
|
||||
* The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
|
||||
* and shares the relative position of the struct can[fd]_frame.len element.
|
||||
* The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
|
||||
* As a side effect setting this bit intentionally breaks the length checks
|
||||
* for Classical CAN and CAN FD frames.
|
||||
*
|
||||
* Undefined bits in canxl_frame.flags are reserved and shall be set to zero.
|
||||
*/
|
||||
#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
|
||||
#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
|
||||
|
||||
/**
|
||||
* struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure
|
||||
* @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags
|
||||
* @flags: additional flags for CAN XL
|
||||
* @sdt: SDU (service data unit) type
|
||||
* @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN)
|
||||
* @af: acceptance field
|
||||
* @data: CAN XL frame payload (CANXL_MIN_DLEN .. CANXL_MAX_DLEN byte)
|
||||
*
|
||||
* @prio shares the same position as @can_id from struct can[fd]_frame.
|
||||
*/
|
||||
struct canxl_frame {
|
||||
canid_t prio; /* 11 bit priority for arbitration (canid_t) */
|
||||
__u8 flags; /* additional flags for CAN XL */
|
||||
__u8 sdt; /* SDU (service data unit) type */
|
||||
__u16 len; /* frame payload length in byte */
|
||||
__u32 af; /* acceptance field */
|
||||
__u8 data[CANXL_MAX_DLEN];
|
||||
};
|
||||
|
||||
#define CAN_MTU (sizeof(struct can_frame))
|
||||
#define CANFD_MTU (sizeof(struct canfd_frame))
|
||||
#define CANXL_MTU (sizeof(struct canxl_frame))
|
||||
#define CANXL_HDR_SIZE (offsetof(struct canxl_frame, data))
|
||||
#define CANXL_MIN_MTU (CANXL_HDR_SIZE + 64)
|
||||
#define CANXL_MAX_MTU CANXL_MTU
|
||||
|
||||
/* particular protocols of the protocol family PF_CAN */
|
||||
#define CAN_RAW 1 /* RAW sockets */
|
||||
|
||||
@@ -71,7 +71,7 @@ struct bcm_msg_head {
|
||||
struct bcm_timeval ival1, ival2;
|
||||
canid_t can_id;
|
||||
__u32 nframes;
|
||||
struct can_frame frames[0];
|
||||
struct can_frame frames[];
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
#define CAN_ERR_BUSOFF 0x00000040U /* bus off */
|
||||
#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */
|
||||
#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */
|
||||
#define CAN_ERR_CNT 0x00000200U /* TX error counter / data[6] */
|
||||
/* RX error counter / data[7] */
|
||||
|
||||
/* arbitration lost in bit ... / data[0] */
|
||||
#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */
|
||||
@@ -120,6 +122,22 @@
|
||||
#define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */
|
||||
#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */
|
||||
|
||||
/* controller specific additional information / data[5..7] */
|
||||
/* data[5] is reserved (do not use) */
|
||||
|
||||
/* TX error counter / data[6] */
|
||||
/* RX error counter / data[7] */
|
||||
|
||||
/* CAN state thresholds
|
||||
*
|
||||
* Error counter Error state
|
||||
* -----------------------------------
|
||||
* 0 - 95 Error-active
|
||||
* 96 - 127 Error-warning
|
||||
* 128 - 255 Error-passive
|
||||
* 256 and greater Bus-off
|
||||
*/
|
||||
#define CAN_ERROR_WARNING_THRESHOLD 96
|
||||
#define CAN_ERROR_PASSIVE_THRESHOLD 128
|
||||
#define CAN_BUS_OFF_THRESHOLD 256
|
||||
|
||||
#endif /* _UAPI_CAN_ERROR_H */
|
||||
|
||||
+35
-18
@@ -124,33 +124,30 @@ struct can_isotp_ll_options {
|
||||
|
||||
/* flags for isotp behaviour */
|
||||
|
||||
#define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */
|
||||
#define CAN_ISOTP_EXTEND_ADDR 0x002 /* enable extended addressing */
|
||||
#define CAN_ISOTP_TX_PADDING 0x004 /* enable CAN frame padding tx path */
|
||||
#define CAN_ISOTP_RX_PADDING 0x008 /* enable CAN frame padding rx path */
|
||||
#define CAN_ISOTP_CHK_PAD_LEN 0x010 /* check received CAN frame padding */
|
||||
#define CAN_ISOTP_CHK_PAD_DATA 0x020 /* check received CAN frame padding */
|
||||
#define CAN_ISOTP_HALF_DUPLEX 0x040 /* half duplex error state handling */
|
||||
#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 */
|
||||
#define CAN_ISOTP_LISTEN_MODE 0x0001 /* listen only (do not send FC) */
|
||||
#define CAN_ISOTP_EXTEND_ADDR 0x0002 /* enable extended addressing */
|
||||
#define CAN_ISOTP_TX_PADDING 0x0004 /* enable CAN frame padding tx path */
|
||||
#define CAN_ISOTP_RX_PADDING 0x0008 /* enable CAN frame padding rx path */
|
||||
#define CAN_ISOTP_CHK_PAD_LEN 0x0010 /* check received CAN frame padding */
|
||||
#define CAN_ISOTP_CHK_PAD_DATA 0x0020 /* check received CAN frame padding */
|
||||
#define CAN_ISOTP_HALF_DUPLEX 0x0040 /* half duplex error state handling */
|
||||
#define CAN_ISOTP_FORCE_TXSTMIN 0x0080 /* ignore stmin from received FC */
|
||||
#define CAN_ISOTP_FORCE_RXSTMIN 0x0100 /* ignore CFs depending on rx stmin */
|
||||
#define CAN_ISOTP_RX_EXT_ADDR 0x0200 /* different rx extended addressing */
|
||||
#define CAN_ISOTP_WAIT_TX_DONE 0x0400 /* wait for tx completion */
|
||||
#define CAN_ISOTP_SF_BROADCAST 0x0800 /* 1-to-N functional addressing */
|
||||
#define CAN_ISOTP_CF_BROADCAST 0x1000 /* 1-to-N transmission w/o FC */
|
||||
|
||||
/* default values */
|
||||
/* protocol machine default values */
|
||||
|
||||
#define CAN_ISOTP_DEFAULT_FLAGS 0
|
||||
#define CAN_ISOTP_DEFAULT_EXT_ADDRESS 0x00
|
||||
#define CAN_ISOTP_DEFAULT_PAD_CONTENT 0xCC /* prevent bit-stuffing */
|
||||
#define CAN_ISOTP_DEFAULT_FRAME_TXTIME 0
|
||||
#define CAN_ISOTP_DEFAULT_FRAME_TXTIME 50000 /* 50 micro seconds */
|
||||
#define CAN_ISOTP_DEFAULT_RECV_BS 0
|
||||
#define CAN_ISOTP_DEFAULT_RECV_STMIN 0x00
|
||||
#define CAN_ISOTP_DEFAULT_RECV_WFTMAX 0
|
||||
|
||||
#define CAN_ISOTP_DEFAULT_LL_MTU CAN_MTU
|
||||
#define CAN_ISOTP_DEFAULT_LL_TX_DL CAN_MAX_DLEN
|
||||
#define CAN_ISOTP_DEFAULT_LL_TX_FLAGS 0
|
||||
|
||||
/*
|
||||
* Remark on CAN_ISOTP_DEFAULT_RECV_* values:
|
||||
*
|
||||
@@ -162,4 +159,24 @@ struct can_isotp_ll_options {
|
||||
* consistency and copied directly into the flow control (FC) frame.
|
||||
*/
|
||||
|
||||
/* link layer default values => make use of Classical CAN frames */
|
||||
|
||||
#define CAN_ISOTP_DEFAULT_LL_MTU CAN_MTU
|
||||
#define CAN_ISOTP_DEFAULT_LL_TX_DL CAN_MAX_DLEN
|
||||
#define CAN_ISOTP_DEFAULT_LL_TX_FLAGS 0
|
||||
|
||||
/*
|
||||
* The CAN_ISOTP_DEFAULT_FRAME_TXTIME has become a non-zero value as
|
||||
* it only makes sense for isotp implementation tests to run without
|
||||
* a N_As value. As user space applications usually do not set the
|
||||
* frame_txtime element of struct can_isotp_options the new in-kernel
|
||||
* default is very likely overwritten with zero when the sockopt()
|
||||
* CAN_ISOTP_OPTS is invoked.
|
||||
* To make sure that a N_As value of zero is only set intentional the
|
||||
* value '0' is now interpreted as 'do not change the current value'.
|
||||
* When a frame_txtime of zero is required for testing purposes this
|
||||
* CAN_ISOTP_FRAME_TXTIME_ZERO u32 value has to be set in frame_txtime.
|
||||
*/
|
||||
#define CAN_ISOTP_FRAME_TXTIME_ZERO 0xFFFFFFFF
|
||||
|
||||
#endif /* !_UAPI_CAN_ISOTP_H */
|
||||
|
||||
@@ -78,11 +78,20 @@ enum {
|
||||
enum {
|
||||
J1939_NLA_PAD,
|
||||
J1939_NLA_BYTES_ACKED,
|
||||
J1939_NLA_TOTAL_SIZE,
|
||||
J1939_NLA_PGN,
|
||||
J1939_NLA_SRC_NAME,
|
||||
J1939_NLA_DEST_NAME,
|
||||
J1939_NLA_SRC_ADDR,
|
||||
J1939_NLA_DEST_ADDR,
|
||||
};
|
||||
|
||||
enum {
|
||||
J1939_EE_INFO_NONE,
|
||||
J1939_EE_INFO_TX_ABORT,
|
||||
J1939_EE_INFO_RX_RTS,
|
||||
J1939_EE_INFO_RX_DPO,
|
||||
J1939_EE_INFO_RX_ABORT,
|
||||
};
|
||||
|
||||
struct j1939_filter {
|
||||
|
||||
@@ -101,6 +101,8 @@ struct can_ctrlmode {
|
||||
#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 */
|
||||
#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */
|
||||
#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */
|
||||
|
||||
/*
|
||||
* CAN device statistics
|
||||
@@ -134,10 +136,48 @@ enum {
|
||||
IFLA_CAN_BITRATE_CONST,
|
||||
IFLA_CAN_DATA_BITRATE_CONST,
|
||||
IFLA_CAN_BITRATE_MAX,
|
||||
__IFLA_CAN_MAX
|
||||
IFLA_CAN_TDC,
|
||||
IFLA_CAN_CTRLMODE_EXT,
|
||||
|
||||
/* add new constants above here */
|
||||
__IFLA_CAN_MAX,
|
||||
IFLA_CAN_MAX = __IFLA_CAN_MAX - 1
|
||||
};
|
||||
|
||||
#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1)
|
||||
/*
|
||||
* CAN FD Transmitter Delay Compensation (TDC)
|
||||
*
|
||||
* Please refer to struct can_tdc_const and can_tdc in
|
||||
* include/linux/can/bittiming.h for further details.
|
||||
*/
|
||||
enum {
|
||||
IFLA_CAN_TDC_UNSPEC,
|
||||
IFLA_CAN_TDC_TDCV_MIN, /* u32 */
|
||||
IFLA_CAN_TDC_TDCV_MAX, /* u32 */
|
||||
IFLA_CAN_TDC_TDCO_MIN, /* u32 */
|
||||
IFLA_CAN_TDC_TDCO_MAX, /* u32 */
|
||||
IFLA_CAN_TDC_TDCF_MIN, /* u32 */
|
||||
IFLA_CAN_TDC_TDCF_MAX, /* u32 */
|
||||
IFLA_CAN_TDC_TDCV, /* u32 */
|
||||
IFLA_CAN_TDC_TDCO, /* u32 */
|
||||
IFLA_CAN_TDC_TDCF, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__IFLA_CAN_TDC,
|
||||
IFLA_CAN_TDC_MAX = __IFLA_CAN_TDC - 1
|
||||
};
|
||||
|
||||
/*
|
||||
* IFLA_CAN_CTRLMODE_EXT nest: controller mode extended parameters
|
||||
*/
|
||||
enum {
|
||||
IFLA_CAN_CTRLMODE_UNSPEC,
|
||||
IFLA_CAN_CTRLMODE_SUPPORTED, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__IFLA_CAN_CTRLMODE,
|
||||
IFLA_CAN_CTRLMODE_MAX = __IFLA_CAN_CTRLMODE - 1
|
||||
};
|
||||
|
||||
/* u16 termination range: 1..65535 Ohms */
|
||||
#define CAN_TERMINATION_DISABLED 0
|
||||
|
||||
@@ -62,6 +62,7 @@ enum {
|
||||
CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */
|
||||
CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */
|
||||
CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */
|
||||
CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */
|
||||
};
|
||||
|
||||
#endif /* !_UAPI_CAN_RAW_H */
|
||||
|
||||
+9
-5
@@ -125,7 +125,7 @@ void print_uds_message(int service, int nrc)
|
||||
case 0x3D: service_name = "WriteMemoryByAddress"; break;
|
||||
case 0x3E: service_name = "TesterPresent"; break;
|
||||
case 0x83: service_name = "AccessTimingParameter"; break;
|
||||
case 0x84: service_name = "SecuredDataTransmision"; break;
|
||||
case 0x84: service_name = "SecuredDataTransmission"; break;
|
||||
case 0x85: service_name = "ControlDTCSetting"; break;
|
||||
case 0x86: service_name = "ResponseOnEvent"; break;
|
||||
case 0x87: service_name = "LinkControl"; break;
|
||||
@@ -225,13 +225,13 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, "s:d:ax:X:ct:u?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
src = strtoul(optarg, (char **)NULL, 16);
|
||||
src = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
src |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dst = strtoul(optarg, (char **)NULL, 16);
|
||||
dst = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
dst |= CAN_EFF_FLAG;
|
||||
break;
|
||||
@@ -249,7 +249,7 @@ int main(int argc, char **argv)
|
||||
if (!strncmp(optarg, "any", 3))
|
||||
extany = 1;
|
||||
else
|
||||
extaddr = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
extaddr = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
@@ -257,7 +257,7 @@ int main(int argc, char **argv)
|
||||
if (!strncmp(optarg, "any", 3))
|
||||
rx_extany = 1;
|
||||
else
|
||||
rx_extaddr = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
rx_extaddr = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
@@ -325,6 +325,10 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
|
||||
+8
-4
@@ -121,25 +121,25 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, "s:d:x:X:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
src = strtoul(optarg, (char **)NULL, 16);
|
||||
src = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
src |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dst = strtoul(optarg, (char **)NULL, 16);
|
||||
dst = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
dst |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
ext = 1;
|
||||
extaddr = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
extaddr = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
rx_ext = 1;
|
||||
rx_extaddr = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
rx_extaddr = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
@@ -189,6 +189,10 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
|
||||
+11
-7
@@ -57,7 +57,7 @@
|
||||
#include <linux/can/isotp.h>
|
||||
|
||||
#define NO_CAN_ID 0xFFFFFFFFU
|
||||
#define BUFSIZE 5000 /* size > 4095 to check socket API internal checks */
|
||||
#define BUFSIZE 67000 /* size > 66000 to check socket API internal checks */
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
@@ -99,13 +99,13 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:b:m:w:f:lL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
@@ -163,20 +163,20 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
fcopts.bs = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
fcopts.stmin = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
fcopts.wftmax = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
opts.flags |= CAN_ISOTP_FORCE_RXSTMIN;
|
||||
force_rx_stmin = strtoul(optarg, (char **)NULL, 10);
|
||||
force_rx_stmin = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
@@ -234,6 +234,10 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
|
||||
+63
-12
@@ -57,7 +57,8 @@
|
||||
#include <linux/can/isotp.h>
|
||||
|
||||
#define NO_CAN_ID 0xFFFFFFFFU
|
||||
#define BUFSIZE 5000 /* size > 4095 to check socket API internal checks */
|
||||
#define BUFSIZE 67000 /* size > 66000 kernel buf to test socket API internal checks */
|
||||
#define ZERO_STRING "ZERO"
|
||||
|
||||
void print_usage(char *prg)
|
||||
{
|
||||
@@ -68,14 +69,18 @@ void print_usage(char *prg)
|
||||
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, " -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 <num> (send num PDUs - use 'i' for infinite loop)\n");
|
||||
fprintf(stderr, " -g <usecs> (wait given usecs before sending a PDU)\n");
|
||||
fprintf(stderr, " -b (block until the PDU transmission is completed)\n");
|
||||
fprintf(stderr, " -S (SF broadcast mode for functional addressing)\n");
|
||||
fprintf(stderr, " -S (SF broadcast mode - for functional addressing)\n");
|
||||
fprintf(stderr, " -C (CF broadcast mode - no wait for flow controls)\n");
|
||||
fprintf(stderr, " -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, "(*) = Use '-t %s' to set N_As to zero for Linux version 5.18+\n", ZERO_STRING);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -87,6 +92,8 @@ int main(int argc, char **argv)
|
||||
static struct can_isotp_ll_options llopts;
|
||||
int opt;
|
||||
extern int optind, opterr, optopt;
|
||||
unsigned int loops = 1; /* one (== no) loop by default */
|
||||
useconds_t usecs = 0; /* wait before sending the PDU */
|
||||
__u32 force_tx_stmin = 0;
|
||||
unsigned char buf[BUFSIZE];
|
||||
int buflen = 0;
|
||||
@@ -95,16 +102,16 @@ 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:bSL:?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:l:g:bSCL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
@@ -162,22 +169,41 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 't':
|
||||
opts.frame_txtime = strtoul(optarg, (char **)NULL, 10);
|
||||
if (!strncmp(optarg, ZERO_STRING, strlen(ZERO_STRING)))
|
||||
opts.frame_txtime = CAN_ISOTP_FRAME_TXTIME_ZERO;
|
||||
else
|
||||
opts.frame_txtime = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
opts.flags |= CAN_ISOTP_FORCE_TXSTMIN;
|
||||
force_tx_stmin = strtoul(optarg, (char **)NULL, 10);
|
||||
force_tx_stmin = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
datalen = strtoul(optarg, (char **)NULL, 10);
|
||||
datalen = strtoul(optarg, NULL, 10);
|
||||
if (!datalen || datalen >= BUFSIZE) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (optarg[0] == 'i') {
|
||||
loops = 0; /* infinite loop */
|
||||
} else {
|
||||
loops = strtoul(optarg, NULL, 10);
|
||||
if (!loops) {
|
||||
fprintf(stderr, "Invalid argument for option -l!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
usecs = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
|
||||
break;
|
||||
@@ -186,6 +212,10 @@ int main(int argc, char **argv)
|
||||
opts.flags |= CAN_ISOTP_SF_BROADCAST;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
opts.flags |= CAN_ISOTP_CF_BROADCAST;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
@@ -210,20 +240,27 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
#define BC_FLAGS (CAN_ISOTP_SF_BROADCAST | CAN_ISOTP_CF_BROADCAST)
|
||||
|
||||
if ((argc - optind != 1) ||
|
||||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
|
||||
((opts.flags & BC_FLAGS) == BC_FLAGS) ||
|
||||
((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
|
||||
(!(opts.flags & CAN_ISOTP_SF_BROADCAST)))) {
|
||||
(!(opts.flags & BC_FLAGS)))) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
|
||||
perror("sockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
if (llopts.tx_dl) {
|
||||
if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
|
||||
@@ -237,6 +274,10 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
@@ -252,6 +293,9 @@ int main(int argc, char **argv)
|
||||
buf[buflen] = ((buflen % 0xFF) + 1) & 0xFF;
|
||||
}
|
||||
|
||||
loop:
|
||||
if (usecs)
|
||||
usleep(usecs);
|
||||
|
||||
retval = write(s, buf, buflen);
|
||||
if (retval < 0) {
|
||||
@@ -262,6 +306,13 @@ int main(int argc, char **argv)
|
||||
if (retval != buflen)
|
||||
fprintf(stderr, "wrote only %d from %d byte\n", retval, buflen);
|
||||
|
||||
if (loops) {
|
||||
if (--loops)
|
||||
goto loop;
|
||||
} else {
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* due to a Kernel internal wait queue the PDU is sent completely
|
||||
* before close() returns.
|
||||
|
||||
+11
-7
@@ -166,17 +166,17 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, "l:s:d:x:p:P:b:m:w:t:L:v?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'l':
|
||||
local_port = strtoul(optarg, (char **)NULL, 10);
|
||||
local_port = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
caddr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
caddr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
caddr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
caddr.can_addr.tp.rx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
caddr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
caddr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
@@ -234,19 +234,19 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
fcopts.bs = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
fcopts.stmin = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
fcopts.wftmax = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
opts.frame_txtime = strtoul(optarg, (char **)NULL, 10);
|
||||
opts.frame_txtime = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
@@ -350,6 +350,10 @@ int main(int argc, char **argv)
|
||||
|
||||
caddr.can_family = AF_CAN;
|
||||
caddr.can_ifindex = if_nametoindex(argv[optind]);
|
||||
if (!caddr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(sc, (struct sockaddr *)&caddr, caddrlen) < 0) {
|
||||
perror("bind");
|
||||
|
||||
+9
-4
@@ -200,25 +200,25 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:L:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
src = strtoul(optarg, (char **)NULL, 16);
|
||||
src = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
src |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dst = strtoul(optarg, (char **)NULL, 16);
|
||||
dst = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
dst |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
opts.flags |= CAN_ISOTP_EXTEND_ADDR;
|
||||
opts.ext_address = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
opts.ext_address = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
opts.flags |= CAN_ISOTP_RX_EXT_ADDR;
|
||||
opts.rx_ext_address = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
opts.rx_ext_address = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
@@ -296,6 +296,11 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(if_name);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
|
||||
|
||||
|
||||
+6
-6
@@ -154,13 +154,13 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, "s:d:n:x:p:P:t:b:m:whL:vD?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.tx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
addr.can_addr.tp.rx_id = strtoul(optarg, NULL, 16);
|
||||
if (strlen(optarg) > 7)
|
||||
addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
|
||||
break;
|
||||
@@ -228,19 +228,19 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 't':
|
||||
opts.frame_txtime = strtoul(optarg, (char **)NULL, 10);
|
||||
opts.frame_txtime = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
fcopts.bs = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.bs = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
fcopts.stmin = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.stmin = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
fcopts.wftmax = strtoul(optarg, (char **)NULL, 16) & 0xFF;
|
||||
fcopts.wftmax = strtoul(optarg, NULL, 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
|
||||
+114
-23
@@ -42,6 +42,12 @@ struct j1939cat_stats {
|
||||
int err;
|
||||
uint32_t tskey;
|
||||
uint32_t send;
|
||||
uint32_t total;
|
||||
uint32_t pgn;
|
||||
uint8_t sa;
|
||||
uint8_t da;
|
||||
uint64_t src_name;
|
||||
uint64_t dst_name;
|
||||
};
|
||||
|
||||
struct j1939cat_priv {
|
||||
@@ -67,6 +73,7 @@ struct j1939cat_priv {
|
||||
struct sock_extended_err *serr;
|
||||
struct scm_timestamping *tss;
|
||||
struct j1939cat_stats stats;
|
||||
int32_t last_dpo;
|
||||
};
|
||||
|
||||
static const char help_msg[] =
|
||||
@@ -141,7 +148,7 @@ static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *nam
|
||||
if (!(cur->tv_sec | cur->tv_nsec))
|
||||
return;
|
||||
|
||||
fprintf(stderr, " %s: %lu s %lu us (seq=%u, send=%u)",
|
||||
fprintf(stderr, " %s: %lu s %lu us (seq=%03u, send=%07u)",
|
||||
name, cur->tv_sec, cur->tv_nsec / 1000,
|
||||
stats->tskey, stats->send);
|
||||
|
||||
@@ -152,13 +159,13 @@ static const char *j1939cat_tstype_to_str(int tstype)
|
||||
{
|
||||
switch (tstype) {
|
||||
case SCM_TSTAMP_SCHED:
|
||||
return " ENQ";
|
||||
return "TX ENQ";
|
||||
case SCM_TSTAMP_SND:
|
||||
return " SND";
|
||||
return "TX SND";
|
||||
case SCM_TSTAMP_ACK:
|
||||
return " ACK";
|
||||
return "TX ACK";
|
||||
default:
|
||||
return " unk";
|
||||
return " unk";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +182,24 @@ static void j1939cat_scm_opt_stats(struct j1939cat_priv *priv, void *buf, int le
|
||||
case J1939_NLA_BYTES_ACKED:
|
||||
stats->send = *(uint32_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
case J1939_NLA_TOTAL_SIZE:
|
||||
stats->total = *(uint32_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
case J1939_NLA_PGN:
|
||||
stats->pgn = *(uint32_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
case J1939_NLA_DEST_ADDR:
|
||||
stats->da = *(uint8_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
case J1939_NLA_SRC_ADDR:
|
||||
stats->sa = *(uint8_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
case J1939_NLA_DEST_NAME:
|
||||
stats->dst_name = *(uint64_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
case J1939_NLA_SRC_NAME:
|
||||
stats->src_name = *(uint64_t *)((char *)nla + NLA_HDRLEN);
|
||||
break;
|
||||
default:
|
||||
warnx("not supported J1939_NLA field\n");
|
||||
}
|
||||
@@ -231,14 +256,39 @@ static int j1939cat_extract_serr(struct j1939cat_priv *priv)
|
||||
* error reason is converted from J1939
|
||||
* abort to linux error name space.
|
||||
*/
|
||||
if (serr->ee_info != J1939_EE_INFO_TX_ABORT)
|
||||
warnx("serr: unknown ee_info: %i",
|
||||
serr->ee_info);
|
||||
switch (serr->ee_info) {
|
||||
case J1939_EE_INFO_TX_ABORT:
|
||||
j1939cat_print_timestamp(priv, "TX ABT", &tss->ts[0]);
|
||||
warnx("serr: tx error: %i, %s", serr->ee_errno,
|
||||
strerror(serr->ee_errno));
|
||||
return serr->ee_errno;
|
||||
case J1939_EE_INFO_RX_RTS:
|
||||
stats->tskey = serr->ee_data;
|
||||
j1939cat_print_timestamp(priv, "RX RTS", &tss->ts[0]);
|
||||
fprintf(stderr, " total size: %u, pgn=0x%05x, sa=0x%02x, da=0x%02x src_name=0x%08" PRIx64 ", dst_name=0x%08" PRIx64 ")\n",
|
||||
stats->total, stats->pgn, stats->sa, stats->da,
|
||||
stats->src_name, stats->dst_name);
|
||||
priv->last_dpo = -1;
|
||||
return 0;
|
||||
case J1939_EE_INFO_RX_DPO:
|
||||
stats->tskey = serr->ee_data;
|
||||
j1939cat_print_timestamp(priv, "RX DPO", &tss->ts[0]);
|
||||
if (stats->send <= (uint32_t)priv->last_dpo && priv->last_dpo != -1)
|
||||
warnx("same dpo? current: %i, last: %i",
|
||||
stats->send, priv->last_dpo);
|
||||
priv->last_dpo = stats->send;
|
||||
return 0;
|
||||
case J1939_EE_INFO_RX_ABORT:
|
||||
j1939cat_print_timestamp(priv, "RX ABT", &tss->ts[0]);
|
||||
warnx("serr: rx error: %i, %s", serr->ee_errno,
|
||||
strerror(serr->ee_errno));
|
||||
return serr->ee_errno;
|
||||
default:
|
||||
warnx("serr: unknown ee_info: %i", serr->ee_info);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
warnx("serr: wrong origin: %u", serr->ee_origin);
|
||||
}
|
||||
@@ -269,7 +319,7 @@ static int j1939cat_parse_cm(struct j1939cat_priv *priv, struct cmsghdr *cm)
|
||||
|
||||
static int j1939cat_recv_err(struct j1939cat_priv *priv)
|
||||
{
|
||||
char control[100];
|
||||
char control[200];
|
||||
struct cmsghdr *cm;
|
||||
int ret;
|
||||
struct msghdr msg = {
|
||||
@@ -318,14 +368,16 @@ static int j1939cat_send_loop(struct j1939cat_priv *priv, int out_fd, char *buf,
|
||||
int ret;
|
||||
|
||||
ret = poll(&fds, 1, priv->polltimeout);
|
||||
if (ret == -EINTR)
|
||||
continue;
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
if (ret == -1) {
|
||||
if (errno == -EINTR)
|
||||
continue;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
if (!ret)
|
||||
return -ETIME;
|
||||
if (!(fds.revents & events)) {
|
||||
warn("%s: something else is wrong", __func__);
|
||||
warn("%s: something else is wrong %x %x", __func__, fds.revents, events);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -457,7 +509,7 @@ static int j1939cat_send(struct j1939cat_priv *priv)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (priv->todo_filesize)
|
||||
size = j1939cat_get_file_size(priv->infile);
|
||||
@@ -499,6 +551,7 @@ static int j1939cat_recv_one(struct j1939cat_priv *priv, uint8_t *buf, size_t bu
|
||||
|
||||
static int j1939cat_recv(struct j1939cat_priv *priv)
|
||||
{
|
||||
unsigned int events = POLLIN | POLLERR;
|
||||
int ret = EXIT_SUCCESS;
|
||||
size_t buf_size;
|
||||
uint8_t *buf;
|
||||
@@ -510,10 +563,48 @@ static int j1939cat_recv(struct j1939cat_priv *priv)
|
||||
return EXIT_FAILURE;;
|
||||
}
|
||||
|
||||
priv->last_dpo = -1;
|
||||
|
||||
while (priv->todo_recv) {
|
||||
ret = j1939cat_recv_one(priv, buf, buf_size);
|
||||
if (ret)
|
||||
break;
|
||||
if (priv->polltimeout) {
|
||||
struct pollfd fds = {
|
||||
.fd = priv->sock,
|
||||
.events = events,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = poll(&fds, 1, priv->polltimeout);
|
||||
if (ret == -1) {
|
||||
if (errno == -EINTR)
|
||||
continue;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
if (!ret)
|
||||
continue;
|
||||
if (!(fds.revents & events)) {
|
||||
warn("%s: something else is wrong %x %x", __func__, fds.revents, events);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (fds.revents & POLLERR) {
|
||||
ret = j1939cat_recv_err(priv);
|
||||
if (ret == -EINTR)
|
||||
continue;
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fds.revents & POLLIN) {
|
||||
ret = j1939cat_recv_one(priv, buf, buf_size);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret = j1939cat_recv_one(priv, buf, buf_size);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
@@ -555,7 +646,7 @@ static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
|
||||
SOF_TIMESTAMPING_TX_ACK |
|
||||
SOF_TIMESTAMPING_TX_SCHED |
|
||||
SOF_TIMESTAMPING_OPT_STATS | SOF_TIMESTAMPING_OPT_TSONLY |
|
||||
SOF_TIMESTAMPING_OPT_ID;
|
||||
SOF_TIMESTAMPING_OPT_ID | SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
|
||||
if (setsockopt(priv->sock, SOL_SOCKET, SO_TIMESTAMPING,
|
||||
(char *) &sock_opt, sizeof(sock_opt)))
|
||||
|
||||
@@ -159,7 +159,7 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
||||
int i, idx, dlen, len;
|
||||
int maxdlen = CAN_MAX_DLEN;
|
||||
int ret = CAN_MTU;
|
||||
unsigned char tmp;
|
||||
canid_t tmp;
|
||||
|
||||
len = strlen(cs);
|
||||
//printf("'%s' len %d\n", cs, len);
|
||||
@@ -568,9 +568,20 @@ static int snprintf_error_data(char *buf, size_t len, uint8_t err,
|
||||
|
||||
for (i = 0; i < arr_len; i++) {
|
||||
if (err & (1 << i)) {
|
||||
if (count)
|
||||
n += snprintf(buf + n, len - n, ",");
|
||||
n += snprintf(buf + n, len - n, "%s", arr[i]);
|
||||
int tmp_n = 0;
|
||||
if (count){
|
||||
/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
|
||||
tmp_n = snprintf(buf + n, len - n, ",");
|
||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n){
|
||||
return n;
|
||||
}
|
||||
n += tmp_n;
|
||||
}
|
||||
tmp_n = snprintf(buf + n, len - n, "%s", arr[i]);
|
||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n){
|
||||
return n;
|
||||
}
|
||||
n += tmp_n;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -644,9 +655,20 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||
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]);
|
||||
int tmp_n = 0;
|
||||
if (classes){
|
||||
/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
|
||||
tmp_n = snprintf(buf + n, len - n, "%s", sep);
|
||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n){
|
||||
return;
|
||||
}
|
||||
n += tmp_n;
|
||||
}
|
||||
tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n){
|
||||
return;
|
||||
}
|
||||
n += tmp_n;
|
||||
if (mask == CAN_ERR_LOSTARB)
|
||||
n += snprintf_error_lostarb(buf + n, len - n,
|
||||
cf);
|
||||
@@ -658,7 +680,7 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
|
||||
}
|
||||
}
|
||||
|
||||
if (cf->data[6] || cf->data[7]) {
|
||||
if (cf->can_id & CAN_ERR_CNT || cf->data[6] || cf->data[7]) {
|
||||
n += snprintf(buf + n, len - n, "%s", sep);
|
||||
n += snprintf(buf + n, len - n, "error-counter-tx-rx{{%d}{%d}}",
|
||||
cf->data[6], cf->data[7]);
|
||||
|
||||
@@ -47,6 +47,13 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define pr_debug(fmt, args...) printf(fmt, ##args)
|
||||
#else
|
||||
__attribute__((format (printf, 1, 2)))
|
||||
static inline int pr_debug(const char* fmt, ...) {return 0;}
|
||||
#endif
|
||||
|
||||
/* buffer sizes for CAN frame string representations */
|
||||
|
||||
#define CL_ID (sizeof("12345678##1"))
|
||||
@@ -95,6 +102,7 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen);
|
||||
*
|
||||
*/
|
||||
|
||||
struct canfd_frame;
|
||||
int parse_canframe(char *cs, struct canfd_frame *cf);
|
||||
/*
|
||||
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
/* needed on some 64 bit platforms to get consistent 64-bit types */
|
||||
#define __SANE_USERSPACE_TYPES__
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/j1939.h>
|
||||
|
||||
@@ -71,11 +71,13 @@ void print_usage(char *prg)
|
||||
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)
|
||||
void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc, char *extra_info, FILE *outfile)
|
||||
{
|
||||
int i;
|
||||
char id[10];
|
||||
char *dir = "Rx";
|
||||
int dlc;
|
||||
struct can_frame *cf = (struct can_frame *)cfd; /* for len8_dlc */
|
||||
|
||||
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
|
||||
|
||||
@@ -94,13 +96,20 @@ void can_asc(struct canfd_frame *cf, int devno, int nortrdlc, char *extra_info,
|
||||
|
||||
fprintf(outfile, "%-15s %s ", id, dir);
|
||||
|
||||
if (cf->len == CAN_MAX_DLC &&
|
||||
cf->len8_dlc > CAN_MAX_DLC &&
|
||||
cf->len8_dlc <= CAN_MAX_RAW_DLC)
|
||||
dlc = cf->len8_dlc;
|
||||
else
|
||||
dlc = cf->len;
|
||||
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
if (nortrdlc)
|
||||
fprintf(outfile, "r"); /* RTR frame */
|
||||
else
|
||||
fprintf(outfile, "r %d", cf->len); /* RTR frame */
|
||||
fprintf(outfile, "r %X", dlc); /* RTR frame */
|
||||
} else {
|
||||
fprintf(outfile, "d %d", cf->len); /* data frame */
|
||||
fprintf(outfile, "d %X", dlc); /* data frame */
|
||||
|
||||
for (i = 0; i < cf->len; i++) {
|
||||
fprintf(outfile, " %02X", cf->data[i]);
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,706 @@
|
||||
000: 024b0760
|
||||
004: 001c0900
|
||||
008: 00050200
|
||||
00c: 00020600
|
||||
010: 017fce42
|
||||
014: 00010000
|
||||
018: 40400040
|
||||
01c: 3f1a0000
|
||||
020: 00000000
|
||||
024: 00000000
|
||||
028: 00000000
|
||||
02c: 00000000
|
||||
030: 00000000
|
||||
034: 00000000
|
||||
038: 00000000
|
||||
03c: 00000003
|
||||
040: 03000029
|
||||
044: 00000000
|
||||
048: 00000024
|
||||
04c: 00000000
|
||||
050: 00600080
|
||||
054: 00000005
|
||||
058: 00000030
|
||||
05c: e3600090
|
||||
060: 00000307
|
||||
064: 00000108
|
||||
068: ef000029
|
||||
06c: 00000300
|
||||
070: 00000234
|
||||
074: 00600000
|
||||
078: 00000000
|
||||
07c: 00000610
|
||||
080: 00600000
|
||||
084: 00000000
|
||||
088: 00000620
|
||||
08c: 00600000
|
||||
090: 00000000
|
||||
094: 00000630
|
||||
098: 00600000
|
||||
09c: 00000000
|
||||
0a0: 00000640
|
||||
0a4: 00600000
|
||||
0a8: 00000000
|
||||
0ac: 00000650
|
||||
0b0: 00600000
|
||||
0b4: 00000000
|
||||
0b8: 00000660
|
||||
0bc: 00600000
|
||||
0c0: 00000000
|
||||
0c4: 00000670
|
||||
0c8: 00600000
|
||||
0cc: 00000000
|
||||
0d0: 00000680
|
||||
0d4: 00600000
|
||||
0d8: 00000000
|
||||
0dc: 00000690
|
||||
0e0: 00600000
|
||||
0e4: 00000000
|
||||
0e8: 000006a0
|
||||
0ec: 00600000
|
||||
0f0: 00000000
|
||||
0f4: 000006b0
|
||||
0f8: 00600000
|
||||
0fc: 00000000
|
||||
100: 000006c0
|
||||
104: 00600000
|
||||
108: 00000000
|
||||
10c: 000006d0
|
||||
110: 00600000
|
||||
114: 00000000
|
||||
118: 000006e0
|
||||
11c: 00600000
|
||||
120: 00000000
|
||||
124: 000006f0
|
||||
128: 00600000
|
||||
12c: 00000000
|
||||
130: 00000700
|
||||
134: 00600000
|
||||
138: 00000000
|
||||
13c: 00000710
|
||||
140: 00600000
|
||||
144: 00000000
|
||||
148: 00000720
|
||||
14c: 00600000
|
||||
150: 00000000
|
||||
154: 00000730
|
||||
158: 00600000
|
||||
15c: 00000000
|
||||
160: 00000740
|
||||
164: 00600000
|
||||
168: 00000000
|
||||
16c: 00000750
|
||||
170: 00600000
|
||||
174: 00000000
|
||||
178: 00000760
|
||||
17c: 00600000
|
||||
180: 00000000
|
||||
184: 00000770
|
||||
188: 00600000
|
||||
18c: 00000000
|
||||
190: 00000780
|
||||
194: 00600000
|
||||
198: 00000000
|
||||
19c: 00000790
|
||||
1a0: 00600000
|
||||
1a4: 00000000
|
||||
1a8: 000007a0
|
||||
1ac: 00600000
|
||||
1b0: 00000000
|
||||
1b4: 000007b0
|
||||
1b8: 00600000
|
||||
1bc: 00000000
|
||||
1c0: 000007c0
|
||||
1c4: 00600000
|
||||
1c8: 00000000
|
||||
1cc: 000007d0
|
||||
1d0: 00000082
|
||||
1d4: 00000000
|
||||
1d8: 00000000
|
||||
1dc: 00000000
|
||||
1e0: 00000000
|
||||
1e4: 00000000
|
||||
1e8: 00000000
|
||||
1ec: 00000000
|
||||
1f0: 00000000
|
||||
1f4: 00000000
|
||||
1f8: 00000000
|
||||
1fc: 00000000
|
||||
200: 00000000
|
||||
204: 00000000
|
||||
208: 00000000
|
||||
20c: 00000000
|
||||
210: 00000000
|
||||
214: 00000000
|
||||
218: 00000000
|
||||
21c: 00000000
|
||||
220: 00000000
|
||||
224: 00000000
|
||||
228: 00000000
|
||||
22c: 00000000
|
||||
230: 00000000
|
||||
234: 00000000
|
||||
238: 00000000
|
||||
23c: 00000000
|
||||
240: 00000000
|
||||
244: 00000000
|
||||
248: 00000000
|
||||
24c: 00000000
|
||||
250: 00000000
|
||||
254: 00000000
|
||||
258: 00000000
|
||||
25c: 00000000
|
||||
260: 00000000
|
||||
264: 00000000
|
||||
268: 00000000
|
||||
26c: 00000000
|
||||
270: 00000000
|
||||
274: 00000000
|
||||
278: 00000000
|
||||
27c: 00000000
|
||||
280: 00000000
|
||||
284: 00000000
|
||||
288: 00000000
|
||||
28c: 00000000
|
||||
290: 00000000
|
||||
294: 00000000
|
||||
298: 00000000
|
||||
29c: 00000000
|
||||
2a0: 00000000
|
||||
2a4: 00000000
|
||||
2a8: 00000000
|
||||
2ac: 00000000
|
||||
2b0: 00000000
|
||||
2b4: 00000000
|
||||
2b8: 00000000
|
||||
2bc: 00000000
|
||||
2c0: 00000000
|
||||
2c4: 00000000
|
||||
2c8: 00000000
|
||||
2cc: 00000000
|
||||
2d0: 00000000
|
||||
2d4: 00000000
|
||||
2d8: 00000000
|
||||
2dc: 00000000
|
||||
2e0: 00000000
|
||||
2e4: 00000000
|
||||
2e8: 00000000
|
||||
2ec: 00000000
|
||||
400: 00000002
|
||||
404: 00000008
|
||||
408: 005897d8
|
||||
40c: 00000002
|
||||
410: 00000208
|
||||
414: 00daf340
|
||||
418: 00000002
|
||||
41c: 00000408
|
||||
420: 01585768
|
||||
424: 00000000
|
||||
428: 00000000
|
||||
42c: 00000000
|
||||
430: 00000002
|
||||
434: 00000008
|
||||
438: 00000000
|
||||
43c: 00000000
|
||||
440: 00000000
|
||||
444: 00000000
|
||||
448: 00000000
|
||||
44c: 00000000
|
||||
450: 00000000
|
||||
454: 00000000
|
||||
458: 00000000
|
||||
45c: 00000000
|
||||
460: 00000000
|
||||
464: 00000000
|
||||
468: 00000000
|
||||
46c: 00000000
|
||||
470: 00000000
|
||||
474: 00000000
|
||||
478: 00000002
|
||||
47c: 00000208
|
||||
480: 00000001
|
||||
484: 00000000
|
||||
488: 00000000
|
||||
48c: 00000000
|
||||
490: 00000000
|
||||
494: 00000000
|
||||
498: 00000000
|
||||
49c: 00000000
|
||||
4a0: 00000000
|
||||
4a4: 00000000
|
||||
4a8: 00000000
|
||||
4ac: 00000000
|
||||
4b0: 00000000
|
||||
4b4: 00000000
|
||||
4b8: 00000000
|
||||
4bc: 00000000
|
||||
4c0: 00000002
|
||||
4c4: 00000408
|
||||
4c8: 00000002
|
||||
4cc: 00000000
|
||||
4d0: 00000000
|
||||
4d4: 00000000
|
||||
4d8: 00000000
|
||||
4dc: 00000000
|
||||
4e0: 00000000
|
||||
4e4: 00000000
|
||||
4e8: 00000000
|
||||
4ec: 00000000
|
||||
4f0: 00000000
|
||||
4f4: 00000000
|
||||
4f8: 00000000
|
||||
4fc: 00000000
|
||||
500: 00000000
|
||||
504: 00000000
|
||||
508: 00000000
|
||||
50c: 00000000
|
||||
510: 00000000
|
||||
514: 00000000
|
||||
518: 00000000
|
||||
51c: 00000000
|
||||
520: 00000000
|
||||
524: 00000000
|
||||
528: 00000000
|
||||
52c: 00000000
|
||||
530: 00000000
|
||||
534: 00000000
|
||||
538: 00000000
|
||||
53c: 00000000
|
||||
540: 00000000
|
||||
544: 00000000
|
||||
548: 00000000
|
||||
54c: 00000000
|
||||
550: 00000002
|
||||
554: 00000008
|
||||
558: 005897d8
|
||||
55c: 00000000
|
||||
560: 00000000
|
||||
564: 00000000
|
||||
568: 00000000
|
||||
56c: 00000000
|
||||
570: 00000000
|
||||
574: 00000000
|
||||
578: 00000000
|
||||
57c: 00000000
|
||||
580: 00000000
|
||||
584: 00000000
|
||||
588: 00000000
|
||||
58c: 00000000
|
||||
590: 00000000
|
||||
594: 00000000
|
||||
598: 00000000
|
||||
59c: 00000002
|
||||
5a0: 00000008
|
||||
5a4: 00daf340
|
||||
5a8: 00000001
|
||||
5ac: 00000000
|
||||
5b0: 00000000
|
||||
5b4: 00000000
|
||||
5b8: 00000000
|
||||
5bc: 00000000
|
||||
5c0: 00000000
|
||||
5c4: 00000000
|
||||
5c8: 00000000
|
||||
5cc: 00000000
|
||||
5d0: 00000000
|
||||
5d4: 00000000
|
||||
5d8: 00000000
|
||||
5dc: 00000000
|
||||
5e0: 00000000
|
||||
5e4: 00000000
|
||||
5e8: 00000002
|
||||
5ec: 00000008
|
||||
5f0: 01585768
|
||||
5f4: 00000002
|
||||
5f8: 00000000
|
||||
5fc: 00000000
|
||||
600: 00000000
|
||||
604: 00000000
|
||||
608: 00000000
|
||||
60c: 00000000
|
||||
610: 00000000
|
||||
614: 00000000
|
||||
618: 00000000
|
||||
61c: 00000000
|
||||
620: 00000000
|
||||
624: 00000000
|
||||
628: 00000000
|
||||
62c: 00000000
|
||||
630: 00000000
|
||||
634: 00000000
|
||||
638: 00000000
|
||||
63c: 00000000
|
||||
640: 00000000
|
||||
644: 00000000
|
||||
648: 00000000
|
||||
64c: 00000000
|
||||
650: 00000000
|
||||
654: 00000000
|
||||
658: 00000000
|
||||
65c: 00000000
|
||||
660: 00000000
|
||||
664: 00000000
|
||||
668: 00000000
|
||||
66c: 00000000
|
||||
670: 00000000
|
||||
674: 00000000
|
||||
678: 00000000
|
||||
67c: 00000000
|
||||
680: 00000000
|
||||
684: 00000000
|
||||
688: 00000000
|
||||
68c: 00000000
|
||||
690: 00000000
|
||||
694: 00000000
|
||||
698: 00000000
|
||||
69c: 00000000
|
||||
6a0: 00000000
|
||||
6a4: 00000000
|
||||
6a8: 00000000
|
||||
6ac: 00000000
|
||||
6b0: 00000000
|
||||
6b4: 00000000
|
||||
6b8: 00000000
|
||||
6bc: 00000000
|
||||
6c0: 00000000
|
||||
6c4: 00000000
|
||||
6c8: 00000000
|
||||
6cc: 00000000
|
||||
6d0: 00000000
|
||||
6d4: 00000000
|
||||
6d8: 00000000
|
||||
6dc: 00000000
|
||||
6e0: 00000000
|
||||
6e4: 00000000
|
||||
6e8: 00000000
|
||||
6ec: 00000000
|
||||
6f0: 00000000
|
||||
6f4: 00000000
|
||||
6f8: 00000000
|
||||
6fc: 00000000
|
||||
700: 00000000
|
||||
704: 00000000
|
||||
708: 00000000
|
||||
70c: 00000000
|
||||
710: 00000000
|
||||
714: 00000000
|
||||
718: 00000000
|
||||
71c: 00000000
|
||||
720: 00000000
|
||||
724: 00000000
|
||||
728: 00000000
|
||||
72c: 00000000
|
||||
730: 00000000
|
||||
734: 00000000
|
||||
738: 00000000
|
||||
73c: 00000000
|
||||
740: 00000000
|
||||
744: 00000000
|
||||
748: 00000000
|
||||
74c: 00000000
|
||||
750: 00000000
|
||||
754: 00000000
|
||||
758: 00000000
|
||||
75c: 00000000
|
||||
760: 00000000
|
||||
764: 00000000
|
||||
768: 00000000
|
||||
76c: 00000000
|
||||
770: 00000000
|
||||
774: 00000000
|
||||
778: 00000000
|
||||
77c: 00000000
|
||||
780: 00000000
|
||||
784: 00000000
|
||||
788: 00000000
|
||||
78c: 00000000
|
||||
790: 00000000
|
||||
794: 00000000
|
||||
798: 00000000
|
||||
79c: 00000000
|
||||
7a0: 00000000
|
||||
7a4: 00000000
|
||||
7a8: 00000000
|
||||
7ac: 00000000
|
||||
7b0: 00000000
|
||||
7b4: 00000000
|
||||
7b8: 00000000
|
||||
7bc: 00000000
|
||||
7c0: 00000000
|
||||
7c4: 00000000
|
||||
7c8: 00000000
|
||||
7cc: 00000000
|
||||
7d0: 00000000
|
||||
7d4: 00000000
|
||||
7d8: 00000000
|
||||
7dc: 00000000
|
||||
7e0: 00000000
|
||||
7e4: 00000000
|
||||
7e8: 00000000
|
||||
7ec: 00000000
|
||||
7f0: 00000000
|
||||
7f4: 00000000
|
||||
7f8: 00000000
|
||||
7fc: 00000000
|
||||
800: 00000000
|
||||
804: 00000000
|
||||
808: 00000000
|
||||
80c: 00000000
|
||||
810: 00000000
|
||||
814: 00000000
|
||||
818: 00000000
|
||||
81c: 00000000
|
||||
820: 00000000
|
||||
824: 00000000
|
||||
828: 00000000
|
||||
82c: 00000000
|
||||
830: 00000000
|
||||
834: 00000000
|
||||
838: 00000000
|
||||
83c: 00000000
|
||||
840: 00000000
|
||||
844: 00000000
|
||||
848: 00000000
|
||||
84c: 00000000
|
||||
850: 00000000
|
||||
854: 00000000
|
||||
858: 00000000
|
||||
85c: 00000000
|
||||
860: 00000000
|
||||
864: 00000000
|
||||
868: 00000000
|
||||
86c: 00000000
|
||||
870: 00000000
|
||||
874: 00000000
|
||||
878: 00000000
|
||||
87c: 00000000
|
||||
880: 00000000
|
||||
884: 00000000
|
||||
888: 00000000
|
||||
88c: 00000000
|
||||
890: 00000000
|
||||
894: 00000000
|
||||
898: 00000000
|
||||
89c: 00000000
|
||||
8a0: 00000000
|
||||
8a4: 00000000
|
||||
8a8: 00000000
|
||||
8ac: 00000000
|
||||
8b0: 00000000
|
||||
8b4: 00000000
|
||||
8b8: 00000000
|
||||
8bc: 00000000
|
||||
8c0: 00000000
|
||||
8c4: 00000000
|
||||
8c8: 00000000
|
||||
8cc: 00000000
|
||||
8d0: 00000000
|
||||
8d4: 00000000
|
||||
8d8: 00000000
|
||||
8dc: 00000000
|
||||
8e0: 00000000
|
||||
8e4: 00000000
|
||||
8e8: 00000000
|
||||
8ec: 00000000
|
||||
8f0: 00000000
|
||||
8f4: 00000000
|
||||
8f8: 00000000
|
||||
8fc: 00000000
|
||||
900: 00000000
|
||||
904: 00000000
|
||||
908: 00000000
|
||||
90c: 00000000
|
||||
910: 00000000
|
||||
914: 00000000
|
||||
918: 00000000
|
||||
91c: 00000000
|
||||
920: 00000000
|
||||
924: 00000000
|
||||
928: 00000000
|
||||
92c: 00000000
|
||||
930: 00000000
|
||||
934: 00000000
|
||||
938: 00000000
|
||||
93c: 00000000
|
||||
940: 00000000
|
||||
944: 00000000
|
||||
948: 00000000
|
||||
94c: 00000000
|
||||
950: 00000000
|
||||
954: 00000000
|
||||
958: 00000000
|
||||
95c: 00000000
|
||||
960: 00000000
|
||||
964: 00000000
|
||||
968: 00000000
|
||||
96c: 00000000
|
||||
970: 00000000
|
||||
974: 00000000
|
||||
978: 00000000
|
||||
97c: 00000000
|
||||
980: 00000000
|
||||
984: 00000000
|
||||
988: 00000000
|
||||
98c: 00000000
|
||||
990: 00000000
|
||||
994: 00000000
|
||||
998: 00000000
|
||||
99c: 00000000
|
||||
9a0: 00000000
|
||||
9a4: 00000000
|
||||
9a8: 00000000
|
||||
9ac: 00000000
|
||||
9b0: 00000000
|
||||
9b4: 00000000
|
||||
9b8: 00000000
|
||||
9bc: 00000000
|
||||
9c0: 00000000
|
||||
9c4: 00000000
|
||||
9c8: 00000000
|
||||
9cc: 00000000
|
||||
9d0: 00000000
|
||||
9d4: 00000000
|
||||
9d8: 00000000
|
||||
9dc: 00000000
|
||||
9e0: 00000000
|
||||
9e4: 00000000
|
||||
9e8: 00000000
|
||||
9ec: 00000000
|
||||
9f0: 00000000
|
||||
9f4: 00000000
|
||||
9f8: 00000000
|
||||
9fc: 00000000
|
||||
a00: 00000000
|
||||
a04: 00000000
|
||||
a08: 00000000
|
||||
a0c: 00000000
|
||||
a10: 00000000
|
||||
a14: 00000000
|
||||
a18: 00000000
|
||||
a1c: 00000000
|
||||
a20: 00000000
|
||||
a24: 00000000
|
||||
a28: 00000000
|
||||
a2c: 00000000
|
||||
a30: 00000000
|
||||
a34: 00000000
|
||||
a38: 00000000
|
||||
a3c: 00000000
|
||||
a40: 00000000
|
||||
a44: 00000000
|
||||
a48: 00000000
|
||||
a4c: 00000000
|
||||
a50: 00000000
|
||||
a54: 00000000
|
||||
a58: 00000000
|
||||
a5c: 00000000
|
||||
a60: 00000000
|
||||
a64: 00000000
|
||||
a68: 00000000
|
||||
a6c: 00000000
|
||||
a70: 00000000
|
||||
a74: 00000000
|
||||
a78: 00000000
|
||||
a7c: 00000000
|
||||
a80: 00000000
|
||||
a84: 00000000
|
||||
a88: 00000000
|
||||
a8c: 00000000
|
||||
a90: 00000000
|
||||
a94: 00000000
|
||||
a98: 00000000
|
||||
a9c: 00000000
|
||||
aa0: 00000000
|
||||
aa4: 00000000
|
||||
aa8: 00000000
|
||||
aac: 00000000
|
||||
ab0: 00000000
|
||||
ab4: 00000000
|
||||
ab8: 00000000
|
||||
abc: 00000000
|
||||
ac0: 00000000
|
||||
ac4: 00000000
|
||||
ac8: 00000000
|
||||
acc: 00000000
|
||||
ad0: 00000000
|
||||
ad4: 00000000
|
||||
ad8: 00000000
|
||||
adc: 00000000
|
||||
ae0: 00000000
|
||||
ae4: 00000000
|
||||
ae8: 00000000
|
||||
aec: 00000000
|
||||
af0: 00000000
|
||||
af4: 00000000
|
||||
af8: 00000000
|
||||
afc: 00000000
|
||||
b00: 00000000
|
||||
b04: 00000000
|
||||
b08: 00000000
|
||||
b0c: 00000000
|
||||
b10: 00000000
|
||||
b14: 00000000
|
||||
b18: 00000000
|
||||
b1c: 00000000
|
||||
b20: 00000000
|
||||
b24: 00000000
|
||||
b28: 00000000
|
||||
b2c: 00000000
|
||||
b30: 00000000
|
||||
b34: 00000000
|
||||
b38: 00000000
|
||||
b3c: 00000000
|
||||
b40: 00000000
|
||||
b44: 00000000
|
||||
b48: 00000000
|
||||
b4c: 00000000
|
||||
b50: 00000000
|
||||
b54: 00000000
|
||||
b58: 00000000
|
||||
b5c: 00000000
|
||||
b60: 00000000
|
||||
b64: 00000000
|
||||
b68: 00000000
|
||||
b6c: 00000000
|
||||
b70: 00000000
|
||||
b74: 00000000
|
||||
b78: 00000000
|
||||
b7c: 00000000
|
||||
b80: 00000000
|
||||
b84: 00000000
|
||||
b88: 00000000
|
||||
b8c: 00000000
|
||||
b90: 00000000
|
||||
b94: 00000000
|
||||
b98: 00000000
|
||||
b9c: 00000000
|
||||
ba0: 00000000
|
||||
ba4: 00000000
|
||||
ba8: 00000000
|
||||
bac: 00000000
|
||||
bb0: 00000000
|
||||
bb4: 00000000
|
||||
bb8: 00000000
|
||||
bbc: 00000000
|
||||
bc0: 00000000
|
||||
bc4: 00000000
|
||||
bc8: 00000000
|
||||
bcc: 00000000
|
||||
bd0: 00000000
|
||||
bd4: 00000000
|
||||
bd8: 00000000
|
||||
bdc: 00000000
|
||||
be0: 00000000
|
||||
be4: 00000000
|
||||
be8: 00000000
|
||||
bec: 00000000
|
||||
bf0: 00000000
|
||||
bf4: 00000000
|
||||
bf8: 00000000
|
||||
bfc: 00000000
|
||||
e00: 00000468
|
||||
e04: 03030003
|
||||
e08: 03000305
|
||||
e0c: 00000007
|
||||
e10: 00000000
|
||||
e14: 00000000
|
||||
@@ -0,0 +1,706 @@
|
||||
000: 05ab0760
|
||||
004: 001c0900
|
||||
008: 00050200
|
||||
00c: 00020600
|
||||
010: 012937f8
|
||||
014: 00010000
|
||||
018: 40400040
|
||||
01c: 3f1a0000
|
||||
020: 00000000
|
||||
024: 00000000
|
||||
028: 00000000
|
||||
02c: 00000000
|
||||
030: 00000000
|
||||
034: 00000000
|
||||
038: 00000000
|
||||
03c: 00000003
|
||||
040: 03000029
|
||||
044: 00000000
|
||||
048: 00000024
|
||||
04c: 00000000
|
||||
050: 00600080
|
||||
054: 00000005
|
||||
058: 00000030
|
||||
05c: ef000029
|
||||
060: 00000300
|
||||
064: 00000114
|
||||
068: e3000029
|
||||
06c: 00000000
|
||||
070: 000004f0
|
||||
074: e3600090
|
||||
078: 00000307
|
||||
07c: 000006f8
|
||||
080: 00600000
|
||||
084: 00000000
|
||||
088: 00000740
|
||||
08c: 00600000
|
||||
090: 00000000
|
||||
094: 00000750
|
||||
098: 00600000
|
||||
09c: 00000000
|
||||
0a0: 00000760
|
||||
0a4: 00600000
|
||||
0a8: 00000000
|
||||
0ac: 00000770
|
||||
0b0: 00600000
|
||||
0b4: 00000000
|
||||
0b8: 00000780
|
||||
0bc: 00600000
|
||||
0c0: 00000000
|
||||
0c4: 00000790
|
||||
0c8: 00600000
|
||||
0cc: 00000000
|
||||
0d0: 000007a0
|
||||
0d4: 00600000
|
||||
0d8: 00000000
|
||||
0dc: 000007b0
|
||||
0e0: 00600000
|
||||
0e4: 00000000
|
||||
0e8: 000007c0
|
||||
0ec: 00600000
|
||||
0f0: 00000000
|
||||
0f4: 000007d0
|
||||
0f8: 00600000
|
||||
0fc: 00000000
|
||||
100: 000007e0
|
||||
104: 00600000
|
||||
108: 00000000
|
||||
10c: 000007f0
|
||||
110: 00600000
|
||||
114: 00000000
|
||||
118: 00000800
|
||||
11c: 00600000
|
||||
120: 00000000
|
||||
124: 00000810
|
||||
128: 00600000
|
||||
12c: 00000000
|
||||
130: 00000820
|
||||
134: 00600000
|
||||
138: 00000000
|
||||
13c: 00000830
|
||||
140: 00600000
|
||||
144: 00000000
|
||||
148: 00000840
|
||||
14c: 00600000
|
||||
150: 00000000
|
||||
154: 00000850
|
||||
158: 00600000
|
||||
15c: 00000000
|
||||
160: 00000860
|
||||
164: 00600000
|
||||
168: 00000000
|
||||
16c: 00000870
|
||||
170: 00600000
|
||||
174: 00000000
|
||||
178: 00000880
|
||||
17c: 00600000
|
||||
180: 00000000
|
||||
184: 00000890
|
||||
188: 00600000
|
||||
18c: 00000000
|
||||
190: 000008a0
|
||||
194: 00600000
|
||||
198: 00000000
|
||||
19c: 000008b0
|
||||
1a0: 00600000
|
||||
1a4: 00000000
|
||||
1a8: 000008c0
|
||||
1ac: 00600000
|
||||
1b0: 00000000
|
||||
1b4: 000008d0
|
||||
1b8: 00600000
|
||||
1bc: 00000000
|
||||
1c0: 000008e0
|
||||
1c4: 00600000
|
||||
1c8: 00000000
|
||||
1cc: 000008f0
|
||||
1d0: 00008281
|
||||
1d4: 00000000
|
||||
1d8: 00000000
|
||||
1dc: 00000000
|
||||
1e0: 00000000
|
||||
1e4: 00000000
|
||||
1e8: 00000000
|
||||
1ec: 00000000
|
||||
1f0: 00000000
|
||||
1f4: 00000000
|
||||
1f8: 00000000
|
||||
1fc: 00000000
|
||||
200: 00000000
|
||||
204: 00000000
|
||||
208: 00000000
|
||||
20c: 00000000
|
||||
210: 00000000
|
||||
214: 00000000
|
||||
218: 00000000
|
||||
21c: 00000000
|
||||
220: 00000000
|
||||
224: 00000000
|
||||
228: 00000000
|
||||
22c: 00000000
|
||||
230: 00000000
|
||||
234: 00000000
|
||||
238: 00000000
|
||||
23c: 00000000
|
||||
240: 00000000
|
||||
244: 00000000
|
||||
248: 00000000
|
||||
24c: 00000000
|
||||
250: 00000000
|
||||
254: 00000000
|
||||
258: 00000000
|
||||
25c: 00000000
|
||||
260: 00000000
|
||||
264: 00000000
|
||||
268: 00000000
|
||||
26c: 00000000
|
||||
270: 00000000
|
||||
274: 00000000
|
||||
278: 00000000
|
||||
27c: 00000000
|
||||
280: 00000000
|
||||
284: 00000000
|
||||
288: 00000000
|
||||
28c: 00000000
|
||||
290: 00000000
|
||||
294: 00000000
|
||||
298: 00000000
|
||||
29c: 00000000
|
||||
2a0: 00000000
|
||||
2a4: 00000000
|
||||
2a8: 00000000
|
||||
2ac: 00000000
|
||||
2b0: 00000000
|
||||
2b4: 00000000
|
||||
2b8: 00000000
|
||||
2bc: 00000000
|
||||
2c0: 00000000
|
||||
2c4: 00000000
|
||||
2c8: 00000000
|
||||
2cc: 00000000
|
||||
2d0: 00000000
|
||||
2d4: 00000000
|
||||
2d8: 00000000
|
||||
2dc: 00000000
|
||||
2e0: 00000000
|
||||
2e4: 00000000
|
||||
2e8: 00000000
|
||||
2ec: 00000000
|
||||
400: 00000002
|
||||
404: 00000008
|
||||
408: 002badca
|
||||
40c: 00000002
|
||||
410: 00000208
|
||||
414: 00a5e13a
|
||||
418: 00000002
|
||||
41c: 00000408
|
||||
420: 01202382
|
||||
424: 00000000
|
||||
428: 00000000
|
||||
42c: 00000000
|
||||
430: 00000002
|
||||
434: 00000008
|
||||
438: 002badca
|
||||
43c: 00000000
|
||||
440: 00000000
|
||||
444: 00000000
|
||||
448: 00000000
|
||||
44c: 00000000
|
||||
450: 00000000
|
||||
454: 00000000
|
||||
458: 00000000
|
||||
45c: 00000000
|
||||
460: 00000000
|
||||
464: 00000000
|
||||
468: 00000000
|
||||
46c: 00000000
|
||||
470: 00000000
|
||||
474: 00000000
|
||||
478: 00000000
|
||||
47c: 00000002
|
||||
480: 00000008
|
||||
484: 00a5e13a
|
||||
488: 00000001
|
||||
48c: 00000000
|
||||
490: 00000000
|
||||
494: 00000000
|
||||
498: 00000000
|
||||
49c: 00000000
|
||||
4a0: 00000000
|
||||
4a4: 00000000
|
||||
4a8: 00000000
|
||||
4ac: 00000000
|
||||
4b0: 00000000
|
||||
4b4: 00000000
|
||||
4b8: 00000000
|
||||
4bc: 00000000
|
||||
4c0: 00000000
|
||||
4c4: 00000000
|
||||
4c8: 00000002
|
||||
4cc: 00000008
|
||||
4d0: 01202382
|
||||
4d4: 00000002
|
||||
4d8: 00000000
|
||||
4dc: 00000000
|
||||
4e0: 00000000
|
||||
4e4: 00000000
|
||||
4e8: 00000000
|
||||
4ec: 00000000
|
||||
4f0: 00000000
|
||||
4f4: 00000000
|
||||
4f8: 00000000
|
||||
4fc: 00000000
|
||||
500: 00000000
|
||||
504: 00000000
|
||||
508: 00000000
|
||||
50c: 00000000
|
||||
510: 00000000
|
||||
514: 00000000
|
||||
518: 00000000
|
||||
51c: 00000000
|
||||
520: 00000000
|
||||
524: 00000000
|
||||
528: 00000000
|
||||
52c: 00000000
|
||||
530: 00000000
|
||||
534: 00000000
|
||||
538: 00000000
|
||||
53c: 00000000
|
||||
540: 00000000
|
||||
544: 00000000
|
||||
548: 00000000
|
||||
54c: 00000000
|
||||
550: 00000000
|
||||
554: 00000000
|
||||
558: 00000000
|
||||
55c: 00000000
|
||||
560: 00000000
|
||||
564: 00000000
|
||||
568: 00000000
|
||||
56c: 00000000
|
||||
570: 00000000
|
||||
574: 00000000
|
||||
578: 00000000
|
||||
57c: 00000000
|
||||
580: 00000000
|
||||
584: 00000000
|
||||
588: 00000000
|
||||
58c: 00000000
|
||||
590: 00000000
|
||||
594: 00000000
|
||||
598: 00000000
|
||||
59c: 00000000
|
||||
5a0: 00000000
|
||||
5a4: 00000000
|
||||
5a8: 00000000
|
||||
5ac: 00000000
|
||||
5b0: 00000000
|
||||
5b4: 00000000
|
||||
5b8: 00000000
|
||||
5bc: 00000000
|
||||
5c0: 00000000
|
||||
5c4: 00000000
|
||||
5c8: 00000000
|
||||
5cc: 00000000
|
||||
5d0: 00000000
|
||||
5d4: 00000000
|
||||
5d8: 00000000
|
||||
5dc: 00000000
|
||||
5e0: 00000000
|
||||
5e4: 00000000
|
||||
5e8: 00000000
|
||||
5ec: 00000000
|
||||
5f0: 00000000
|
||||
5f4: 00000000
|
||||
5f8: 00000000
|
||||
5fc: 00000000
|
||||
600: 00000000
|
||||
604: 00000000
|
||||
608: 00000000
|
||||
60c: 00000000
|
||||
610: 00000000
|
||||
614: 00000000
|
||||
618: 00000000
|
||||
61c: 00000000
|
||||
620: 00000000
|
||||
624: 00000000
|
||||
628: 00000000
|
||||
62c: 00000000
|
||||
630: 00000000
|
||||
634: 00000000
|
||||
638: 00000000
|
||||
63c: 00000000
|
||||
640: 00000000
|
||||
644: 00000000
|
||||
648: 00000000
|
||||
64c: 00000000
|
||||
650: 00000000
|
||||
654: 00000000
|
||||
658: 00000000
|
||||
65c: 00000000
|
||||
660: 00000000
|
||||
664: 00000000
|
||||
668: 00000000
|
||||
66c: 00000000
|
||||
670: 00000000
|
||||
674: 00000000
|
||||
678: 00000000
|
||||
67c: 00000000
|
||||
680: 00000000
|
||||
684: 00000000
|
||||
688: 00000000
|
||||
68c: 00000000
|
||||
690: 00000000
|
||||
694: 00000000
|
||||
698: 00000000
|
||||
69c: 00000000
|
||||
6a0: 00000000
|
||||
6a4: 00000000
|
||||
6a8: 00000000
|
||||
6ac: 00000000
|
||||
6b0: 00000000
|
||||
6b4: 00000000
|
||||
6b8: 00000000
|
||||
6bc: 00000000
|
||||
6c0: 00000000
|
||||
6c4: 00000000
|
||||
6c8: 00000000
|
||||
6cc: 00000000
|
||||
6d0: 00000000
|
||||
6d4: 00000000
|
||||
6d8: 00000000
|
||||
6dc: 00000000
|
||||
6e0: 00000000
|
||||
6e4: 00000000
|
||||
6e8: 00000000
|
||||
6ec: 00000000
|
||||
6f0: 00000000
|
||||
6f4: 00000000
|
||||
6f8: 00000000
|
||||
6fc: 00000000
|
||||
700: 00000000
|
||||
704: 00000000
|
||||
708: 00000000
|
||||
70c: 00000000
|
||||
710: 00000000
|
||||
714: 00000000
|
||||
718: 00000000
|
||||
71c: 00000000
|
||||
720: 00000000
|
||||
724: 00000000
|
||||
728: 00000000
|
||||
72c: 00000000
|
||||
730: 00000000
|
||||
734: 00000000
|
||||
738: 00000000
|
||||
73c: 00000000
|
||||
740: 00000000
|
||||
744: 00000000
|
||||
748: 00000000
|
||||
74c: 00000000
|
||||
750: 00000000
|
||||
754: 00000000
|
||||
758: 00000000
|
||||
75c: 00000000
|
||||
760: 00000000
|
||||
764: 00000000
|
||||
768: 00000000
|
||||
76c: 00000000
|
||||
770: 00000000
|
||||
774: 00000000
|
||||
778: 00000000
|
||||
77c: 00000000
|
||||
780: 00000000
|
||||
784: 00000000
|
||||
788: 00000000
|
||||
78c: 00000000
|
||||
790: 00000000
|
||||
794: 00000000
|
||||
798: 00000000
|
||||
79c: 00000000
|
||||
7a0: 00000000
|
||||
7a4: 00000000
|
||||
7a8: 00000000
|
||||
7ac: 00000000
|
||||
7b0: 00000000
|
||||
7b4: 00000000
|
||||
7b8: 00000000
|
||||
7bc: 00000000
|
||||
7c0: 00000000
|
||||
7c4: 00000000
|
||||
7c8: 00000000
|
||||
7cc: 00000000
|
||||
7d0: 00000000
|
||||
7d4: 00000000
|
||||
7d8: 00000000
|
||||
7dc: 00000000
|
||||
7e0: 00000000
|
||||
7e4: 00000000
|
||||
7e8: 00000000
|
||||
7ec: 00000000
|
||||
7f0: 00000000
|
||||
7f4: 00000000
|
||||
7f8: 00000000
|
||||
7fc: 00000000
|
||||
800: 00000000
|
||||
804: 00000000
|
||||
808: 00000000
|
||||
80c: 00000000
|
||||
810: 00000000
|
||||
814: 00000000
|
||||
818: 00000000
|
||||
81c: 00000000
|
||||
820: 00000000
|
||||
824: 00000000
|
||||
828: 00000000
|
||||
82c: 00000000
|
||||
830: 00000000
|
||||
834: 00000000
|
||||
838: 00000000
|
||||
83c: 00000000
|
||||
840: 00000000
|
||||
844: 00000000
|
||||
848: 00000000
|
||||
84c: 00000000
|
||||
850: 00000000
|
||||
854: 00000000
|
||||
858: 00000000
|
||||
85c: 00000000
|
||||
860: 00000000
|
||||
864: 00000000
|
||||
868: 00000000
|
||||
86c: 00000000
|
||||
870: 00000000
|
||||
874: 00000000
|
||||
878: 00000000
|
||||
87c: 00000000
|
||||
880: 00000000
|
||||
884: 00000000
|
||||
888: 00000000
|
||||
88c: 00000000
|
||||
890: 00000000
|
||||
894: 00000000
|
||||
898: 00000000
|
||||
89c: 00000000
|
||||
8a0: 00000000
|
||||
8a4: 00000000
|
||||
8a8: 00000000
|
||||
8ac: 00000000
|
||||
8b0: 00000000
|
||||
8b4: 00000000
|
||||
8b8: 00000000
|
||||
8bc: 00000000
|
||||
8c0: 00000000
|
||||
8c4: 00000000
|
||||
8c8: 00000000
|
||||
8cc: 00000000
|
||||
8d0: 00000000
|
||||
8d4: 00000000
|
||||
8d8: 00000000
|
||||
8dc: 00000000
|
||||
8e0: 00000000
|
||||
8e4: 00000000
|
||||
8e8: 00000000
|
||||
8ec: 00000000
|
||||
8f0: 00000000
|
||||
8f4: 00000000
|
||||
8f8: 00000000
|
||||
8fc: 00000000
|
||||
900: 00000000
|
||||
904: 00000000
|
||||
908: 00000000
|
||||
90c: 00000000
|
||||
910: 00000000
|
||||
914: 00000000
|
||||
918: 00000000
|
||||
91c: 00000000
|
||||
920: 00000000
|
||||
924: 00000000
|
||||
928: 00000000
|
||||
92c: 00000000
|
||||
930: 00000000
|
||||
934: 00000000
|
||||
938: 00000000
|
||||
93c: 00000000
|
||||
940: 00000000
|
||||
944: 00000000
|
||||
948: 00000000
|
||||
94c: 00000000
|
||||
950: 00000000
|
||||
954: 00000000
|
||||
958: 00000000
|
||||
95c: 00000000
|
||||
960: 00000000
|
||||
964: 00000000
|
||||
968: 00000000
|
||||
96c: 00000000
|
||||
970: 00000000
|
||||
974: 00000000
|
||||
978: 00000000
|
||||
97c: 00000000
|
||||
980: 00000000
|
||||
984: 00000000
|
||||
988: 00000000
|
||||
98c: 00000000
|
||||
990: 00000000
|
||||
994: 00000000
|
||||
998: 00000000
|
||||
99c: 00000000
|
||||
9a0: 00000000
|
||||
9a4: 00000000
|
||||
9a8: 00000000
|
||||
9ac: 00000000
|
||||
9b0: 00000000
|
||||
9b4: 00000000
|
||||
9b8: 00000000
|
||||
9bc: 00000000
|
||||
9c0: 00000000
|
||||
9c4: 00000000
|
||||
9c8: 00000000
|
||||
9cc: 00000000
|
||||
9d0: 00000000
|
||||
9d4: 00000000
|
||||
9d8: 00000000
|
||||
9dc: 00000000
|
||||
9e0: 00000000
|
||||
9e4: 00000000
|
||||
9e8: 00000000
|
||||
9ec: 00000000
|
||||
9f0: 00000000
|
||||
9f4: 00000000
|
||||
9f8: 00000000
|
||||
9fc: 00000000
|
||||
a00: 00000000
|
||||
a04: 00000000
|
||||
a08: 00000000
|
||||
a0c: 00000000
|
||||
a10: 00000000
|
||||
a14: 00000000
|
||||
a18: 00000000
|
||||
a1c: 00000000
|
||||
a20: 00000002
|
||||
a24: 00000008
|
||||
a28: 00000000
|
||||
a2c: 00000000
|
||||
a30: 00000000
|
||||
a34: 00000000
|
||||
a38: 00000000
|
||||
a3c: 00000000
|
||||
a40: 00000000
|
||||
a44: 00000000
|
||||
a48: 00000000
|
||||
a4c: 00000000
|
||||
a50: 00000000
|
||||
a54: 00000000
|
||||
a58: 00000000
|
||||
a5c: 00000000
|
||||
a60: 00000000
|
||||
a64: 00000000
|
||||
a68: 00000002
|
||||
a6c: 00000208
|
||||
a70: 00000001
|
||||
a74: 00000000
|
||||
a78: 00000000
|
||||
a7c: 00000000
|
||||
a80: 00000000
|
||||
a84: 00000000
|
||||
a88: 00000000
|
||||
a8c: 00000000
|
||||
a90: 00000000
|
||||
a94: 00000000
|
||||
a98: 00000000
|
||||
a9c: 00000000
|
||||
aa0: 00000000
|
||||
aa4: 00000000
|
||||
aa8: 00000000
|
||||
aac: 00000000
|
||||
ab0: 00000002
|
||||
ab4: 00000408
|
||||
ab8: 00000002
|
||||
abc: 00000000
|
||||
ac0: 00000000
|
||||
ac4: 00000000
|
||||
ac8: 00000000
|
||||
acc: 00000000
|
||||
ad0: 00000000
|
||||
ad4: 00000000
|
||||
ad8: 00000000
|
||||
adc: 00000000
|
||||
ae0: 00000000
|
||||
ae4: 00000000
|
||||
ae8: 00000000
|
||||
aec: 00000000
|
||||
af0: 00000000
|
||||
af4: 00000000
|
||||
af8: 00000000
|
||||
afc: 00000000
|
||||
b00: 00000000
|
||||
b04: 00000000
|
||||
b08: 00000000
|
||||
b0c: 00000000
|
||||
b10: 00000000
|
||||
b14: 00000000
|
||||
b18: 00000000
|
||||
b1c: 00000000
|
||||
b20: 00000000
|
||||
b24: 00000000
|
||||
b28: 00000000
|
||||
b2c: 00000000
|
||||
b30: 00000000
|
||||
b34: 00000000
|
||||
b38: 00000000
|
||||
b3c: 00000000
|
||||
b40: 00000000
|
||||
b44: 00000000
|
||||
b48: 00000000
|
||||
b4c: 00000000
|
||||
b50: 00000000
|
||||
b54: 00000000
|
||||
b58: 00000000
|
||||
b5c: 00000000
|
||||
b60: 00000000
|
||||
b64: 00000000
|
||||
b68: 00000000
|
||||
b6c: 00000000
|
||||
b70: 00000000
|
||||
b74: 00000000
|
||||
b78: 00000000
|
||||
b7c: 00000000
|
||||
b80: 00000000
|
||||
b84: 00000000
|
||||
b88: 00000000
|
||||
b8c: 00000000
|
||||
b90: 00000000
|
||||
b94: 00000000
|
||||
b98: 00000000
|
||||
b9c: 00000000
|
||||
ba0: 00000000
|
||||
ba4: 00000000
|
||||
ba8: 00000000
|
||||
bac: 00000000
|
||||
bb0: 00000000
|
||||
bb4: 00000000
|
||||
bb8: 00000000
|
||||
bbc: 00000000
|
||||
bc0: 00000000
|
||||
bc4: 00000000
|
||||
bc8: 00000000
|
||||
bcc: 00000000
|
||||
bd0: 00000000
|
||||
bd4: 00000000
|
||||
bd8: 00000000
|
||||
bdc: 00000000
|
||||
be0: 00000000
|
||||
be4: 00000000
|
||||
be8: 00000000
|
||||
bec: 00000000
|
||||
bf0: 00000000
|
||||
bf4: 00000000
|
||||
bf8: 00000000
|
||||
bfc: 00000000
|
||||
e00: 00000468
|
||||
e04: 03030003
|
||||
e08: 03000305
|
||||
e0c: 00000007
|
||||
e10: 00000000
|
||||
e14: 00000000
|
||||
@@ -0,0 +1,706 @@
|
||||
000: 024b0760
|
||||
004: 001c0900
|
||||
008: 000e0303
|
||||
00c: 00021000
|
||||
010: 0380d6b3
|
||||
014: 00010000
|
||||
018: 40400040
|
||||
01c: 3f1a0000
|
||||
020: 00000000
|
||||
024: 00000000
|
||||
028: 00000000
|
||||
02c: 00000000
|
||||
030: 00000000
|
||||
034: 00000000
|
||||
038: 00000000
|
||||
03c: 00000007
|
||||
040: 07000029
|
||||
044: 00000000
|
||||
048: 00000054
|
||||
04c: 00000000
|
||||
050: 00600080
|
||||
054: 00000005
|
||||
058: 00000060
|
||||
05c: 07600090
|
||||
060: 00000707
|
||||
064: 000000d0
|
||||
068: 1f000029
|
||||
06c: 00000700
|
||||
070: 0000016c
|
||||
074: 00600000
|
||||
078: 00000000
|
||||
07c: 00000360
|
||||
080: 00600000
|
||||
084: 00000000
|
||||
088: 00000370
|
||||
08c: 00600000
|
||||
090: 00000000
|
||||
094: 00000380
|
||||
098: 00600000
|
||||
09c: 00000000
|
||||
0a0: 00000390
|
||||
0a4: 00600000
|
||||
0a8: 00000000
|
||||
0ac: 000003a0
|
||||
0b0: 00600000
|
||||
0b4: 00000000
|
||||
0b8: 000003b0
|
||||
0bc: 00600000
|
||||
0c0: 00000000
|
||||
0c4: 000003c0
|
||||
0c8: 00600000
|
||||
0cc: 00000000
|
||||
0d0: 000003d0
|
||||
0d4: 00600000
|
||||
0d8: 00000000
|
||||
0dc: 000003e0
|
||||
0e0: 00600000
|
||||
0e4: 00000000
|
||||
0e8: 000003f0
|
||||
0ec: 00600000
|
||||
0f0: 00000000
|
||||
0f4: 00000400
|
||||
0f8: 00600000
|
||||
0fc: 00000000
|
||||
100: 00000410
|
||||
104: 00600000
|
||||
108: 00000000
|
||||
10c: 00000420
|
||||
110: 00600000
|
||||
114: 00000000
|
||||
118: 00000430
|
||||
11c: 00600000
|
||||
120: 00000000
|
||||
124: 00000440
|
||||
128: 00600000
|
||||
12c: 00000000
|
||||
130: 00000450
|
||||
134: 00600000
|
||||
138: 00000000
|
||||
13c: 00000460
|
||||
140: 00600000
|
||||
144: 00000000
|
||||
148: 00000470
|
||||
14c: 00600000
|
||||
150: 00000000
|
||||
154: 00000480
|
||||
158: 00600000
|
||||
15c: 00000000
|
||||
160: 00000490
|
||||
164: 00600000
|
||||
168: 00000000
|
||||
16c: 000004a0
|
||||
170: 00600000
|
||||
174: 00000000
|
||||
178: 000004b0
|
||||
17c: 00600000
|
||||
180: 00000000
|
||||
184: 000004c0
|
||||
188: 00600000
|
||||
18c: 00000000
|
||||
190: 000004d0
|
||||
194: 00600000
|
||||
198: 00000000
|
||||
19c: 000004e0
|
||||
1a0: 00600000
|
||||
1a4: 00000000
|
||||
1a8: 000004f0
|
||||
1ac: 00600000
|
||||
1b0: 00000000
|
||||
1b4: 00000500
|
||||
1b8: 00600000
|
||||
1bc: 00000000
|
||||
1c0: 00000510
|
||||
1c4: 00600000
|
||||
1c8: 00000000
|
||||
1cc: 00000520
|
||||
1d0: 00000082
|
||||
1d4: 00000000
|
||||
1d8: 00000000
|
||||
1dc: 00000000
|
||||
1e0: 00000000
|
||||
1e4: 00000000
|
||||
1e8: 00000000
|
||||
1ec: 00000000
|
||||
1f0: 00000000
|
||||
1f4: 00000000
|
||||
1f8: 00000000
|
||||
1fc: 00000000
|
||||
200: 00000000
|
||||
204: 00000000
|
||||
208: 00000000
|
||||
20c: 00000000
|
||||
210: 00000000
|
||||
214: 00000000
|
||||
218: 00000000
|
||||
21c: 00000000
|
||||
220: 00000000
|
||||
224: 00000000
|
||||
228: 00000000
|
||||
22c: 00000000
|
||||
230: 00000000
|
||||
234: 00000000
|
||||
238: 00000000
|
||||
23c: 00000000
|
||||
240: 00000000
|
||||
244: 00000000
|
||||
248: 00000000
|
||||
24c: 00000000
|
||||
250: 00000000
|
||||
254: 00000000
|
||||
258: 00000000
|
||||
25c: 00000000
|
||||
260: 00000000
|
||||
264: 00000000
|
||||
268: 00000000
|
||||
26c: 00000000
|
||||
270: 00000000
|
||||
274: 00000000
|
||||
278: 00000000
|
||||
27c: 00000000
|
||||
280: 00000000
|
||||
284: 00000000
|
||||
288: 00000000
|
||||
28c: 00000000
|
||||
290: 00000000
|
||||
294: 00000000
|
||||
298: 00000000
|
||||
29c: 00000000
|
||||
2a0: 00000000
|
||||
2a4: 00000000
|
||||
2a8: 00000000
|
||||
2ac: 00000000
|
||||
2b0: 00000000
|
||||
2b4: 00000000
|
||||
2b8: 00000000
|
||||
2bc: 00000000
|
||||
2c0: 00000000
|
||||
2c4: 00000000
|
||||
2c8: 00000000
|
||||
2cc: 00000000
|
||||
2d0: 00000000
|
||||
2d4: 00000000
|
||||
2d8: 00000000
|
||||
2dc: 00000000
|
||||
2e0: 00000000
|
||||
2e4: 00000000
|
||||
2e8: 00000000
|
||||
2ec: 00000000
|
||||
400: 00000002
|
||||
404: 00000008
|
||||
408: 00640279
|
||||
40c: 00000002
|
||||
410: 00000208
|
||||
414: 00e52ec1
|
||||
418: 00000002
|
||||
41c: 00000408
|
||||
420: 01627f61
|
||||
424: 00000002
|
||||
428: 00000608
|
||||
42c: 01e002a1
|
||||
430: 00000002
|
||||
434: 00000808
|
||||
438: 025f8459
|
||||
43c: 00000002
|
||||
440: 00000a08
|
||||
444: 02dc5e61
|
||||
448: 00000002
|
||||
44c: 00000c08
|
||||
450: 0359f7d1
|
||||
454: 00000000
|
||||
458: 00000000
|
||||
45c: 00000000
|
||||
460: 00000002
|
||||
464: 00000008
|
||||
468: 00000000
|
||||
46c: 00000000
|
||||
470: 00000002
|
||||
474: 00000208
|
||||
478: 00000001
|
||||
47c: 00000000
|
||||
480: 00000002
|
||||
484: 00000408
|
||||
488: 00000002
|
||||
48c: 00000000
|
||||
490: 00000002
|
||||
494: 00000608
|
||||
498: 00000003
|
||||
49c: 00000000
|
||||
4a0: 00000002
|
||||
4a4: 00000808
|
||||
4a8: 00000004
|
||||
4ac: 00000000
|
||||
4b0: 00000002
|
||||
4b4: 00000a08
|
||||
4b8: 00000005
|
||||
4bc: 00000000
|
||||
4c0: 00000002
|
||||
4c4: 00000c08
|
||||
4c8: 00000006
|
||||
4cc: 00000000
|
||||
4d0: 00000000
|
||||
4d4: 00000000
|
||||
4d8: 00000000
|
||||
4dc: 00000000
|
||||
4e0: 00000002
|
||||
4e4: 00000008
|
||||
4e8: 00640279
|
||||
4ec: 00000000
|
||||
4f0: 00000000
|
||||
4f4: 00000002
|
||||
4f8: 00000008
|
||||
4fc: 00e52ec1
|
||||
500: 00000001
|
||||
504: 00000000
|
||||
508: 00000002
|
||||
50c: 00000008
|
||||
510: 01627f61
|
||||
514: 00000002
|
||||
518: 00000000
|
||||
51c: 00000002
|
||||
520: 00000008
|
||||
524: 01e002a1
|
||||
528: 00000003
|
||||
52c: 00000000
|
||||
530: 00000002
|
||||
534: 00000008
|
||||
538: 025f8459
|
||||
53c: 00000004
|
||||
540: 00000000
|
||||
544: 00000002
|
||||
548: 00000008
|
||||
54c: 02dc5e61
|
||||
550: 00000005
|
||||
554: 00000000
|
||||
558: 00000002
|
||||
55c: 00000008
|
||||
560: 0359f7d1
|
||||
564: 00000006
|
||||
568: 00000000
|
||||
56c: 00000000
|
||||
570: 00000000
|
||||
574: 00000000
|
||||
578: 00000000
|
||||
57c: 00000000
|
||||
580: 00000000
|
||||
584: 00000000
|
||||
588: 00000000
|
||||
58c: 00000000
|
||||
590: 00000000
|
||||
594: 00000000
|
||||
598: 00000000
|
||||
59c: 00000000
|
||||
5a0: 00000000
|
||||
5a4: 00000000
|
||||
5a8: 00000000
|
||||
5ac: 00000000
|
||||
5b0: 00000000
|
||||
5b4: 00000000
|
||||
5b8: 00000000
|
||||
5bc: 00000000
|
||||
5c0: 00000000
|
||||
5c4: 00000000
|
||||
5c8: 00000000
|
||||
5cc: 00000000
|
||||
5d0: 00000000
|
||||
5d4: 00000000
|
||||
5d8: 00000000
|
||||
5dc: 00000000
|
||||
5e0: 00000000
|
||||
5e4: 00000000
|
||||
5e8: 00000000
|
||||
5ec: 00000000
|
||||
5f0: 00000000
|
||||
5f4: 00000000
|
||||
5f8: 00000000
|
||||
5fc: 00000000
|
||||
600: 00000000
|
||||
604: 00000000
|
||||
608: 00000000
|
||||
60c: 00000000
|
||||
610: 00000000
|
||||
614: 00000000
|
||||
618: 00000000
|
||||
61c: 00000000
|
||||
620: 00000000
|
||||
624: 00000000
|
||||
628: 00000000
|
||||
62c: 00000000
|
||||
630: 00000000
|
||||
634: 00000000
|
||||
638: 00000000
|
||||
63c: 00000000
|
||||
640: 00000000
|
||||
644: 00000000
|
||||
648: 00000000
|
||||
64c: 00000000
|
||||
650: 00000000
|
||||
654: 00000000
|
||||
658: 00000000
|
||||
65c: 00000000
|
||||
660: 00000000
|
||||
664: 00000000
|
||||
668: 00000000
|
||||
66c: 00000000
|
||||
670: 00000000
|
||||
674: 00000000
|
||||
678: 00000000
|
||||
67c: 00000000
|
||||
680: 00000000
|
||||
684: 00000000
|
||||
688: 00000000
|
||||
68c: 00000000
|
||||
690: 00000000
|
||||
694: 00000000
|
||||
698: 00000000
|
||||
69c: 00000000
|
||||
6a0: 00000000
|
||||
6a4: 00000000
|
||||
6a8: 00000000
|
||||
6ac: 00000000
|
||||
6b0: 00000000
|
||||
6b4: 00000000
|
||||
6b8: 00000000
|
||||
6bc: 00000000
|
||||
6c0: 00000000
|
||||
6c4: 00000000
|
||||
6c8: 00000000
|
||||
6cc: 00000000
|
||||
6d0: 00000000
|
||||
6d4: 00000000
|
||||
6d8: 00000000
|
||||
6dc: 00000000
|
||||
6e0: 00000000
|
||||
6e4: 00000000
|
||||
6e8: 00000000
|
||||
6ec: 00000000
|
||||
6f0: 00000000
|
||||
6f4: 00000000
|
||||
6f8: 00000000
|
||||
6fc: 00000000
|
||||
700: 00000000
|
||||
704: 00000000
|
||||
708: 00000000
|
||||
70c: 00000000
|
||||
710: 00000000
|
||||
714: 00000000
|
||||
718: 00000000
|
||||
71c: 00000000
|
||||
720: 00000000
|
||||
724: 00000000
|
||||
728: 00000000
|
||||
72c: 00000000
|
||||
730: 00000000
|
||||
734: 00000000
|
||||
738: 00000000
|
||||
73c: 00000000
|
||||
740: 00000000
|
||||
744: 00000000
|
||||
748: 00000000
|
||||
74c: 00000000
|
||||
750: 00000000
|
||||
754: 00000000
|
||||
758: 00000000
|
||||
75c: 00000000
|
||||
760: 00000000
|
||||
764: 00000000
|
||||
768: 00000000
|
||||
76c: 00000000
|
||||
770: 00000000
|
||||
774: 00000000
|
||||
778: 00000000
|
||||
77c: 00000000
|
||||
780: 00000000
|
||||
784: 00000000
|
||||
788: 00000000
|
||||
78c: 00000000
|
||||
790: 00000000
|
||||
794: 00000000
|
||||
798: 00000000
|
||||
79c: 00000000
|
||||
7a0: 00000000
|
||||
7a4: 00000000
|
||||
7a8: 00000000
|
||||
7ac: 00000000
|
||||
7b0: 00000000
|
||||
7b4: 00000000
|
||||
7b8: 00000000
|
||||
7bc: 00000000
|
||||
7c0: 00000000
|
||||
7c4: 00000000
|
||||
7c8: 00000000
|
||||
7cc: 00000000
|
||||
7d0: 00000000
|
||||
7d4: 00000000
|
||||
7d8: 00000000
|
||||
7dc: 00000000
|
||||
7e0: 00000000
|
||||
7e4: 00000000
|
||||
7e8: 00000000
|
||||
7ec: 00000000
|
||||
7f0: 00000000
|
||||
7f4: 00000000
|
||||
7f8: 00000000
|
||||
7fc: 00000000
|
||||
800: 00000000
|
||||
804: 00000000
|
||||
808: 00000000
|
||||
80c: 00000000
|
||||
810: 00000000
|
||||
814: 00000000
|
||||
818: 00000000
|
||||
81c: 00000000
|
||||
820: 00000000
|
||||
824: 00000000
|
||||
828: 00000000
|
||||
82c: 00000000
|
||||
830: 00000000
|
||||
834: 00000000
|
||||
838: 00000000
|
||||
83c: 00000000
|
||||
840: 00000000
|
||||
844: 00000000
|
||||
848: 00000000
|
||||
84c: 00000000
|
||||
850: 00000000
|
||||
854: 00000000
|
||||
858: 00000000
|
||||
85c: 00000000
|
||||
860: 00000000
|
||||
864: 00000000
|
||||
868: 00000000
|
||||
86c: 00000000
|
||||
870: 00000000
|
||||
874: 00000000
|
||||
878: 00000000
|
||||
87c: 00000000
|
||||
880: 00000000
|
||||
884: 00000000
|
||||
888: 00000000
|
||||
88c: 00000000
|
||||
890: 00000000
|
||||
894: 00000000
|
||||
898: 00000000
|
||||
89c: 00000000
|
||||
8a0: 00000000
|
||||
8a4: 00000000
|
||||
8a8: 00000000
|
||||
8ac: 00000000
|
||||
8b0: 00000000
|
||||
8b4: 00000000
|
||||
8b8: 00000000
|
||||
8bc: 00000000
|
||||
8c0: 00000000
|
||||
8c4: 00000000
|
||||
8c8: 00000000
|
||||
8cc: 00000000
|
||||
8d0: 00000000
|
||||
8d4: 00000000
|
||||
8d8: 00000000
|
||||
8dc: 00000000
|
||||
8e0: 00000000
|
||||
8e4: 00000000
|
||||
8e8: 00000000
|
||||
8ec: 00000000
|
||||
8f0: 00000000
|
||||
8f4: 00000000
|
||||
8f8: 00000000
|
||||
8fc: 00000000
|
||||
900: 00000000
|
||||
904: 00000000
|
||||
908: 00000000
|
||||
90c: 00000000
|
||||
910: 00000000
|
||||
914: 00000000
|
||||
918: 00000000
|
||||
91c: 00000000
|
||||
920: 00000000
|
||||
924: 00000000
|
||||
928: 00000000
|
||||
92c: 00000000
|
||||
930: 00000000
|
||||
934: 00000000
|
||||
938: 00000000
|
||||
93c: 00000000
|
||||
940: 00000000
|
||||
944: 00000000
|
||||
948: 00000000
|
||||
94c: 00000000
|
||||
950: 00000000
|
||||
954: 00000000
|
||||
958: 00000000
|
||||
95c: 00000000
|
||||
960: 00000000
|
||||
964: 00000000
|
||||
968: 00000000
|
||||
96c: 00000000
|
||||
970: 00000000
|
||||
974: 00000000
|
||||
978: 00000000
|
||||
97c: 00000000
|
||||
980: 00000000
|
||||
984: 00000000
|
||||
988: 00000000
|
||||
98c: 00000000
|
||||
990: 00000000
|
||||
994: 00000000
|
||||
998: 00000000
|
||||
99c: 00000000
|
||||
9a0: 00000000
|
||||
9a4: 00000000
|
||||
9a8: 00000000
|
||||
9ac: 00000000
|
||||
9b0: 00000000
|
||||
9b4: 00000000
|
||||
9b8: 00000000
|
||||
9bc: 00000000
|
||||
9c0: 00000000
|
||||
9c4: 00000000
|
||||
9c8: 00000000
|
||||
9cc: 00000000
|
||||
9d0: 00000000
|
||||
9d4: 00000000
|
||||
9d8: 00000000
|
||||
9dc: 00000000
|
||||
9e0: 00000000
|
||||
9e4: 00000000
|
||||
9e8: 00000000
|
||||
9ec: 00000000
|
||||
9f0: 00000000
|
||||
9f4: 00000000
|
||||
9f8: 00000000
|
||||
9fc: 00000000
|
||||
a00: 00000000
|
||||
a04: 00000000
|
||||
a08: 00000000
|
||||
a0c: 00000000
|
||||
a10: 00000000
|
||||
a14: 00000000
|
||||
a18: 00000000
|
||||
a1c: 00000000
|
||||
a20: 00000000
|
||||
a24: 00000000
|
||||
a28: 00000000
|
||||
a2c: 00000000
|
||||
a30: 00000000
|
||||
a34: 00000000
|
||||
a38: 00000000
|
||||
a3c: 00000000
|
||||
a40: 00000000
|
||||
a44: 00000000
|
||||
a48: 00000000
|
||||
a4c: 00000000
|
||||
a50: 00000000
|
||||
a54: 00000000
|
||||
a58: 00000000
|
||||
a5c: 00000000
|
||||
a60: 00000000
|
||||
a64: 00000000
|
||||
a68: 00000000
|
||||
a6c: 00000000
|
||||
a70: 00000000
|
||||
a74: 00000000
|
||||
a78: 00000000
|
||||
a7c: 00000000
|
||||
a80: 00000000
|
||||
a84: 00000000
|
||||
a88: 00000000
|
||||
a8c: 00000000
|
||||
a90: 00000000
|
||||
a94: 00000000
|
||||
a98: 00000000
|
||||
a9c: 00000000
|
||||
aa0: 00000000
|
||||
aa4: 00000000
|
||||
aa8: 00000000
|
||||
aac: 00000000
|
||||
ab0: 00000000
|
||||
ab4: 00000000
|
||||
ab8: 00000000
|
||||
abc: 00000000
|
||||
ac0: 00000000
|
||||
ac4: 00000000
|
||||
ac8: 00000000
|
||||
acc: 00000000
|
||||
ad0: 00000000
|
||||
ad4: 00000000
|
||||
ad8: 00000000
|
||||
adc: 00000000
|
||||
ae0: 00000000
|
||||
ae4: 00000000
|
||||
ae8: 00000000
|
||||
aec: 00000000
|
||||
af0: 00000000
|
||||
af4: 00000000
|
||||
af8: 00000000
|
||||
afc: 00000000
|
||||
b00: 00000000
|
||||
b04: 00000000
|
||||
b08: 00000000
|
||||
b0c: 00000000
|
||||
b10: 00000000
|
||||
b14: 00000000
|
||||
b18: 00000000
|
||||
b1c: 00000000
|
||||
b20: 00000000
|
||||
b24: 00000000
|
||||
b28: 00000000
|
||||
b2c: 00000000
|
||||
b30: 00000000
|
||||
b34: 00000000
|
||||
b38: 00000000
|
||||
b3c: 00000000
|
||||
b40: 00000000
|
||||
b44: 00000000
|
||||
b48: 00000000
|
||||
b4c: 00000000
|
||||
b50: 00000000
|
||||
b54: 00000000
|
||||
b58: 00000000
|
||||
b5c: 00000000
|
||||
b60: 00000000
|
||||
b64: 00000000
|
||||
b68: 00000000
|
||||
b6c: 00000000
|
||||
b70: 00000000
|
||||
b74: 00000000
|
||||
b78: 00000000
|
||||
b7c: 00000000
|
||||
b80: 00000000
|
||||
b84: 00000000
|
||||
b88: 00000000
|
||||
b8c: 00000000
|
||||
b90: 00000000
|
||||
b94: 00000000
|
||||
b98: 00000000
|
||||
b9c: 00000000
|
||||
ba0: 00000000
|
||||
ba4: 00000000
|
||||
ba8: 00000000
|
||||
bac: 00000000
|
||||
bb0: 00000000
|
||||
bb4: 00000000
|
||||
bb8: 00000000
|
||||
bbc: 00000000
|
||||
bc0: 00000000
|
||||
bc4: 00000000
|
||||
bc8: 00000000
|
||||
bcc: 00000000
|
||||
bd0: 00000000
|
||||
bd4: 00000000
|
||||
bd8: 00000000
|
||||
bdc: 00000000
|
||||
be0: 00000000
|
||||
be4: 00000000
|
||||
be8: 00000000
|
||||
bec: 00000000
|
||||
bf0: 00000000
|
||||
bf4: 00000000
|
||||
bf8: 00000000
|
||||
bfc: 00000000
|
||||
e00: 00000468
|
||||
e04: 03030003
|
||||
e08: 03000305
|
||||
e0c: 00000007
|
||||
e10: 00000000
|
||||
e14: 00000000
|
||||
@@ -0,0 +1,706 @@
|
||||
000: 05ab0760
|
||||
004: 001c0900
|
||||
008: 000e0303
|
||||
00c: 00021000
|
||||
010: 03184e05
|
||||
014: 00010000
|
||||
018: 40400040
|
||||
01c: 3f1a0000
|
||||
020: 00000000
|
||||
024: 00000000
|
||||
028: 00000000
|
||||
02c: 00000000
|
||||
030: 00000000
|
||||
034: 00000000
|
||||
038: 00000000
|
||||
03c: 00000007
|
||||
040: 07000029
|
||||
044: 00000000
|
||||
048: 00000054
|
||||
04c: 00000000
|
||||
050: 00600080
|
||||
054: 00000005
|
||||
058: 00000060
|
||||
05c: 1f000029
|
||||
060: 00000700
|
||||
064: 000000ec
|
||||
068: 1f000029
|
||||
06c: 00000000
|
||||
070: 000002e0
|
||||
074: 0f000029
|
||||
078: 00000000
|
||||
07c: 00000560
|
||||
080: 07600090
|
||||
084: 00000707
|
||||
088: 00000710
|
||||
08c: 00600000
|
||||
090: 00000000
|
||||
094: 00000720
|
||||
098: 00600000
|
||||
09c: 00000000
|
||||
0a0: 00000730
|
||||
0a4: 00600000
|
||||
0a8: 00000000
|
||||
0ac: 00000740
|
||||
0b0: 00600000
|
||||
0b4: 00000000
|
||||
0b8: 00000750
|
||||
0bc: 00600000
|
||||
0c0: 00000000
|
||||
0c4: 00000760
|
||||
0c8: 00600000
|
||||
0cc: 00000000
|
||||
0d0: 00000770
|
||||
0d4: 00600000
|
||||
0d8: 00000000
|
||||
0dc: 00000780
|
||||
0e0: 00600000
|
||||
0e4: 00000000
|
||||
0e8: 00000790
|
||||
0ec: 00600000
|
||||
0f0: 00000000
|
||||
0f4: 000007a0
|
||||
0f8: 00600000
|
||||
0fc: 00000000
|
||||
100: 000007b0
|
||||
104: 00600000
|
||||
108: 00000000
|
||||
10c: 000007c0
|
||||
110: 00600000
|
||||
114: 00000000
|
||||
118: 000007d0
|
||||
11c: 00600000
|
||||
120: 00000000
|
||||
124: 000007e0
|
||||
128: 00600000
|
||||
12c: 00000000
|
||||
130: 000007f0
|
||||
134: 00600000
|
||||
138: 00000000
|
||||
13c: 00000800
|
||||
140: 00600000
|
||||
144: 00000000
|
||||
148: 00000810
|
||||
14c: 00600000
|
||||
150: 00000000
|
||||
154: 00000820
|
||||
158: 00600000
|
||||
15c: 00000000
|
||||
160: 00000830
|
||||
164: 00600000
|
||||
168: 00000000
|
||||
16c: 00000840
|
||||
170: 00600000
|
||||
174: 00000000
|
||||
178: 00000850
|
||||
17c: 00600000
|
||||
180: 00000000
|
||||
184: 00000860
|
||||
188: 00600000
|
||||
18c: 00000000
|
||||
190: 00000870
|
||||
194: 00600000
|
||||
198: 00000000
|
||||
19c: 00000880
|
||||
1a0: 00600000
|
||||
1a4: 00000000
|
||||
1a8: 00000890
|
||||
1ac: 00600000
|
||||
1b0: 00000000
|
||||
1b4: 000008a0
|
||||
1b8: 00600000
|
||||
1bc: 00000000
|
||||
1c0: 000008b0
|
||||
1c4: 00600000
|
||||
1c8: 00000000
|
||||
1cc: 000008c0
|
||||
1d0: 00838281
|
||||
1d4: 00000000
|
||||
1d8: 00000000
|
||||
1dc: 00000000
|
||||
1e0: 00000000
|
||||
1e4: 00000000
|
||||
1e8: 00000000
|
||||
1ec: 00000000
|
||||
1f0: 00000000
|
||||
1f4: 00000000
|
||||
1f8: 00000000
|
||||
1fc: 00000000
|
||||
200: 00000000
|
||||
204: 00000000
|
||||
208: 00000000
|
||||
20c: 00000000
|
||||
210: 00000000
|
||||
214: 00000000
|
||||
218: 00000000
|
||||
21c: 00000000
|
||||
220: 00000000
|
||||
224: 00000000
|
||||
228: 00000000
|
||||
22c: 00000000
|
||||
230: 00000000
|
||||
234: 00000000
|
||||
238: 00000000
|
||||
23c: 00000000
|
||||
240: 00000000
|
||||
244: 00000000
|
||||
248: 00000000
|
||||
24c: 00000000
|
||||
250: 00000000
|
||||
254: 00000000
|
||||
258: 00000000
|
||||
25c: 00000000
|
||||
260: 00000000
|
||||
264: 00000000
|
||||
268: 00000000
|
||||
26c: 00000000
|
||||
270: 00000000
|
||||
274: 00000000
|
||||
278: 00000000
|
||||
27c: 00000000
|
||||
280: 00000000
|
||||
284: 00000000
|
||||
288: 00000000
|
||||
28c: 00000000
|
||||
290: 00000000
|
||||
294: 00000000
|
||||
298: 00000000
|
||||
29c: 00000000
|
||||
2a0: 00000000
|
||||
2a4: 00000000
|
||||
2a8: 00000000
|
||||
2ac: 00000000
|
||||
2b0: 00000000
|
||||
2b4: 00000000
|
||||
2b8: 00000000
|
||||
2bc: 00000000
|
||||
2c0: 00000000
|
||||
2c4: 00000000
|
||||
2c8: 00000000
|
||||
2cc: 00000000
|
||||
2d0: 00000000
|
||||
2d4: 00000000
|
||||
2d8: 00000000
|
||||
2dc: 00000000
|
||||
2e0: 00000000
|
||||
2e4: 00000000
|
||||
2e8: 00000000
|
||||
2ec: 00000000
|
||||
400: 00000002
|
||||
404: 00000008
|
||||
408: 002a5227
|
||||
40c: 00000002
|
||||
410: 00000208
|
||||
414: 00a49627
|
||||
418: 00000002
|
||||
41c: 00000408
|
||||
420: 011edd47
|
||||
424: 00000002
|
||||
428: 00000608
|
||||
42c: 0199149f
|
||||
430: 00000002
|
||||
434: 00000808
|
||||
438: 021357d7
|
||||
43c: 00000002
|
||||
440: 00000a08
|
||||
444: 028d9e07
|
||||
448: 00000002
|
||||
44c: 00000c08
|
||||
450: 0307e45f
|
||||
454: 00000000
|
||||
458: 00000000
|
||||
45c: 00000000
|
||||
460: 00000002
|
||||
464: 00000008
|
||||
468: 002a5227
|
||||
46c: 00000000
|
||||
470: 00000000
|
||||
474: 00000002
|
||||
478: 00000008
|
||||
47c: 00a49627
|
||||
480: 00000001
|
||||
484: 00000000
|
||||
488: 00000002
|
||||
48c: 00000008
|
||||
490: 011edd47
|
||||
494: 00000002
|
||||
498: 00000000
|
||||
49c: 00000002
|
||||
4a0: 00000008
|
||||
4a4: 0199149f
|
||||
4a8: 00000003
|
||||
4ac: 00000000
|
||||
4b0: 00000002
|
||||
4b4: 00000008
|
||||
4b8: 021357d7
|
||||
4bc: 00000004
|
||||
4c0: 00000000
|
||||
4c4: 00000002
|
||||
4c8: 00000008
|
||||
4cc: 028d9e07
|
||||
4d0: 00000005
|
||||
4d4: 00000000
|
||||
4d8: 00000002
|
||||
4dc: 00000008
|
||||
4e0: 0307e45f
|
||||
4e4: 00000006
|
||||
4e8: 00000000
|
||||
4ec: 00000000
|
||||
4f0: 00000000
|
||||
4f4: 00000000
|
||||
4f8: 00000000
|
||||
4fc: 00000000
|
||||
500: 00000000
|
||||
504: 00000000
|
||||
508: 00000000
|
||||
50c: 00000000
|
||||
510: 00000000
|
||||
514: 00000000
|
||||
518: 00000000
|
||||
51c: 00000000
|
||||
520: 00000000
|
||||
524: 00000000
|
||||
528: 00000000
|
||||
52c: 00000000
|
||||
530: 00000000
|
||||
534: 00000000
|
||||
538: 00000000
|
||||
53c: 00000000
|
||||
540: 00000000
|
||||
544: 00000000
|
||||
548: 00000000
|
||||
54c: 00000000
|
||||
550: 00000000
|
||||
554: 00000000
|
||||
558: 00000000
|
||||
55c: 00000000
|
||||
560: 00000000
|
||||
564: 00000000
|
||||
568: 00000000
|
||||
56c: 00000000
|
||||
570: 00000000
|
||||
574: 00000000
|
||||
578: 00000000
|
||||
57c: 00000000
|
||||
580: 00000000
|
||||
584: 00000000
|
||||
588: 00000000
|
||||
58c: 00000000
|
||||
590: 00000000
|
||||
594: 00000000
|
||||
598: 00000000
|
||||
59c: 00000000
|
||||
5a0: 00000000
|
||||
5a4: 00000000
|
||||
5a8: 00000000
|
||||
5ac: 00000000
|
||||
5b0: 00000000
|
||||
5b4: 00000000
|
||||
5b8: 00000000
|
||||
5bc: 00000000
|
||||
5c0: 00000000
|
||||
5c4: 00000000
|
||||
5c8: 00000000
|
||||
5cc: 00000000
|
||||
5d0: 00000000
|
||||
5d4: 00000000
|
||||
5d8: 00000000
|
||||
5dc: 00000000
|
||||
5e0: 00000000
|
||||
5e4: 00000000
|
||||
5e8: 00000000
|
||||
5ec: 00000000
|
||||
5f0: 00000000
|
||||
5f4: 00000000
|
||||
5f8: 00000000
|
||||
5fc: 00000000
|
||||
600: 00000000
|
||||
604: 00000000
|
||||
608: 00000000
|
||||
60c: 00000000
|
||||
610: 00000000
|
||||
614: 00000000
|
||||
618: 00000000
|
||||
61c: 00000000
|
||||
620: 00000000
|
||||
624: 00000000
|
||||
628: 00000000
|
||||
62c: 00000000
|
||||
630: 00000000
|
||||
634: 00000000
|
||||
638: 00000000
|
||||
63c: 00000000
|
||||
640: 00000000
|
||||
644: 00000000
|
||||
648: 00000000
|
||||
64c: 00000000
|
||||
650: 00000000
|
||||
654: 00000000
|
||||
658: 00000000
|
||||
65c: 00000000
|
||||
660: 00000000
|
||||
664: 00000000
|
||||
668: 00000000
|
||||
66c: 00000000
|
||||
670: 00000000
|
||||
674: 00000000
|
||||
678: 00000000
|
||||
67c: 00000000
|
||||
680: 00000000
|
||||
684: 00000000
|
||||
688: 00000000
|
||||
68c: 00000000
|
||||
690: 00000000
|
||||
694: 00000000
|
||||
698: 00000000
|
||||
69c: 00000000
|
||||
6a0: 00000000
|
||||
6a4: 00000000
|
||||
6a8: 00000000
|
||||
6ac: 00000000
|
||||
6b0: 00000000
|
||||
6b4: 00000000
|
||||
6b8: 00000000
|
||||
6bc: 00000000
|
||||
6c0: 00000000
|
||||
6c4: 00000000
|
||||
6c8: 00000000
|
||||
6cc: 00000000
|
||||
6d0: 00000000
|
||||
6d4: 00000000
|
||||
6d8: 00000000
|
||||
6dc: 00000000
|
||||
6e0: 00000000
|
||||
6e4: 00000000
|
||||
6e8: 00000000
|
||||
6ec: 00000000
|
||||
6f0: 00000000
|
||||
6f4: 00000000
|
||||
6f8: 00000000
|
||||
6fc: 00000000
|
||||
700: 00000000
|
||||
704: 00000000
|
||||
708: 00000000
|
||||
70c: 00000000
|
||||
710: 00000000
|
||||
714: 00000000
|
||||
718: 00000000
|
||||
71c: 00000000
|
||||
720: 00000000
|
||||
724: 00000000
|
||||
728: 00000000
|
||||
72c: 00000000
|
||||
730: 00000000
|
||||
734: 00000000
|
||||
738: 00000000
|
||||
73c: 00000000
|
||||
740: 00000000
|
||||
744: 00000000
|
||||
748: 00000000
|
||||
74c: 00000000
|
||||
750: 00000000
|
||||
754: 00000000
|
||||
758: 00000000
|
||||
75c: 00000000
|
||||
760: 00000000
|
||||
764: 00000000
|
||||
768: 00000000
|
||||
76c: 00000000
|
||||
770: 00000000
|
||||
774: 00000000
|
||||
778: 00000000
|
||||
77c: 00000000
|
||||
780: 00000000
|
||||
784: 00000000
|
||||
788: 00000000
|
||||
78c: 00000000
|
||||
790: 00000000
|
||||
794: 00000000
|
||||
798: 00000000
|
||||
79c: 00000000
|
||||
7a0: 00000000
|
||||
7a4: 00000000
|
||||
7a8: 00000000
|
||||
7ac: 00000000
|
||||
7b0: 00000000
|
||||
7b4: 00000000
|
||||
7b8: 00000000
|
||||
7bc: 00000000
|
||||
7c0: 00000000
|
||||
7c4: 00000000
|
||||
7c8: 00000000
|
||||
7cc: 00000000
|
||||
7d0: 00000000
|
||||
7d4: 00000000
|
||||
7d8: 00000000
|
||||
7dc: 00000000
|
||||
7e0: 00000000
|
||||
7e4: 00000000
|
||||
7e8: 00000000
|
||||
7ec: 00000000
|
||||
7f0: 00000000
|
||||
7f4: 00000000
|
||||
7f8: 00000000
|
||||
7fc: 00000000
|
||||
800: 00000000
|
||||
804: 00000000
|
||||
808: 00000000
|
||||
80c: 00000000
|
||||
810: 00000000
|
||||
814: 00000000
|
||||
818: 00000000
|
||||
81c: 00000000
|
||||
820: 00000000
|
||||
824: 00000000
|
||||
828: 00000000
|
||||
82c: 00000000
|
||||
830: 00000000
|
||||
834: 00000000
|
||||
838: 00000000
|
||||
83c: 00000000
|
||||
840: 00000000
|
||||
844: 00000000
|
||||
848: 00000000
|
||||
84c: 00000000
|
||||
850: 00000000
|
||||
854: 00000000
|
||||
858: 00000000
|
||||
85c: 00000000
|
||||
860: 00000000
|
||||
864: 00000000
|
||||
868: 00000000
|
||||
86c: 00000000
|
||||
870: 00000000
|
||||
874: 00000000
|
||||
878: 00000000
|
||||
87c: 00000000
|
||||
880: 00000000
|
||||
884: 00000000
|
||||
888: 00000000
|
||||
88c: 00000000
|
||||
890: 00000000
|
||||
894: 00000000
|
||||
898: 00000000
|
||||
89c: 00000000
|
||||
8a0: 00000000
|
||||
8a4: 00000000
|
||||
8a8: 00000000
|
||||
8ac: 00000000
|
||||
8b0: 00000000
|
||||
8b4: 00000000
|
||||
8b8: 00000000
|
||||
8bc: 00000000
|
||||
8c0: 00000000
|
||||
8c4: 00000000
|
||||
8c8: 00000000
|
||||
8cc: 00000000
|
||||
8d0: 00000000
|
||||
8d4: 00000000
|
||||
8d8: 00000000
|
||||
8dc: 00000000
|
||||
8e0: 00000000
|
||||
8e4: 00000000
|
||||
8e8: 00000000
|
||||
8ec: 00000000
|
||||
8f0: 00000000
|
||||
8f4: 00000000
|
||||
8f8: 00000000
|
||||
8fc: 00000000
|
||||
900: 00000000
|
||||
904: 00000000
|
||||
908: 00000000
|
||||
90c: 00000000
|
||||
910: 00000000
|
||||
914: 00000000
|
||||
918: 00000000
|
||||
91c: 00000000
|
||||
920: 00000000
|
||||
924: 00000000
|
||||
928: 00000000
|
||||
92c: 00000000
|
||||
930: 00000000
|
||||
934: 00000000
|
||||
938: 00000000
|
||||
93c: 00000000
|
||||
940: 00000000
|
||||
944: 00000000
|
||||
948: 00000000
|
||||
94c: 00000000
|
||||
950: 00000000
|
||||
954: 00000000
|
||||
958: 00000000
|
||||
95c: 00000000
|
||||
960: 00000000
|
||||
964: 00000000
|
||||
968: 00000000
|
||||
96c: 00000000
|
||||
970: 00000000
|
||||
974: 00000000
|
||||
978: 00000000
|
||||
97c: 00000000
|
||||
980: 00000000
|
||||
984: 00000000
|
||||
988: 00000000
|
||||
98c: 00000000
|
||||
990: 00000000
|
||||
994: 00000000
|
||||
998: 00000000
|
||||
99c: 00000000
|
||||
9a0: 00000000
|
||||
9a4: 00000000
|
||||
9a8: 00000000
|
||||
9ac: 00000000
|
||||
9b0: 00000000
|
||||
9b4: 00000000
|
||||
9b8: 00000000
|
||||
9bc: 00000000
|
||||
9c0: 00000000
|
||||
9c4: 00000000
|
||||
9c8: 00000000
|
||||
9cc: 00000000
|
||||
9d0: 00000000
|
||||
9d4: 00000000
|
||||
9d8: 00000000
|
||||
9dc: 00000000
|
||||
9e0: 00000000
|
||||
9e4: 00000000
|
||||
9e8: 00000000
|
||||
9ec: 00000000
|
||||
9f0: 00000000
|
||||
9f4: 00000000
|
||||
9f8: 00000000
|
||||
9fc: 00000000
|
||||
a00: 00000000
|
||||
a04: 00000000
|
||||
a08: 00000000
|
||||
a0c: 00000000
|
||||
a10: 00000000
|
||||
a14: 00000000
|
||||
a18: 00000000
|
||||
a1c: 00000000
|
||||
a20: 00000000
|
||||
a24: 00000000
|
||||
a28: 00000000
|
||||
a2c: 00000000
|
||||
a30: 00000000
|
||||
a34: 00000000
|
||||
a38: 00000000
|
||||
a3c: 00000000
|
||||
a40: 00000000
|
||||
a44: 00000000
|
||||
a48: 00000000
|
||||
a4c: 00000000
|
||||
a50: 00000000
|
||||
a54: 00000000
|
||||
a58: 00000000
|
||||
a5c: 00000000
|
||||
a60: 00000000
|
||||
a64: 00000000
|
||||
a68: 00000000
|
||||
a6c: 00000000
|
||||
a70: 00000000
|
||||
a74: 00000000
|
||||
a78: 00000000
|
||||
a7c: 00000000
|
||||
a80: 00000000
|
||||
a84: 00000000
|
||||
a88: 00000000
|
||||
a8c: 00000000
|
||||
a90: 00000000
|
||||
a94: 00000000
|
||||
a98: 00000000
|
||||
a9c: 00000000
|
||||
aa0: 00000002
|
||||
aa4: 00000008
|
||||
aa8: 00000000
|
||||
aac: 00000000
|
||||
ab0: 00000002
|
||||
ab4: 00000208
|
||||
ab8: 00000001
|
||||
abc: 00000000
|
||||
ac0: 00000002
|
||||
ac4: 00000408
|
||||
ac8: 00000002
|
||||
acc: 00000000
|
||||
ad0: 00000002
|
||||
ad4: 00000608
|
||||
ad8: 00000003
|
||||
adc: 00000000
|
||||
ae0: 00000002
|
||||
ae4: 00000808
|
||||
ae8: 00000004
|
||||
aec: 00000000
|
||||
af0: 00000002
|
||||
af4: 00000a08
|
||||
af8: 00000005
|
||||
afc: 00000000
|
||||
b00: 00000002
|
||||
b04: 00000c08
|
||||
b08: 00000006
|
||||
b0c: 00000000
|
||||
b10: 00000000
|
||||
b14: 00000000
|
||||
b18: 00000000
|
||||
b1c: 00000000
|
||||
b20: 00000000
|
||||
b24: 00000000
|
||||
b28: 00000000
|
||||
b2c: 00000000
|
||||
b30: 00000000
|
||||
b34: 00000000
|
||||
b38: 00000000
|
||||
b3c: 00000000
|
||||
b40: 00000000
|
||||
b44: 00000000
|
||||
b48: 00000000
|
||||
b4c: 00000000
|
||||
b50: 00000000
|
||||
b54: 00000000
|
||||
b58: 00000000
|
||||
b5c: 00000000
|
||||
b60: 00000000
|
||||
b64: 00000000
|
||||
b68: 00000000
|
||||
b6c: 00000000
|
||||
b70: 00000000
|
||||
b74: 00000000
|
||||
b78: 00000000
|
||||
b7c: 00000000
|
||||
b80: 00000000
|
||||
b84: 00000000
|
||||
b88: 00000000
|
||||
b8c: 00000000
|
||||
b90: 00000000
|
||||
b94: 00000000
|
||||
b98: 00000000
|
||||
b9c: 00000000
|
||||
ba0: 00000000
|
||||
ba4: 00000000
|
||||
ba8: 00000000
|
||||
bac: 00000000
|
||||
bb0: 00000000
|
||||
bb4: 00000000
|
||||
bb8: 00000000
|
||||
bbc: 00000000
|
||||
bc0: 00000000
|
||||
bc4: 00000000
|
||||
bc8: 00000000
|
||||
bcc: 00000000
|
||||
bd0: 00000000
|
||||
bd4: 00000000
|
||||
bd8: 00000000
|
||||
bdc: 00000000
|
||||
be0: 00000000
|
||||
be4: 00000000
|
||||
be8: 00000000
|
||||
bec: 00000000
|
||||
bf0: 00000000
|
||||
bf4: 00000000
|
||||
bf8: 00000000
|
||||
bfc: 00000000
|
||||
e00: 00000468
|
||||
e04: 03030003
|
||||
e08: 03000305
|
||||
e0c: 00000007
|
||||
e10: 00000000
|
||||
e14: 00000000
|
||||
@@ -17,19 +17,10 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "lib.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;
|
||||
@@ -37,20 +28,20 @@ struct mcp251xfd_dump_iter {
|
||||
const void *object_end;
|
||||
};
|
||||
|
||||
static __attribute__((__unused__)) const char *
|
||||
const char *
|
||||
get_object_type_str(enum mcp251xfd_dump_object_type object_type)
|
||||
{
|
||||
switch (object_type) {
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
|
||||
return "reg";
|
||||
return "REG";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
|
||||
return "tef";
|
||||
return "TEF";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
|
||||
return "rx";
|
||||
return "RX";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
|
||||
return "tx";
|
||||
return "TX";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_END:
|
||||
return "end";
|
||||
return "END";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
@@ -94,7 +85,7 @@ do_dev_coredump_read_reg(const struct mcp251xfd_priv *priv,
|
||||
reg = le32toh(object->reg);
|
||||
val = le32toh(object->val);
|
||||
|
||||
pr_debug("%s: object=0x%04zx reg=0x%04x - val=0x%08x\n",
|
||||
pr_debug("%s: offset=0x%04zx reg=0x%04x - val=0x%08x\n",
|
||||
__func__,
|
||||
(void *)object - iter->start,
|
||||
reg, val);
|
||||
@@ -124,7 +115,7 @@ do_dev_coredump_read_ring(const struct mcp251xfd_priv *priv,
|
||||
key = le32toh(object->reg);
|
||||
val = le32toh(object->val);
|
||||
|
||||
pr_debug("%s: reg=0x%04zx key=0x%02x: %8s - val=0x%08x\n",
|
||||
pr_debug("%s: offset=0x%04zx key=0x%02x: %8s - val=0x%08x\n",
|
||||
__func__,
|
||||
(void *)object - iter->start,
|
||||
key, get_ring_key_str(key), val);
|
||||
@@ -152,7 +143,7 @@ do_dev_coredump_read_ring(const struct mcp251xfd_priv *priv,
|
||||
ring->obj_size = val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +166,7 @@ do_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
le32toh(iter->hdr->magic) == MCP251XFD_DUMP_MAGIC) {
|
||||
const struct mcp251xfd_dump_object_header *hdr = iter->hdr;
|
||||
enum mcp251xfd_dump_object_type object_type;
|
||||
struct mcp251xfd_ring ring;
|
||||
size_t object_offset, object_len;
|
||||
int err;
|
||||
|
||||
@@ -188,6 +180,8 @@ do_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
iter->object_start = iter->start + object_offset;
|
||||
iter->object_end = iter->object_start + object_len;
|
||||
|
||||
mcp251xfd_dump_ring_init(&ring);
|
||||
|
||||
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,
|
||||
@@ -199,13 +193,17 @@ do_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
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);
|
||||
err = do_dev_coredump_read_ring(priv, iter, &ring);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ring.fifo_nr >= ARRAY_SIZE(priv->ring))
|
||||
return -EINVAL;
|
||||
|
||||
priv->ring[ring.fifo_nr] = ring;
|
||||
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_END:
|
||||
return 0;
|
||||
|
||||
@@ -12,14 +12,17 @@
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump.h"
|
||||
|
||||
#define MCP251XFD_TX_FIFO 1
|
||||
#define MCP251XFD_RX_FIFO(x) (MCP251XFD_TX_FIFO + 1 + (x))
|
||||
#define MCP251XFD_DUMP_UNKNOWN (-1U)
|
||||
|
||||
struct mcp251xfd_mem {
|
||||
char buf[0x1000];
|
||||
};
|
||||
|
||||
struct mcp251xfd_ring {
|
||||
enum mcp251xfd_dump_object_type type;
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo;
|
||||
void *ram;
|
||||
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
|
||||
@@ -30,25 +33,14 @@ struct mcp251xfd_ring {
|
||||
u8 obj_size;
|
||||
};
|
||||
|
||||
#define MCP251XFD_RING_TEF 0
|
||||
|
||||
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;
|
||||
struct mcp251xfd_ring ring[32];
|
||||
};
|
||||
|
||||
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_ring_init(struct mcp251xfd_ring *ring);
|
||||
|
||||
void mcp251xfd_dump(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
@@ -57,5 +49,7 @@ int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path);
|
||||
const char *
|
||||
get_object_type_str(enum mcp251xfd_dump_object_type object_type);
|
||||
|
||||
#endif
|
||||
|
||||
+329
-302
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
// Copyright (c) 2019, 2020, 2021, 2022 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
@@ -72,6 +72,18 @@ struct mcp251xfd_dump_regs_mcp251xfd {
|
||||
u32 devid;
|
||||
};
|
||||
|
||||
static bool
|
||||
mcp251xfd_fifo_is_unused(const struct mcp251xfd_dump_regs_fifo *fifo)
|
||||
{
|
||||
return fifo->con == 0x00600000 && fifo->sta == 0x00000000;
|
||||
}
|
||||
|
||||
static bool
|
||||
mcp251xfd_fifo_is_rx(const struct mcp251xfd_dump_regs_fifo *fifo)
|
||||
{
|
||||
return !(fifo->con & MCP251XFD_REG_FIFOCON_TXEN);
|
||||
}
|
||||
|
||||
#define __dump_bit(val, prefix, bit, desc) \
|
||||
pr_info("%16s %s\t\t%s\n", __stringify(bit), \
|
||||
(val) & prefix##_##bit ? "x" : " ", desc)
|
||||
@@ -232,7 +244,7 @@ static void mcp251xfd_dump_reg_intf(const struct mcp251xfd_priv *priv, u32 val,
|
||||
#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; \
|
||||
size_t i; \
|
||||
\
|
||||
pr_info(__stringify(name) ": " __stringify(fifo) "(0x%03x)=0x%08x\n", addr, val); \
|
||||
pr_info(description ":\n"); \
|
||||
@@ -244,7 +256,7 @@ static void mcp251xfd_dump_reg_##fifo(const struct mcp251xfd_priv *priv, u32 val
|
||||
pr_info("\t\t"); \
|
||||
for (i = 0; i < sizeof(val); i++) { \
|
||||
if (val & BIT(i)) \
|
||||
pr_cont("%d ", i); \
|
||||
pr_cont("%zd ", i); \
|
||||
} \
|
||||
\
|
||||
pr_cont("\n"); \
|
||||
@@ -318,6 +330,24 @@ static void mcp251xfd_dump_reg_osc(const struct mcp251xfd_priv *priv, u32 val, u
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, PLLEN, "PLL Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_iocon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("IOCON: iocon(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, INTOD, "Interrupt pins Open Drain Mode (0: Push/Pull Output, 1: Open Drain Output)");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, SOF, "Start-Of-Frame signal (0: Clock on CLKO pin, 1: SOF signal on CLKO pin)");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, TXCANOD, "TXCAN Open Drain Mode (0: Push/Pull Output, 1: Open Drain Output)");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, PM1, "GPIO Pin Mode (0: Interrupt Pin INT1 (RXIF), 1: Pin is used as GPIO1)");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, PM0, "GPIO Pin Mode (0: Interrupt Pin INT0 (TXIF), 1: Pin is used as GPIO0)");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, GPIO1, "GPIO1 Status");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, GPIO0, "GPIO0 Status");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, LAT1, "GPIO1 Latch");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, LAT0, "GPIO0 Latch");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, XSTBYEN, "Enable Transceiver Standby Pin Control");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, TRIS1, "GPIO1 Data Direction (0: Output Pin, 1: Input Pin)");
|
||||
__dump_bit(val, MCP251XFD_REG_IOCON, TRIS0, "GPIO0 Data Direction (0: Output Pin, 1: Input Pin)");
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -408,6 +438,8 @@ mcp251xfd_dump_regs(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_regs_mcp251xfd *regs_mcp251xfd)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
netdev_info(priv->ndev, "-------------------- register dump --------------------\n");
|
||||
__dump_call(regs, con);
|
||||
__dump_call(regs, nbtcfg);
|
||||
@@ -425,29 +457,46 @@ mcp251xfd_dump_regs(const struct mcp251xfd_priv *priv,
|
||||
__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");
|
||||
__dump_call(regs_mcp251xfd, iocon);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs->fifo); i++) {
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo = ®s->fifo[i];
|
||||
|
||||
if (mcp251xfd_fifo_is_unused(fifo))
|
||||
continue;
|
||||
|
||||
pr_info("----------------------- FIFO %2d - ", i);
|
||||
|
||||
if (i == 0) {
|
||||
pr_info("TEF -----------------\n");
|
||||
|
||||
__dump_call(regs, tefcon);
|
||||
__dump_call(regs, tefsta);
|
||||
__dump_call(regs, tefua);
|
||||
} else {
|
||||
if (mcp251xfd_fifo_is_rx(fifo))
|
||||
pr_info("RX ------------------\n");
|
||||
else
|
||||
pr_info("TX ------------------\n");
|
||||
|
||||
__dump_call_fifo(fifocon, fifo[i].con);
|
||||
__dump_call_fifo(fifosta, fifo[i].sta);
|
||||
__dump_call_fifo(fifoua, fifo[i].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)
|
||||
static u8
|
||||
mcp251xfd_dump_get_fifo_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs_fifo *regs_fifo)
|
||||
{
|
||||
u8 obj_size;
|
||||
|
||||
obj_size = FIELD_GET(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, fifo_con);
|
||||
obj_size = FIELD_GET(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, regs_fifo->con);
|
||||
switch (obj_size) {
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_8:
|
||||
return 8;
|
||||
@@ -470,16 +519,91 @@ static u8 mcp251xfd_dump_get_fifo_size(const struct mcp251xfd_priv *priv, const
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 mcp251xfd_dump_get_fifo_obj_num(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tef_obj);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_rx_obj_can) -
|
||||
sizeof_field(struct mcp251xfd_hw_rx_obj_can, data) +
|
||||
mcp251xfd_dump_get_fifo_size(priv, fifo);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tx_obj_can) -
|
||||
sizeof_field(struct mcp251xfd_hw_tx_obj_can, data) +
|
||||
mcp251xfd_dump_get_fifo_size(priv, fifo);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_fifo_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo)
|
||||
{
|
||||
u8 obj_num;
|
||||
|
||||
obj_num = FIELD_GET(MCP251XFD_REG_FIFOCON_FSIZE_MASK, fifo_con);
|
||||
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)
|
||||
static u16
|
||||
mcp251xfd_dump_get_ring_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring,
|
||||
u8 n)
|
||||
{
|
||||
return ring->base + ring->obj_size * n;
|
||||
}
|
||||
|
||||
static void *
|
||||
mcp251xfd_dump_get_ring_hw_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring,
|
||||
u8 n)
|
||||
{
|
||||
return ring->ram + ring->obj_size * n;
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_ring_head(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return ring->head & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_ring_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return ring->tail & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_chip_head(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK,
|
||||
ring->fifo->sta);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_chip_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return (ring->fifo->ua -
|
||||
(ring->base - MCP251XFD_RAM_START)) / ring->obj_size;
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ring_obj_data(const struct mcp251xfd_priv *priv,
|
||||
const u8 *data, u8 dlc)
|
||||
{
|
||||
int i;
|
||||
u8 len;
|
||||
@@ -510,326 +634,228 @@ static void mcp251xfd_dump_ram_fifo_obj_data(const struct mcp251xfd_priv *priv,
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
/* TEF */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
static void
|
||||
mcp251xfd_dump_analyze_regs_and_ram(struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tef.con);
|
||||
u16 base = MCP251XFD_RAM_START;
|
||||
u8 ring_nr_rx = 0, ring_nr_tx = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs->fifo); i++) {
|
||||
const struct mcp251xfd_dump_regs_fifo *fifo;
|
||||
struct mcp251xfd_ring *ring = &priv->ring[i];
|
||||
|
||||
if (i == MCP251XFD_RING_TEF) {
|
||||
/* FIFO 0 is the TXQ, but it's unused by the driver
|
||||
* put TEF here to make things easier.
|
||||
*/
|
||||
fifo = ®s->tef;
|
||||
|
||||
ring->type = MCP251XFD_DUMP_OBJECT_TYPE_TEF;
|
||||
|
||||
ring->nr = 0;
|
||||
ring->obj_size = mcp251xfd_dump_get_tef_obj_size(priv, fifo);
|
||||
} else {
|
||||
fifo = ®s->fifo[i];
|
||||
|
||||
if (mcp251xfd_fifo_is_unused(fifo)) {
|
||||
continue;
|
||||
} else if (mcp251xfd_fifo_is_rx(fifo)) {
|
||||
ring->type = MCP251XFD_DUMP_OBJECT_TYPE_RX;
|
||||
ring->nr = ring_nr_rx++;
|
||||
ring->obj_size = mcp251xfd_dump_get_rx_obj_size(priv, fifo);
|
||||
} else {
|
||||
ring->type = MCP251XFD_DUMP_OBJECT_TYPE_TX;
|
||||
ring->nr = ring_nr_tx++;
|
||||
ring->obj_size = mcp251xfd_dump_get_tx_obj_size(priv, fifo);
|
||||
}
|
||||
}
|
||||
|
||||
ring->fifo = fifo;
|
||||
ring->ram = (void *)ram + (base - MCP251XFD_RAM_START);
|
||||
|
||||
ring->base = base;
|
||||
ring->fifo_nr = i;
|
||||
ring->obj_num = mcp251xfd_dump_get_fifo_obj_num(priv, fifo);
|
||||
|
||||
base = mcp251xfd_dump_get_ring_obj_addr(priv, ring, ring->obj_num);
|
||||
}
|
||||
|
||||
printf("Found %u RX-FIFO%s, %u TX-FIFO%s\n\n",
|
||||
ring_nr_rx, ring_nr_rx > 1 ? "s" : "",
|
||||
ring_nr_tx, ring_nr_tx > 1 ? "s" : "");
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
static const char *
|
||||
mcp251xfd_dump_ring_obj_one_fifo_flags_chip(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring,
|
||||
const u8 n)
|
||||
{
|
||||
return regs->tefua / sizeof(struct mcp251xfd_hw_tef_obj);
|
||||
if (mcp251xfd_dump_get_chip_tail(priv, ring) != n)
|
||||
return "";
|
||||
|
||||
if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_TX) {
|
||||
if (!(ring->fifo->sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF))
|
||||
return " chip-FIFO-full";
|
||||
if (ring->fifo->sta & MCP251XFD_REG_FIFOSTA_TFERFFIF)
|
||||
return " chip-FIFO-empty";
|
||||
} else {
|
||||
if (ring->fifo->sta & MCP251XFD_REG_FIFOSTA_TFERFFIF)
|
||||
return " chip-FIFO-full";
|
||||
if (!(ring->fifo->sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF))
|
||||
return " chip-FIFO-empty";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tef_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
u8 n)
|
||||
static const char *
|
||||
mcp251xfd_dump_ring_obj_one_fifo_flags_ring(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring,
|
||||
const u8 n)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tef_obj) * n;
|
||||
if (ring->head == MCP251XFD_DUMP_UNKNOWN ||
|
||||
ring->tail == MCP251XFD_DUMP_UNKNOWN ||
|
||||
mcp251xfd_dump_get_ring_tail(priv, ring) != n ||
|
||||
mcp251xfd_dump_get_ring_head(priv, ring) != mcp251xfd_dump_get_ring_tail(priv, ring))
|
||||
return "";
|
||||
|
||||
if (ring->head == ring->tail)
|
||||
return " ring-FIFO-empty";
|
||||
else
|
||||
return " ring-FIFO-full";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
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)
|
||||
mcp251xfd_dump_ring_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring,
|
||||
const void *hw_obj, const 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") :
|
||||
("")));
|
||||
const struct mcp251xfd_hw_tef_obj *hw_tef_obj = hw_obj;
|
||||
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = hw_obj;
|
||||
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj = hw_obj;
|
||||
|
||||
pr_info("%s-%d Object: "
|
||||
"0x%02x (0x%03x)"
|
||||
"%s%s%s%s%s%s"
|
||||
"\n",
|
||||
get_object_type_str(ring->type), ring->nr,
|
||||
n, mcp251xfd_dump_get_ring_obj_addr(priv, ring, n),
|
||||
|
||||
ring->type != MCP251XFD_DUMP_OBJECT_TYPE_TEF && mcp251xfd_dump_get_chip_head(priv, ring) == n ? " chip-HEAD" : "",
|
||||
ring->head != MCP251XFD_DUMP_UNKNOWN && mcp251xfd_dump_get_ring_head(priv, ring) == n ? " ring-HEAD" : "",
|
||||
mcp251xfd_dump_get_chip_tail(priv, ring) == n ? " chip-TAIL" : "",
|
||||
ring->tail != MCP251XFD_DUMP_UNKNOWN && mcp251xfd_dump_get_ring_tail(priv, ring) == n ? " ring-TAIL" : "",
|
||||
mcp251xfd_dump_ring_obj_one_fifo_flags_chip(priv, ring, n),
|
||||
mcp251xfd_dump_ring_obj_one_fifo_flags_ring(priv, ring, n)
|
||||
);
|
||||
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;
|
||||
if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_TEF ||
|
||||
ring->type == MCP251XFD_DUMP_OBJECT_TYPE_RX)
|
||||
pr_info("%16s = 0x%08x\n", "ts", hw_tef_obj->ts);
|
||||
|
||||
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);
|
||||
if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_TEF) {
|
||||
__dump_mask(hw_tef_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ, "0x%06lx", "Sequence");
|
||||
} else if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_TX) {
|
||||
__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)");
|
||||
}
|
||||
}
|
||||
|
||||
/* dump TX */
|
||||
if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_RX ||
|
||||
ring->type == MCP251XFD_DUMP_OBJECT_TYPE_TX) {
|
||||
const u8* data;
|
||||
u8 dlc;
|
||||
|
||||
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");
|
||||
}
|
||||
if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_RX)
|
||||
data = hw_rx_obj->data;
|
||||
else
|
||||
data = hw_tx_obj->data;
|
||||
|
||||
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);
|
||||
dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags);
|
||||
mcp251xfd_dump_ring_obj_data(priv, data, dlc);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
mcp251xfd_dump_ring(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_ring *ring,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
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%s-%d FIFO %d Overview:\n",
|
||||
get_object_type_str(ring->type), ring->nr, ring->fifo_nr);
|
||||
|
||||
if (ring->type == MCP251XFD_DUMP_OBJECT_TYPE_TEF) {
|
||||
if (ring->head == MCP251XFD_DUMP_UNKNOWN)
|
||||
pr_info("%16s\n", "head ( / )");
|
||||
else
|
||||
pr_info("%16s = 0x%02x 0x%08x\n", "head ( /r)",
|
||||
mcp251xfd_dump_get_ring_head(priv, ring),
|
||||
ring->head);
|
||||
} else {
|
||||
if (ring->head == MCP251XFD_DUMP_UNKNOWN)
|
||||
pr_info("%16s = 0x%02x\n", "head (c/ )",
|
||||
mcp251xfd_dump_get_chip_head(priv, ring));
|
||||
else
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/r)",
|
||||
mcp251xfd_dump_get_chip_head(priv, ring),
|
||||
mcp251xfd_dump_get_ring_head(priv, ring),
|
||||
ring->head);
|
||||
}
|
||||
|
||||
if (ring->tail == MCP251XFD_DUMP_UNKNOWN)
|
||||
pr_info("%16s = 0x%02x\n", "tail (c/ )",
|
||||
mcp251xfd_dump_get_chip_tail(priv, ring));
|
||||
else
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/r)",
|
||||
mcp251xfd_dump_get_chip_tail(priv, ring),
|
||||
mcp251xfd_dump_get_ring_tail(priv, ring),
|
||||
ring->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;
|
||||
for (i = 0; i < ring->obj_num; i++) {
|
||||
void *hw_obj;
|
||||
|
||||
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);
|
||||
hw_obj = mcp251xfd_dump_get_ring_hw_obj(priv, ring, i);
|
||||
mcp251xfd_dump_ring_obj_one(priv, ring, hw_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)
|
||||
static void
|
||||
mcp251xfd_dump_ram(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs->fifo); i++) {
|
||||
const struct mcp251xfd_ring *ring = &priv->ring[i];
|
||||
|
||||
switch (ring->type) {
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
|
||||
mcp251xfd_dump_ring(priv, ring, regs);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
|
||||
}
|
||||
|
||||
@@ -858,6 +884,7 @@ void mcp251xfd_dump(struct mcp251xfd_priv *priv)
|
||||
if (err)
|
||||
return;
|
||||
|
||||
mcp251xfd_dump_analyze_regs_and_ram(priv, ®s, &ram);
|
||||
mcp251xfd_dump_regs(priv, ®s, ®s_mcp251xfd);
|
||||
mcp251xfd_dump_ram(priv, ®s, &ram);
|
||||
}
|
||||
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2023 Pengutronix,
|
||||
# Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
DEV=${1:-can0}
|
||||
SPI=${2:-$(ethtool -i ${DEV}|sed -ne "s/bus-info: //p")}
|
||||
|
||||
modprobe -r mcp251xfd
|
||||
modprobe mcp251xfd
|
||||
|
||||
sleep 2
|
||||
|
||||
ip link set ${DEV} down
|
||||
|
||||
sleep 2
|
||||
rm -vf /var/log/devcoredump-*.dump
|
||||
|
||||
ip link set ${DEV} up type can bitrate 1000000 dbitrate 4000000 fd on restart-ms 1000 berr-reporting off listen-only off loopback on
|
||||
|
||||
ethtool -g ${DEV} || true
|
||||
ethtool -c ${DEV} || true
|
||||
|
||||
cangen ${DEV} -Di -L8 -I2 -p 10 -g 200 -n 3
|
||||
|
||||
cat /sys/kernel/debug/regmap/${SPI}-crc/registers > data/registers-canfd.dump
|
||||
|
||||
ip link set ${DEV} down
|
||||
sleep 2
|
||||
cp -av /var/log/devcoredump-*.dump data
|
||||
|
||||
|
||||
ip link set ${DEV} up type can bitrate 1000000 fd off restart-ms 1000 berr-reporting off listen-only off loopback on
|
||||
|
||||
rm -vf /var/log/devcoredump-*.dump
|
||||
|
||||
ethtool -g ${DEV} || true
|
||||
ethtool -c ${DEV} || true
|
||||
|
||||
cangen ${DEV} -Di -L8 -I2 -p 10 -g 200 -n 7
|
||||
|
||||
cat /sys/kernel/debug/regmap/${SPI}-crc/registers > data/registers-classic-can.dump
|
||||
|
||||
ip link set ${DEV} down
|
||||
sleep 2
|
||||
cp -av /var/log/devcoredump-*.dump data
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -44,6 +45,17 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mcp251xfd_dump_ring_init(struct mcp251xfd_ring *ring)
|
||||
{
|
||||
memset(ring, 0x0, sizeof(*ring));
|
||||
|
||||
ring->type = MCP251XFD_DUMP_UNKNOWN;
|
||||
ring->head = MCP251XFD_DUMP_UNKNOWN;
|
||||
ring->tail = MCP251XFD_DUMP_UNKNOWN;
|
||||
ring->nr = (uint8_t)MCP251XFD_DUMP_UNKNOWN;
|
||||
ring->fifo_nr = (uint8_t)MCP251XFD_DUMP_UNKNOWN;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct mcp251xfd_mem mem = { };
|
||||
@@ -54,6 +66,7 @@ int main(int argc, char *argv[])
|
||||
.map = &map,
|
||||
};
|
||||
const char *file_path;
|
||||
unsigned int i;
|
||||
int opt, err;
|
||||
|
||||
struct option long_options[] = {
|
||||
@@ -82,6 +95,9 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv.ring); i++)
|
||||
mcp251xfd_dump_ring_init(&priv.ring[i]);
|
||||
|
||||
err = mcp251xfd_dev_coredump_read(&priv, &mem, file_path);
|
||||
if (err)
|
||||
err = mcp251xfd_regmap_read(&priv, &mem, file_path);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020 Pengutronix,
|
||||
// Copyright (c) 2020, 2022, 2023 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
@@ -26,21 +26,37 @@ do_mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
FILE *reg_file;
|
||||
uint16_t reg;
|
||||
uint32_t val;
|
||||
unsigned int n = 0;
|
||||
int ret, err = 0;
|
||||
|
||||
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;
|
||||
while ((ret = fscanf(reg_file, "%hx: %x\n", ®, &val)) != EOF) {
|
||||
if (ret != 2) {
|
||||
fscanf(reg_file, "%*[^\n]\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reg >= ARRAY_SIZE(mem->buf)) {
|
||||
err = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
*(uint32_t *)(mem->buf + reg) = val;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
printf("regmap: Found %u registers in %s\n", n, file_path);
|
||||
if (!n)
|
||||
err = -EINVAL;
|
||||
|
||||
out_close:
|
||||
fclose(reg_file);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
|
||||
+2
-2
@@ -67,7 +67,7 @@ void print_usage(char *prg)
|
||||
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, " -w (attach - wait for keypress - detach)\n");
|
||||
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
|
||||
fprintf(stderr, "\n"
|
||||
" <speed> Bitrate\n"
|
||||
@@ -141,7 +141,7 @@ int main(int argc, char **argv)
|
||||
|
||||
case 'b':
|
||||
btr = optarg;
|
||||
if (strlen(btr) > 6)
|
||||
if (strlen(btr) > 8)
|
||||
print_usage(argv[0]);
|
||||
break;
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'b':
|
||||
btr = optarg;
|
||||
if (strlen(btr) > 6)
|
||||
if (strlen(btr) > 8)
|
||||
print_usage(argv[0]);
|
||||
break;
|
||||
case 'F':
|
||||
|
||||
+9
-22
@@ -43,27 +43,12 @@
|
||||
#include <linux/can/raw.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
/* maximum rx buffer len: extended CAN frame with timestamp */
|
||||
#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
|
||||
#define DEVICE_NAME_PTMX "/dev/ptmx"
|
||||
|
||||
#define DEBUG
|
||||
|
||||
static int asc2nibble(char c)
|
||||
{
|
||||
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
return c - '0';
|
||||
|
||||
if ((c >= 'A') && (c <= 'F'))
|
||||
return c - 'A' + 10;
|
||||
|
||||
if ((c >= 'a') && (c <= 'f'))
|
||||
return c - 'a' + 10;
|
||||
|
||||
return 16; /* error */
|
||||
}
|
||||
|
||||
/* read data from pty, send CAN frames to CAN socket and answer commands */
|
||||
int pty2can(int pty, int socket, struct can_filter *fi,
|
||||
int *is_open, int *tstamp)
|
||||
@@ -119,14 +104,12 @@ rx_restart:
|
||||
cmd = buf[0];
|
||||
buf[nbytes] = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (tmp = 0; tmp < nbytes; tmp++)
|
||||
if (buf[tmp] == '\r')
|
||||
putchar('@');
|
||||
pr_debug("@");
|
||||
else
|
||||
putchar(buf[tmp]);
|
||||
printf("\n");
|
||||
#endif
|
||||
pr_debug("%c", buf[tmp]);
|
||||
pr_debug("\n");
|
||||
|
||||
/* check for filter configuration commands */
|
||||
if (cmd == 'm' || cmd == 'M') {
|
||||
@@ -501,6 +484,10 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = if_nametoindex(argv[2]);
|
||||
if (!addr.can_ifindex) {
|
||||
perror("if_nametoindex");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* disable reception of CAN frames until we are opened by 'O' */
|
||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ static const char help_msg[] =
|
||||
" -s[=LEN] Initial send of LEN bytes dummy data\n"
|
||||
" -r Receive (and print) data\n"
|
||||
" -e Echo incoming packets back\n"
|
||||
" This atually receives packets\n"
|
||||
" This actually receives packets\n"
|
||||
" -c Issue connect()\n"
|
||||
" -p=PRIO Set priority to PRIO\n"
|
||||
" -P Promiscuous mode. Allow to receive all packets\n"
|
||||
|
||||
Reference in New Issue
Block a user