250 Commits
Author SHA1 Message Date
Marc Kleine-BuddeandGitHub e9dd86fa5c Merge pull request #300 from hartkopp/master
canplayer: add interactive single-step frame processing mode
2021-06-07 16:14:23 +02:00
Oliver Hartkopp affdc1b799 can: uapi: update can.h to latest upstream version
This update includes:

commit f5076c6ba02e ("can: uapi: can.h: mark union inside struct can_frame packed")
commit 7e97d274db92 ("can: uapi: update CAN-FD frame description")
commit 025468842212 ("can: uapi: introduce CANFD_FDF flag for mixed content in struct canfd_frame")

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2021-06-01 19:55:40 +02:00
Marc Kleine-BuddeandGitHub a70801f1ce Merge pull request #297 from marckleinebudde/fix-candump
candump: fix epoll_wait() returning -1, errno == -EINTR
2021-05-28 12:22:59 +02:00
Marc Kleine-Budde 1b4e317083 candump: fix epoll_wait() returning -1, errno == -EINTR
-EINTR is not an error, just restart the syscall.

Fixes: 639498bc80 ("candump: use epoll_wait() instead of select()")
Link: https://github.com/linux-can/can-utils/issues/296
Reported-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-05-28 11:57:38 +02:00
Marc Kleine-BuddeandGitHub f8a2cf01fa Merge pull request #293 from marckleinebudde/misc-cleanups
Misc cleanups
2021-05-06 15:59:52 +02:00
Marc Kleine-Budde b88a64e9fc slcan_attach: add bit rate table for -s parameter
Reported-by: Chris Fiege <chris.fiege.pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-05-06 15:56:07 +02:00
Marc Kleine-Budde 70eda640d5 slcan_attach: remove trailing whitespace
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-05-06 15:54:39 +02:00
Marc Kleine-Budde fd6829eb4f canfdtest: main(): sort switch/case in cmd line parser alphabetically
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-05-04 12:00:39 +02:00
Marc Kleine-Budde 4b94546cf9 canfdtest: print_usage(): sort options alphabetically
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-05-04 11:58:25 +02:00
Oliver Hartkopp aaa7fd215f canplayer: add interactive single-step frame processing mode
Wait for ENTER key to process next CAN frame from the log file.

As the new line is printed each time this approach doesn't win a
design price. But this feature is very uncommon and setting the
terminal into some raw mode to get the raw keyboard hits would
introduce a big code overhead to handle e.g. CTRL-C signals which
is a vital functionality for canplayer.

Link: https://github.com/linux-can/can-utils/issues/280
Suggested-by: https://github.com/nico0481
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2021-04-17 13:01:29 +02:00
Oliver Hartkopp 553f0d282b canplayer: fix usec overflow handling
Commit 9c2de072a0 ("asc2log: Correct usec overflow handling") fixed the
usec overflow handling which is contained in a similar code snippet in
canplayer too.

Cc: Simon Tegelid <simon.tegelid@niradynamics.se>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2021-04-16 16:18:40 +02:00
Simon TegelidandOliver Hartkopp 9c2de072a0 asc2log: Correct usec overflow handling
This commit fixes these lines
(1614188635.1000000) can1 4A8##28001E9A318ACC0 R
to become this
(1614188636.000000) can1 4A8##28001E9A318ACC0 R
2021-04-16 14:30:50 +02:00
Marc Kleine-BuddeandGitHub 5116452e6d Merge pull request #285 from kurnev/kurnev-patch-1
Update description for candump
2021-04-14 18:14:23 +02:00
Egor KurnevandGitHub bdf3e96ef9 Update candump.c 2021-04-14 18:49:49 +03:00
Oliver Hartkopp 02b330a87d cangen: fix help text for burst send option
The option '-c' requires a value. Add this hint to the help text.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2021-04-07 13:42:28 +02:00
Marc Kleine-BuddeandGitHub d2f5b3dbe0 Merge pull request #283 from Lauszus/master
Clarify that the mcp251x uses half of the external OSC clock as the base clock
2021-03-23 08:11:47 +01:00
Kristian Sloth Lauszus f11949b7d8 Use the name member to clarify the OSC clock connected to the mcp251x 2021-03-23 00:35:38 +01:00
Kristian Sloth Lauszus b1312a03f0 Added OSC with a clock of 8 MHz to the mcp251x reference clocks 2021-03-23 00:20:19 +01:00
Kristian Sloth Lauszus 890dcc4735 Added comment to clarify that the mcp251x uses half of the external OSC clock as the base clock 2021-03-23 00:19:56 +01:00
Marc Kleine-BuddeandGitHub cafc4bf748 Merge pull request #278 from marckleinebudde/mcp251xfd-dump
mcp251xfd-dump: add tool to decode chip and driver state of mcp251xfd
2021-02-13 23:45:57 +01:00
Marc Kleine-Budde 1792aebd8b mcp251xfd: add sample dev-coredump udev rule
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-13 23:36:43 +01:00
Marc Kleine-Budde 66de96d337 mcp251xfd-dump: add tool to decode chip and driver state of mcp251xfd
It works on dev coredump data generated by the mcp251xfd driver in
case of failures, as well as on regmap based register dumps.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-13 23:36:43 +01:00
Marc Kleine-BuddeandGitHub e8c90ddff9 Merge pull request #277 from marckleinebudde/can-calc-bitming
can-calc-bitming: cleanups, add mcp251xfd and add decoding of low level bit timing parameters into bitrate
2021-02-10 22:15:17 +01:00
Thomas KoppandOliver Hartkopp fe07dc5837 cangen: add possibility to generate random ID odd/even
Use this for stress testing, when sending with two CAN controllers on
the same CAN bus to avoid broken CAN frames due sending the same
CAN-id.
2021-02-10 21:16:29 +01:00
Marc Kleine-Budde 913311fc15 can-calc-bit-timing: add support to decode user supplied bit timing parameters
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-10 17:25:08 +01:00
Marc Kleine-Budde ef8cea79f0 can-calc-bit-timing: move bit rate calculation and print loop into separate function
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-10 17:25:08 +01:00
Marc Kleine-Budde d72438243a can-calc-bit-timing: add support for mcp251xfd
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-10 17:25:08 +01:00
Marc Kleine-Budde 3fc6c05ce2 can-calc-bit-timing: mcp251x: replace 16MHz refclock by 10MHz
The mcp251x uses half of the external OSC rate as CAN clock. In real world
applications external OSC with a clock of 16MHz or 20MHz are used. Adjust the
example ref clocks accordingly.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-10 17:25:08 +01:00
Marc Kleine-Budde dd315316d8 can-calc-bit-timing: mscan: remove printf_btr_sja1000
It makes no sense to print the mscan bit timing register values using the
sja1000 printf function.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-10 17:25:08 +01:00
Marc Kleine-Budde 84bc52d6ff can-calc-bit-timing: make btc->printf_btr callback optional
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2021-02-10 17:25:08 +01:00
Richard YoungandOliver Hartkopp eb66451df2 candump: Enable zero relative timestamps to be used in log files
The logfile format which is generated with '-l' and '-L' consists of an
absolute epoch timestamp. In some use cases (e.g. for documentation) a
zero relative timestamp can be useful which was only configurable with
the '-tz' option for the classic output.

'-tz' and '-ta' are now valid options for the logfile format.

Signed-off-by: Richard Young <code@richyoung.ca>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-08 20:52:54 +01:00
Oliver Hartkopp 682e01a40a isotpsend: add SF_BROADCAST support for functional addressing
When CAN_ISOTP_SF_BROADCAST is set in the CAN_ISOTP_OPTS flags the
CAN_ISOTP socket is switched into functional addressing mode, where
only single frame (SF) protocol data units can be send on the specified
CAN interface and the given tp.tx_id after bind().

In opposite to normal and extended addressing this socket does not
register a CAN-ID for reception which would be needed for a 1-to-1
ISOTP connection with a segmented bi-directional data transfer.

The new option '-S' sets the CAN_ISOTP_SF_BROADCAST to test the option
with different length settings, e.g. link layer data lengths.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-06 14:41:48 +01:00
Oliver Hartkopp 280ea436d4 isotp: add define for SF_BROADCAST support
When CAN_ISOTP_SF_BROADCAST is set in the CAN_ISOTP_OPTS flags the
CAN_ISOTP socket is switched into functional addressing mode, where
only single frame (SF) protocol data units can be send on the specified
CAN interface and the given tp.tx_id after bind().

Add the CAN_ISOTP_SF_BROADCAST define from Linux UAPI includes.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-06 14:17:36 +01:00
Marc Kleine-BuddeandGitHub 33de12680a Merge pull request #270 from marckleinebudde/candump-cleanups
Candump cleanups
2020-12-06 10:22:14 +01:00
Marc Kleine-Budde bfaa44fa91 candump: convert to kernel codeing style
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-12-06 10:09:36 +01:00
Marc Kleine-Budde 305b2e8b79 candump: fix indention
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-12-06 09:58:52 +01:00
Marc Kleine-Budde 15f3a2e385 candump: remove trailing whitespace
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-12-06 09:57:52 +01:00
Marc Kleine-BuddeandGitHub aa6411075f Merge pull request #264 from IDC-Dragon/master
candump: epoll_wait() instead of select() runs faster and better keeps packet order
2020-12-06 09:54:33 +01:00
Marc Kleine-BuddeandGitHub 51d675368d Merge pull request #269 from timgates42/bugfix_typo_caught
docs: fix simple typo, cought -> caught
2020-12-06 09:53:21 +01:00
Jörg HohensohnandJörg Hohensohn 639498bc80 candump: use epoll_wait() instead of select()
Using epoll_wait() instead of select() gives higher
performance for listening on multiple interfaces.
Additionally, the read order has a higher chance
to resemble the true temporal order.
select() gives implicit priority to the lower index socket.

Signed-off-by: Jörg Hohensohn <joerg.hohensohn@gmx.de>
2020-12-06 08:32:36 +01:00
Tim Gates 333e631286 docs: fix simple typo, cought -> caught
There is a small typo in canlogserver.c.

Should read `caught` rather than `cought`.
2020-12-06 17:31:33 +11:00
Oliver Hartkopp 6a14256323 cansniffer: fix snifftab CAN-ID query
Due to a wrong test to check for existing CAN-IDs in the snifftab
it was not possible to have the CAN-ID '0' in the list and displayed.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-12-02 13:26:42 +01:00
Oliver Hartkopp c3d9cc2027 cangw: support len8_dlc for Classical CAN frames
The can_dlc value that is passed to the kernel is not sanitized in cangw
therefore we only update the help text and some comments in gw.h.

In the case that the CAN interface supports len8_dlc by setting
CAN_CTRLMODE_CC_LEN8_DLC the can-gw module can modify the full DLC value
range (0 .. 15) for Classic CAN frames.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:57:27 +01:00
Oliver Hartkopp 972054446a can: rename CAN FD related can_len2dlc and can_dlc2len helpers
The helper functions can_len2dlc and can_dlc2len are only relevant for
CAN FD data length code (DLC) conversion.

Update to latest in-kernel naming scheme:

can_dlc2len -> can_fd_dlc2len to get the payload length from the DLC
can_len2dlc -> can_fd_len2dlc to get the DLC from the payload length

Suggested-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:54:58 +01:00
Oliver Hartkopp 6799180bd0 log asc converter: support len8_dlc for Classical CAN frames
The CANFD format in asc logfiles can be used to describe Classical CAN
frame content too. As this CANFD format has two different elements to
transport the payload length and the 'raw data length code' the new
len8_dlc option now allows to support the full qualified conversion.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:47:24 +01:00
Oliver Hartkopp 11edd1d05e candump: support len8_dlc for standard candump output
The display of Classical CAN raw DLC values is an expert feature which is
not enabled by default to not break toolchains that use the candump
standard output for further processing. (N.B. using the log file format and
the functions from lib.h/lib.c provide convenient CAN frame conversions)

After enabling the raw DLC for Classical CAN with the '-8' option the raw
DLC value is printed in 'unusual' curly braces {}.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:42:38 +01:00
Oliver Hartkopp a272fd2082 cansend: add support for Classic CAN raw DLC values
Update help text only as the new extended frame format is already
implemented in lib.h/lib.c

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:33:16 +01:00
Oliver Hartkopp 1ba0c576ae cangen: add support for Classic CAN raw DLC values
A new option '-8' has been added to generate Classical CAN frames with
DLC codes from 0 .. 15.

Fixed and random mode implemented by Oliver Hartkopp.
Incremental DLC mode 'cangen -8 -Li can0' implemented by Vincent Mailhol.

Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 19:13:21 +01:00
Oliver Hartkopp b70d8c050f lib: add support for Classic CAN raw DLC values
ISO 11898-1 Chapter 8.4.2.3 defines a 4 bit data length code (DLC) table which
maps the DLC to the payload length of the CAN frame in bytes:

    DLC      ->  payload length
    0 .. 8   ->  0 .. 8
    9 .. 15  ->  8

To access the raw DLC values 9 .. 15 the len8_dlc element is introduced, which
is only valid when the payload length 'len' is 8 and the DLC is greater than 8.

The extension for len8_dlc has been implemented for the Classic CAN frame
representation in the log file format and for the standard output for
candump where the raw DLC value is printed in 'unusual' curly braces {}.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 18:59:53 +01:00
Oliver Hartkopp c398e56afb can: add optional DLC element to Classical CAN frame structure
ISO 11898-1 Chapter 8.4.2.3 defines a 4 bit data length code (DLC) table which
maps the DLC to the payload length of the CAN frame in bytes:

    DLC      ->  payload length
    0 .. 8   ->  0 .. 8
    9 .. 15  ->  8

Although the DLC values 8 .. 15 in Classical CAN always result in a payload
length of 8 bytes these DLC values are transparently transmitted on the CAN
bus. As the struct can_frame only provides a 'len' element (formerly 'can_dlc')
which contains the plain payload length ( 0 .. 8 ) of the CAN frame, the raw
DLC is not visible to the application programmer, e.g. for testing use-cases.

To access the raw DLC values 9 .. 15 the len8_dlc element is introduced, which
is only valid when the payload length 'len' is 8 and the DLC is greater than 8.

The len8_dlc element is filled by the CAN interface driver and used for CAN
frame creation by the CAN driver when the CAN_CTRLMODE_CC_LEN8_DLC flag is
supported by the driver and enabled via netlink configuration interface.

Reported-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-11-22 18:41:38 +01:00
Marc Kleine-BuddeandGitHub d0ad168953 Merge pull request #261 from neheb/patch-1
add missing time.h include
2020-11-18 08:22:31 +01:00
Rosen PenevandGitHub c3348ed51e add missing time.h include
Needed for musl.
2020-11-17 22:14:09 -08:00
Marc Kleine-BuddeandGitHub 856d0a662a Merge pull request #259 from marckleinebudde/cansequence
cansequence: do_send(): remove unneeded cast
2020-11-04 17:08:52 +01:00
Marc Kleine-Budde ccfa3c8b00 cansequence: do_send(): remove unneeded cast
This patch fixes the following warning:

cansequence.c:232:3: warning: expression result unused [-Wunused-value]
	(unsigned char)frame.data[0]++;
	^              ~~~~~~~~~~~~~~~

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-11-04 14:58:10 +01:00
Marc Kleine-BuddeandGitHub a6cac755b4 Merge pull request #258 from gibsson/master
Android.mk: remove duplicated cansequence definition
2020-11-04 14:57:44 +01:00
Gary Bisson 86bfa25f9d Android.mk: remove duplicated cansequence definition
Otherwise throwing the following error:
build/make/core/base_rules.mk:325: error: external/can-utils:
MODULE.TARGET.EXECUTABLES.cansequence already defined by
external/can-utils.

Fixes: a726c2a ("Merge branch 'cansequence' of
github.com:marckleinebudde/can-utils into master")

Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
2020-11-04 14:12:47 +01:00
Marc Kleine-BuddeandOliver Hartkopp 4573e852f9 log2asc: fix spelling
Fixes: 61dbb56ef6 ("log2asc: support DLC values in Classic CAN RTR frames")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-19 20:52:05 +02:00
Marc Kleine-BuddeandGitHub 09466c2f1d Merge pull request #255 from marckleinebudde/ppc64le
travis: fix env for ppc64le
2020-10-19 15:00:41 +02:00
Marc Kleine-Budde eada3b4f53 travis: fix env for ppc64le
Fixes: b7ba7f32fc ("added script to run on power")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-19 14:37:30 +02:00
Marc Kleine-BuddeandGitHub cb5d2fd653 Merge pull request #254 from marckleinebudde/cansequence
can-utils: import PTX cansequence utility
2020-10-19 14:35:04 +02:00
Marc Kleine-Budde a726c2a57a Merge branch 'cansequence' of github.com:marckleinebudde/can-utils into master
The PTX flavour canutils have a useful utility for generating a sequence of CAN
frames with an incrementing payload and checking such a sequence for missed and
reordered frames.

Recently, it has helped finding a regression in the kernel pfifo_fast qdisc,
which led to reordered frames.

To bring the utility to a greater audience, import the current state, including
its history, into the linux-can set of utilities.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-19 13:44:16 +02:00
Marc Kleine-Budde a8131b7996 cansequence: add SPDX identifier for GPL-2.0-only and copyrights
Message-Id: 20201019111239.GM12463@pengutronix.de
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-19 13:26:43 +02:00
Marc Kleine-BuddeandGitHub 93ef09d9b0 Merge pull request #242 from marckleinebudde/travis-ppc64le
travis: add ppc64le support
2020-10-15 18:36:19 +02:00
Marc Kleine-BuddeandGitHub 677f9ec26f Merge pull request #253 from marckleinebudde/fix-indention
Makefile: fix indention
2020-10-15 18:35:12 +02:00
Marc Kleine-Budde f3cf4cdf88 Makefile: fix indention
This patch fixes the indention, which was broken while renaming the j1939
tools.

Fixes: 8106214b55 ("Rename j* to j1939\1")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-15 18:08:49 +02:00
Marc Kleine-Budde 2afcbd2fee cansequence: print error frames in hex
Fixes: faad20983348 ("cansequence: receive snd show error frames")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 00134246c2 cansequence.c: add extended identifier flag to mask
Without this, the extended identifier flag was not important when
filtering on CAN frames. Add this to mask to only receive the frame type
we want to recieve.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde a1c20aeb45 cansequence: receive snd show error frames
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde d699135833 cansequence: show delta and obsolute overflows
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde de5b9607dc cansequence: add internal 32 bit sequence counter 2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 36fc75bdb7 cansequence: use sigaction() instead of signal
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 68d5f87889 cansequence: exit with failure in case of unknown option
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 4d50109a69 cansequence: do_receive: move variables into loop
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde ac9124c776 cansequence: sort options more alphabetically
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 0bcb5d9c2c cansequence: codingstyle cleanups
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 1e0fb39e8b cansequence: add support for drop after a certain number of incidents
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:32 +02:00
Marc Kleine-Budde 9567230494 cansequence: print out dropped packages by socket counter
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:30 +02:00
Marc Kleine-Budde 985121aaad cansequence: cleanup perror() and exit()
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde 7975f9859c cansequence: make use of bool variables
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde c9bb22022d cansequence: move rx and tx loop into separate functions
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde 2f125e44ce cansequence: mark functions as static
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde 9841820ea0 [cansequence] add sequence wrap around counter
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde fb5903f226 [cansequece] added various improvements
- added poll support if sender
- add cmd line option for can_id
- setup canfilter to disable receiving in sender mode

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde 4aaad29082 * src/cansequence.c:
obay loop option


git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@104 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 18:02:24 +02:00
Marc Kleine-Budde a16f8ed471 git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@98 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c 2020-10-14 18:02:24 +02:00
Marc Kleine-Budde 6e3b123d5b git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@97 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c 2020-10-14 18:02:20 +02:00
Marc Kleine-Budde c93d3a63c5 * src/cansequence.c, src/cansend.c:
fix interface cmd line

git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@95 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 18:02:10 +02:00
Marc Kleine-Budde 5fa35cbe2a git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@92 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c 2020-10-14 18:02:01 +02:00
Marc Kleine-Budde f4cec293dc git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@91 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c 2020-10-14 18:01:50 +02:00
Marc Kleine-Budde bd3ea25fe1 * src/cansequence.c, src/cansend.c:
cleanups

git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@90 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 18:01:48 +02:00
Marc Kleine-Budde d8be4d8a4f * src/canecho.c, src/candump.c, src/cansequence.c, src/cansend.c:
include limits.h

git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@89 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 18:01:37 +02:00
Marc Kleine-Budde b3b501d922 git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-3.0-trunk@88 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c 2020-10-14 18:01:23 +02:00
Marc Kleine-Budde 0c888d7942 * src/cansequence.c:
fixed print of received frame number


git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-2.0-trunk@85 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 18:00:36 +02:00
Marc Kleine-Budde ac8ae17727 * src/cansequence.c:
fixed out of order expected and received value


git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-2.0-trunk@84 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 18:00:36 +02:00
Marc Kleine-Budde 3794644caa git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-2.0-trunk@71 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c 2020-10-14 18:00:33 +02:00
Sascha HauerandMarc Kleine-Budde fc3b0449a9 use unsigned elements
git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-1.0-trunk@49 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 17:59:02 +02:00
Sascha HauerandMarc Kleine-Budde c55d181360 added twice verbose option
git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-1.0-trunk@41 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 17:59:02 +02:00
Sascha HauerandMarc Kleine-Budde d8435a56af add cansequence tool
git-svn-id: https://iocaste.extern.pengutronix.de/svn/canutils/trunks/canutils-1.0-trunk@40 5fd5a299-6ef2-0310-aa18-8b01d7c39d8c
2020-10-14 17:58:58 +02:00
Rosen PenevandOliver Hartkopp 204235c9ce make struct initialization C99 compatible again
Mainly change {} to { 0 } to remove a pedantic warning.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-14 13:29:13 +02:00
Oliver Hartkopp d3b29dfa48 includes: update to Linux 5.10 include files
- isotp.h: use latest version and formatting
- raw.h: introduce SCM_CAN_RAW_ERRQUEUE

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-10-14 09:28:22 +02:00
Oliver Hartkopp a591dadd96 cangw: fix sscanf() signed/unsigned warning
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-10-13 10:28:52 +02:00
Oliver Hartkopp 5e713b3ee0 cansniffer: remove obsolete semicolons
Silence compiler warning.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-10-13 10:16:52 +02:00
Oliver Hartkopp 5d5ccf38ee fix include order and unify local include placement
In commit https://github.com/linux-can/can-utils/commit/b153fe3f3591
("clang-tidy: sort includes alphabetically") the position of the "lib.h"
include has been moved in a way that struct canfd_frame has not been
defined anymore and lead to a warning when compiling cangen.c

This patch reverts that specific move and unifies the location of local
includes at the end of the include list.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-10-13 10:03:19 +02:00
Marc Kleine-BuddeandGitHub bda4b0ad8c Merge pull request #251 from neheb/clng
custom if statement reordering
2020-10-13 08:55:34 +02:00
Rosen Penev f766174677 custom if statement reordering
It makes more sense to return before hitting else.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:48:38 -07:00
Marc Kleine-BuddeandGitHub 7759b00c58 Merge pull request #250 from neheb/clng
clang-tidy fixes
2020-10-13 08:44:49 +02:00
Rosen Penev 48bb69bc7b remove basic usages of memset with {}
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:58 -07:00
Rosen Penev b153fe3f35 clang-tidy: sort includes alphabetically
Found with llvm-include-order

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:58 -07:00
Rosen Penev 3e85fc5422 clang-tidy: fix cmp function usage
Found with bugprone-suspicious-string-compare

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:58 -07:00
Rosen Penev 33f3593436 clang-tidy: use uppercase literal
Found with readability-uppercase-literal-suffix

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:57 -07:00
Rosen Penev 3e67b5cbd1 clang-tidy: remove pointless return
Found with readability-redundant-control-flow

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:57 -07:00
Rosen Penev d5320d554e clang-tidy: fix wrong identation
Found with readability-misleading-indentation

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:57 -07:00
Rosen Penev 17a5fe6022 clang-tidy: do not use else after return
Found with readability-else-after-return

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-12 23:28:22 -07:00
Marc Kleine-BuddeandGitHub 5a93509655 Merge pull request #249 from neheb/nanosleep
convert usleep to nanosleep
2020-10-12 08:48:33 +02:00
Rosen Penev d7df79e687 convert usleep to nanosleep
usleep is removed in POSIX 2008.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-11 23:35:31 -07:00
Marc Kleine-BuddeandGitHub 18573d1dd2 Merge pull request #248 from neheb/bzr
j1939cat: remove bzero
2020-10-12 08:12:05 +02:00
Rosen Penev 8d2ed4c959 j1939cat: remove bzero
bzero is removed in POSIX 2008. malloc/bzero can also be replaced with
calloc.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2020-10-11 22:02:23 -07:00
c27c61424f can utils [can-j1939-install-kernel-module.md]: better explanation for adding backports, fixed typos and grammar (#247)
* Add tutorial how to compile kernel with can-j1939 module

* cosmetic changes

* improvement by adding debian backports to separate sources list

* better explanation for adding backports

* fixed typos

* fixed grammar

* improvement by adding debian backports to separate sources list

* better explanation for adding backports

* fixed typos

* fixed grammar

Co-authored-by: Zeljko Avramovic <avr0833@zelsd.rs>
2020-10-06 15:33:57 +02:00
zeljkoavramovicandGitHub 194959270f Added tutorial how to compile kernel with can-j1939 module (#246)
Add tutorial how to compile kernel with can-j1939 module
2020-10-05 16:15:08 +02:00
Oliver Hartkopp f6d963b5d9 isotpsend: add support for blocking write flag
With the new flag 'CAN_ISOTP_WAIT_TX_DONE' the send()/write() syscall returns
when the PDU is completely passed to the CAN netdevice queue. Depending on
STmin and other settings for the tx-queue-len this does not necessarily mean
that the PDU has been completely sent on the CAN interface at that time.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-10-01 20:42:50 +02:00
Marc Kleine-BuddeandGitHub 485d813545 Merge pull request #244 from marckleinebudde/canfdtest-check-device
canfdtest: bail out if trying to use non-existing CAN interface
2020-09-29 09:14:29 +02:00
Marc Kleine-Budde ce7f22928d canfdtest: bail out if trying to use non-existing CAN interface
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-09-29 09:06:12 +02:00
Marc Kleine-BuddeandGitHub dd8fb0b697 Merge pull request #241 from marckleinebudde/travis
travis: fix indention
2020-09-25 15:33:55 +02:00
genisysramandMarc Kleine-Budde b7ba7f32fc added script to run on power 2020-09-25 15:33:00 +02:00
Marc Kleine-Budde b99f540039 travis: add architecture marker
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-09-25 15:33:00 +02:00
Marc Kleine-Budde 7fb2585641 travis: fix indention
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-09-25 15:24:25 +02:00
Marc Kleine-BuddeandGitHub e1f75da433 Merge pull request #240 from marckleinebudde/canfdtest
canfdtest: remove trailing whitespace and print RX'ed frame in case of RX before TX
2020-09-24 11:27:10 +02:00
Marc Kleine-Budde 435a59a394 canfdtest: can_echo_gen(): print RX'ed frame in case of RX before TX
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-09-24 11:13:41 +02:00
Marc Kleine-Budde 73e421557f canfdtest: remove trailing whitespace
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-09-24 11:13:38 +02:00
Oleksij RempelandOliver Hartkopp ea844bdc5e Document J1939 commands
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2020-08-21 16:11:41 +02:00
Marc Kleine-BuddeandGitHub e6dfcb773e Merge pull request #237 from marckleinebudde/fix-canfdtest
canfdtest: fix frame consistency check
2020-08-20 09:33:11 +02:00
Marc Kleine-Budde c43a168c68 canfdtest: fix frame consistency check
This patch fixes the issue reported in:

https://github.com/linux-can/can-utils/commit/d7f28a0ffe36f73fe08729202f9c49ca5cac1dd4
https://github.com/linux-can/can-utils/issues/236

Reported-by: https://github.com/ronitnvidia
Fixes: d7f28a0ffe ("canfdtest: can_echo_dut(): check received frame for consistency")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-08-20 09:30:27 +02:00
Oliver Hartkopp 7cb3e760fe logfile: add new extra info field
This patch adds a fourth string field in the can logfile format.
This new field contains the rx/tx direction information R/T as the
first entry (only one character separated from the CAN frame by space).

To generate the logfile format with this extra field candump has to be
called with the '-x' option for extra message infos,
e.g. 'candump -x -l can0' or 'candump -x -L can0'

log2asc and asc2log are extended to support the direction information
but still support the previous format without direction information.

The format extension does not affect legacy tools, e.g. the existing
canplayer ignores this extra information and does not need to be changed.

Therefore the existing logfiles remain valid and usable.

The extra message infos will be colon separated when there's need for
additional content beyond the rx/tx direction information, e.g. R:xx:yyy

Suggested-by: Pallavi Revanna https://github.com/brpallu
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-08-18 13:29:36 +02:00
Oliver Hartkopp a4905ed7c8 fix timeval to ASCII unsigned value conversion
As reported by Oleksij Rempel here
https://github.com/linux-can/can-utils/issues/233#issuecomment-674818935
the representation of timeval timestamps are signed values which leads to
negative values on 32 bit machines addressing the year 2038 unix sec counter
overflow.

Fix the issue on 32 bit systems by converting the timeval values to unsigned
ASCII value representations.

Fixes: https://github.com/linux-can/can-utils/issues/234
Reported-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-08-18 12:51:35 +02:00
Marc Kleine-BuddeandGitHub ab23c6f7e7 Merge pull request #232 from olerem/testj1939
testj1939: print proper offset in the data damp
2020-08-07 15:06:36 +02:00
Oleksij Rempel c912d6f8d5 testj1939: print proper offset in the data damp
without this patch we will always print "0008" on each line

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2020-08-07 15:01:43 +02:00
Marc Kleine-BuddeandGitHub 58dc257e11 Merge pull request #231 from olerem/jcat-bam
j1939cat: add broadcast support
2020-08-07 14:23:46 +02:00
Oleksij Rempel 327587b2c8 j1939cat: add broadcast support
Allow to use j1939cat to send and receive broadcast (TP.BAM) messages.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2020-08-07 14:14:38 +02:00
Marc Kleine-BuddeandGitHub 659e0acfe6 Merge pull request #230 from marckleinebudde/j1939acd
j1939acd help text improvements
2020-08-07 14:10:29 +02:00
josemicandMarc Kleine-Budde 88ad7e5755 j1939acd: add example showing optional interface parameter
Changed j1939acd help examples by adding one example showing optional interface
parameter.
2020-08-07 14:01:34 +02:00
josemicandMarc Kleine-Budde 112421dc22 j1939acd: fix help examples
Changed j1939acd help examples by removing duplicate example.

Fixes: 506252e9bc ("jacd.c: Reformat help/usage output to be compatible with help2man.")
2020-08-07 14:00:57 +02:00
Marc Kleine-BuddeandGitHub dec3c5eda1 Merge pull request #225 from marckleinebudde/fix-warnings
Fix warnings
2020-08-07 13:53:48 +02:00
Marc Kleine-BuddeandGitHub bad90515f0 Merge pull request #229 from joseogandoj/patch-1
Update testj1939.c
2020-07-31 08:21:17 +02:00
joseogandojandGitHub da87d595c5 Update testj1939.c
When receiving multi chunk messages, only the first 8 are printed.

Simple coding mistake. Should print dat[i] instead of dat[j]
2020-07-30 16:21:45 -05:00
Göran MannbergandOliver Hartkopp af531c3d52 Update Android.mk
Fixed typo in LOCAL_MODULE isotpsniffer
2020-07-06 08:47:35 +02:00
Marc Kleine-Budde 8e3c050b1c CMakeLists.txt: update test for _GNU_SOURCE to fix warnings
../asc2log.c:264:8: warning: implicit declaration of function 'strcasestr' is invalid in C99 [-Wimplicit-function-declaration]
        ptr = strcasestr(buf, tmp1);
              ^
../asc2log.c:264:6: warning: incompatible integer to pointer conversion assigning to 'char *' from 'int' [-Wint-conversion]
        ptr = strcasestr(buf, tmp1);
            ^ ~~~~~~~~~~~~~~~~~~~~~
../asc2log.c:328:6: warning: implicit declaration of function 'strcasestr' is invalid in C99 [-Wimplicit-function-declaration]
        if (strcasestr(date, " pm ") != NULL) {
            ^
../asc2log.c:328:31: warning: comparison between pointer and integer ('int' and 'void *') [-Wpointer-integer-compare]
        if (strcasestr(date, " pm ") != NULL) {
            ~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~~~~
../asc2log.c:336:8: warning: implicit declaration of function 'strptime' is invalid in C99 [-Wimplicit-function-declaration]
                if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) {
                     ^
../asc2log.c:354:8: warning: implicit declaration of function 'strptime' is invalid in C99 [-Wimplicit-function-declaration]
                if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) {

../slcanpty.c:476:7: warning: implicit declaration of function 'grantpt' is invalid in C99 [-Wimplicit-function-declaration]
                if (grantpt(p) < 0) {
                    ^
../slcanpty.c:481:7: warning: implicit declaration of function 'unlockpt' is invalid in C99 [-Wimplicit-function-declaration]
                if (unlockpt(p) < 0) {
                    ^
../slcanpty.c:486:14: warning: implicit declaration of function 'ptsname' is invalid in C99 [-Wimplicit-function-declaration]
                name_pts = ptsname(p);
                           ^
../slcanpty.c:486:12: warning: incompatible integer to pointer conversion assigning to 'char *' from 'int' [-Wint-conversion]
                name_pts = ptsname(p);
                         ^ ~~~~~~~~~~

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-29 18:20:18 +02:00
Marc Kleine-Budde a5c049d37a slcanpty: add missing include sys/select.h
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-29 18:20:18 +02:00
Marc Kleine-Budde 57949154cc slcanpty: sort includes alphabetically
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-29 18:20:11 +02:00
Marc Kleine-BuddeandGitHub 24b73044c5 Merge pull request #224 from marckleinebudde/canfdtest
Canfdtest
2020-06-29 18:18:18 +02:00
Marc Kleine-Budde b29a75d4c6 j1939cat: j1939cat_parse_args(): fix warning
although it looks like a false positive:

/home/travis/build/linux-can/can-utils/j1939cat.c: In function ‘main’:
/home/travis/build/linux-can/can-utils/j1939cat.c:648:6: warning: ‘ret’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  int ret;
      ^

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 12:41:48 +02:00
Marc Kleine-Budde 0f9c69c193 can-calc-bit-timing: fix warning
although it looks like a false positive:

/home/travis/build/linux-can/can-utils/can-calc-bit-timing.c: In function ‘print_bit_timing.isra.6’:
/home/travis/build/linux-can/can-utils/can-calc-bit-timing.c:447:42: warning: ‘tseg2’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  unsigned int brp, tsegall, tseg, tseg1, tseg2;
                                          ^
/home/travis/build/linux-can/can-utils/can-calc-bit-timing.c:447:35: warning: ‘tseg1’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  unsigned int brp, tsegall, tseg, tseg1, tseg2;
                                   ^

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 12:41:48 +02:00
Marc Kleine-Budde 13ecaa6d7e canfdtest: make number of frames in flight a command line option
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:59:35 +02:00
Marc Kleine-Budde d7f28a0ffe canfdtest: can_echo_dut(): check received frame for consistency
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:38:48 +02:00
Marc Kleine-Budde e393697112 canfdtest: can_echo_dut(): move functionality to increment frame data into separate function
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:38:48 +02:00
Marc Kleine-Budde 645cd1b1ba canfdtest: can_echo_dut(): make use of print_frame() instead of open coding it
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:38:48 +02:00
Marc Kleine-Budde aa5386f1cb canfdtest: print_frame(): add missing cast to uint8_t to avoid overruns
While there, use cast in compare_frame(), too.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:38:48 +02:00
Marc Kleine-Budde ff3d0e0d05 canfdtest: print_frame()/print_compare(): mark parameters "struct can_frame *" as const
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:38:17 +02:00
Marc Kleine-Budde 29605e3314 canfdtest: compare_frame(): remove stray space in front of "!"
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:26:03 +02:00
Marc Kleine-Budde d92adf68e8 canfdtest: main(): remove double ";"
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-22 11:25:21 +02:00
Marc Kleine-BuddeandGitHub 063e361cc5 Merge pull request #194 from marckleinebudde/canfdtest-initialize-tx_frames
canfdtest: can_echo_gen(): initialize tx_frames with zero
2020-06-17 12:53:32 +02:00
Marc Kleine-BuddeandGitHub e9e1a02085 Merge pull request #223 from marckleinebudde/jacd
j1939acd: replace 0x0fed8 by constant J1939_PGN_ADDRESS_COMMANDED
2020-06-17 12:51:32 +02:00
Marc Kleine-Budde 19b3ffe34b j1939acd: replace 0x0fed8 by constant J1939_PGN_ADDRESS_COMMANDED
Reported-by: josemic <josemic@users.noreply.github.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-06-17 12:37:30 +02:00
Marc Kleine-BuddeandGitHub 6553ccaf06 Merge pull request #221 from josemic/patch-4
Changed hardcoded hex number 0x0fed8 to j1939.h constant "J1939_PGN_ADDRESS_COMMANDED"
2020-06-17 12:34:51 +02:00
josemicandGitHub 1b5d3adbe5 Changed hardcoded hex number 0x0fed8 to j1939.h constant "J1939_PGN_ADDRESS_COMMANDED"
Use include constant instead of hardcoded constant
2020-06-17 10:54:46 +02:00
Marc Kleine-BuddeandGitHub e15b044a1d Merge pull request #220 from olerem/j1939acd-verbose
J1939acd verbose
2020-06-16 14:35:57 +02:00
Oliver Hartkopp 669fa79b21 j1939: Fix arithmetic on a pointer warning
Fix missing (recently introduced) j1939 files that have not been fixed
in commit 43610bd621 ("Fix arithmetic on a pointer warning") from
Gary Bisson.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-06-12 20:08:18 +02:00
Oliver Hartkopp 75d9c7e95f j1939: Fix comparison type mismatch warnings
Fix missing (recently introduced) j1939 files that have not been fixed
in commit 46895a41c5 ("Fix comparison type mismatch warnings") from
Gary Bisson.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-06-12 20:08:18 +02:00
Oliver Hartkopp 85ae5aaecf j1939acd: fix unused variable warning
open_socket() has a parameter to provide a network device name which
is properly assigned by its callers to s.intf in main().
Instead of using the callers value open_socket() directly accesses the
global s.intf which generates an unused variable warning with clang.

Fix this by using the provided parameter (no functional change).

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-06-12 20:08:18 +02:00
Oleksij Rempel 1f5c9638ab j1939acd: unify debug messages
Most of verbose messages are already stderr, make sure, rest of them do
the same.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2020-06-12 14:37:22 +02:00
Oleksij Rempel 1d3125bef2 j1939acd: do not exit on debug messages
Some debug messages were implemented using err(), which does not return,
but exit the program. This patches replaces the debug messages by
fprintf(stdout, ).

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
2020-06-12 14:24:58 +02:00
Oliver Hartkopp 62f995601e Android.mk: Introduce LOCAL_VENDOR_MODULE to build in AOSP tree
Change path for canutils modules from system/bin to vendor/bin in the
case of building in AOSP tree.

https://github.com/linux-can/can-utils/pull/204

Suggested-by: Pavel Salomatov https://github.com/PsycheEYE
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-06-04 18:02:10 +02:00
Oliver Hartkopp 647210ee1c Android.mk: Add missing targets
The J1939 tools and asc2log was missing in the Android build.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-06-04 18:02:10 +02:00
josemicandOliver Hartkopp eac93ced80 can-j1939-kickstart.md: fix example in documentation 2020-05-30 19:32:32 +02:00
Gary BissonandOliver Hartkopp da42cf4bb5 Android.mk: fix Android 10 build
Android now uses clang with Werror by default which prevents from
building.
Removing Werror for the current warnings.

Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
2020-05-29 17:58:23 +02:00
Gary BissonandOliver Hartkopp 43610bd621 Fix arithmetic on a pointer warning
Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
2020-05-28 20:54:37 +02:00
Gary BissonandOliver Hartkopp 46895a41c5 Fix comparison type mismatch warnings
Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
2020-05-28 20:54:37 +02:00
Oliver Hartkopp 2c87dcf468 can-utils: fix unused variable warnings
As pointed out by Gary Bisson clang complains about unused variables in
some valid cases.

Reported-by: Gary Bisson <gary.bisson@boundarydevices.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-28 19:32:20 +02:00
Marc Kleine-BuddeandGitHub 8df3d1dd3f Merge pull request #205 from josemic/patch-2
Update j1939acd.c
2020-05-27 09:07:24 +02:00
josemicandGitHub 255e360233 Update j1939acd.c
Minor change, as jacd had been renamed to j1939acd.
2020-05-26 23:11:33 +02:00
Oliver Hartkopp d91288f754 README: cansniffer is now also 29 bit CAN ID capable
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-11 15:26:05 +02:00
Oliver Hartkopp 9b75c6020f asc2log: support milliseconds resolution in date/time string
While strptime() does not support fractions of seconds in the date/time
string some new asc files support the milliseconds resolution.

When detecting this new format the msecs are retrieved by a separate
sscanf() invocation and added to the timeval's tv_usec element.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 19:22:53 +02:00
Oliver HartkoppandGitHub 41c8ead6c0 Rework for CAN FD support and fixes for asc to log file conversion tools
Detailed change log:

log2asc:
- support CAN FD tags and Classic CAN frames
- support RTR frames including DLC values
- new option '-r' disable the RTR DLC value for potential compatibility reasons
- new option '-f' to use the CANFD format for Classic CAN too

asc2log:
- support CAN FD tags and Classic CAN frames
- be robust against fractions of seconds in date/time string
- fix reading of RTR frames including DLC values in Classic CAN parsing
- fix date/time string detection

cangen:
- new option '-E' to support ESI bit for CAN FD frame generation
(was needed for reference log file generation)
2020-05-10 16:45:21 +02:00
Oliver Hartkopp 3bb659d18d asc2log: fix handling for RTR frames in Classic CAN mode
Fix reading of the RTR representation without and with DLC (v8.5+ tools).

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 15:09:55 +02:00
Oliver Hartkopp 9cde2ebe8f asc2log: fix date string detection
The former check was too complex and did not catch all valid cases.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 14:41:34 +02:00
Oliver Hartkopp 7729c046c5 cangen: support ESI bit for CAN FD frame generation
The CAN FD frames support BTR and ESI as special flags. While BTR could
be generated by cangen the ESI bit could not be generated so far.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 12:03:35 +02:00
Oliver Hartkopp 61dbb56ef6 log2asc: support DLC values in Classic CAN RTR frames
RTR frames contain a valid DLC value which has not been exposed in the
ASC file format since v8.5 of the tools.

So log2asc will expose this DLC value by default which can be changed
by applying the '-r' option to create the former format.

It can be assumed that the tools pre v8.5 will ignore the value but
if not this switch will make sure to create the old format.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 11:45:03 +02:00
Oliver Hartkopp 3014d390b4 log2asc: support CANFD format also for Classic CAN
The CANFD tagged format also supports the encapsulation of Classic CAN
frames which is selected when logging on CAN FD capable CAN interfaces.

With a new option '-f' this CANFD format is selected.

Although this representation is even more inefficient it is seems to be
the common way and increases the readability for mixed CAN/CANFD logs.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 11:22:05 +02:00
Oliver Hartkopp ad9fc28f9e asc2log: add sanity checks for search pattern
Add some more sanity checks and increase readability for the sscanf()
procedure to read a CANFD tagged line.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-10 10:44:11 +02:00
Oliver Hartkopp 9a079942cd log2asc: support CANFD asc file generation
The CANFD asc format adds information about the CAN controllers bitrate
settings, CRCs and message length (in bits) and its duration.

The plan is to provide static values for these attributes that we can not
get from the log file anyway and stay on the 'old style' format for
classic CAN frames - which has been successfully tested on the latest tools.

The remaining drawback is that the 'old style' format is not able to
provide a DLC information for RTR frames.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-09 22:08:19 +02:00
Oliver Hartkopp ed9c646608 log2asc: reorder code to prepare CAN FD support
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-09 19:04:53 +02:00
Oliver Hartkopp df0b25c17e asc2log: support CANFD tagged asc file content
Handles CANFD asc files with classic CAN and CAN FD frames.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-09 18:42:55 +02:00
Oliver Hartkopp 3c8197e4d1 asc2log: make date time sting milliseconds aware
strptime() does not support milliseconds but the latest ASC logfile
also provides a fraction of seconds, e.g.

date Fri May 8 08:49:04.052 pm 2020

Read the value into the year variable before parsing the real year.
We will therefore omit the milliseconds resolution for now.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-09 18:19:24 +02:00
Oliver Hartkopp 43a3cca54d asc2log: reorder code to prepare CAN FD support
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-09 13:10:27 +02:00
Oliver Hartkopp becc0fc6cc cansniffer: fix buffer length in readsettings()
The Android build discovered a char buffer overflow in readsettings().

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-05-07 18:49:20 +02:00
Oliver HartkoppandGitHub c5cb7e1a7c Merge pull request #200 from hartkopp/29bit-cansniffer
cansniffer: support EFF frames with 29 bit CAN IDs

Convert cansniffer from CAN_BCM to CAN_RAW sockets and handle the
content filter in user space. Conversion CAN_RAW including slot
concept and sorting contributed by @coryjfowler.

Functional changes visible to users:
    
- New format for settings file (using 'r' and 'w' interactive commands)
- New command '8' to switch in a compact binary view for 80 columns view
- New head line layout
- The gap time between CAN frames is displayed in milli seconds (ms)
- The interactive filters support 29 bit CAN IDs
- New interactive command to clear/redraw the screen (<SPACE><ENTER>)
- New interactive commands to enable/disable SFF/EFF frames
    a<ENTER>        - enable 'a'll SFF CAN-IDs to sniff
    n<ENTER>        - enable 'n'one SFF CAN-IDs to sniff
    A<ENTER>        - enable 'A'll EFF CAN-IDs to sniff
    N<ENTER>        - enable 'N'one EFF CAN-IDs to sniff
- Fixes in bit change colorization and gap calculation detected at rework
2020-05-07 18:35:50 +02:00
Rasmus PedersenandGitHub 729e346d31 cangen.c: added -c option for bursty output. (#201)
added -c option for bursty output.
specify -c 100 to have 100 packets sent in burst before a gap.
use for example -p 1000 to avoid TX buffer full errors
2020-05-05 10:14:58 +02:00
Oliver Hartkopp 7575d43fd2 cangen: fix doubled description in help text
The help2man conversion created a second application description.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 19:11:41 +02:00
Oliver Hartkopp 2a8867f3cb cansniffer: add short description in help text
Following other can-utils applications.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 19:06:57 +02:00
Oliver Hartkopp ab2e8ffe0e cansniffer: formatting and variable renaming
Some unification of code formatting and rename of a variable in
print_snifline() which does not represent a CAN ID anymore.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 18:56:25 +02:00
Oliver Hartkopp ac55db508a cansniffer: exit after displaying help text
Do not start the application when the user wants to read the help text.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 09:55:28 +02:00
Oliver Hartkopp 64e33bf9ad cansniffer: add new interactive commands to enable/disable SFF/EFF frames
With the new commands

a<ENTER>        - enable 'a'll SFF CAN-IDs to sniff
n<ENTER>        - enable 'n'one SFF CAN-IDs to sniff
A<ENTER>        - enable 'A'll EFF CAN-IDs to sniff
N<ENTER>        - enable 'N'one EFF CAN-IDs to sniff

the EFF/SFF frames can be added/removed with a single command.
Of course this could be done with the '+' and '-' filters too.
But 'N' is much easier to type then '-0000000000000000' ...

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 09:52:20 +02:00
Oliver Hartkopp adf29573f4 cansniffer: add interactive command to clear/redraw the screen
For efficiency reasons on slow embedded machines cansniffer usually
does not clear the screen but only writes updates on required lines.
Sometimes the written lines exceed the terminal lines and people
resize the window which is not detected by cansniffer.

With entering <SPACE><ENTER> in interactive mode the screen can be
forced to redraw after resizing the terminal window.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 09:51:33 +02:00
Oliver Hartkopp bd6ef44321 cansniffer: support EFF frames with 29 bit CAN IDs
Convert cansniffer from CAN_BCM to CAN_RAW sockets and handle the
content filter in user space. Conversion CAN_RAW including slot
concept and sorting contributed by coryjfowler.

Functional changes visible to users:

- New format for settings file
- New command '8' to switch in a compact binary view for 80 columns view
- New head line layout
- The gap time between CAN frames is displayed in milli seconds (ms)
- The interactive filters support 29 bit CAN IDs

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 09:48:52 +02:00
Oliver Hartkopp 6d112a7209 cansniffer: terminate when settings file is not found
Clean up readsettings() and terminate when the settings file
'sniffset.*' is not found when given on commandline.

The readsettings() status output could not be read anyway due to
instant redraw from CAN frames.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 07:18:47 +02:00
Oliver Hartkopp 6f44582c19 cansniffer: make use of if_nametoindex()
Simplify the code as in other can-utils applications.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 06:57:16 +02:00
Oliver Hartkopp 507ff82d81 cansniffer: remove CAN_BCM specific functionalities
Remove functionalities that are not supported resp. can not be implemented
after the CAN_BCM to CAN_RAW conversion of cansnifffer.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-29 06:49:39 +02:00
Oliver Hartkopp 1665abf46f can-utils: fix missing include of libgen.h
The basename() function needs libgen.h to be included as otherwise this
will fail to compile in some environments.

Reported-by: Robert Schwebel <r.schwebel@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-28 19:14:52 +02:00
Oliver Hartkopp 853989bed2 canplayer: make help text fit into 80 colums again
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-28 19:01:45 +02:00
Oliver Hartkopp f3ced10007 cangw: make help text fit into 80 colums again
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-28 19:01:07 +02:00
Oliver Hartkopp 819a03f6e2 candump: fix/unify help text indention
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-28 18:59:37 +02:00
Oliver Hartkopp e266422c54 isotpdump: make help text fit into 80 colums again
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-28 18:57:26 +02:00
Oliver Hartkopp 5ca66d7bea slcanpty: simplify tool decription in help text
Simplify tool description and format the empty lines like in other
(e.g. slcand) tools.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-27 11:09:05 +02:00
Oliver Hartkopp d007263021 cansend: simplify tool decription in help text
Simplify tool description and format the empty lines like in other
(e.g. slcand) tools.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-27 10:53:02 +02:00
Oliver HartkoppandGitHub f91b537c01 Merge pull request #69 from gerasiov/help-reformat
Reformat output of help/usage information - Thanks Alexander!
2020-04-27 09:16:13 +02:00
Alexander GQ GerasiovandAlexander Gerasiov b43d1b4d27 cansend.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0010-cansend.c-Reformat-help-usage-output-to-be-compatibl.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov f638cdc79b slcanpty.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0029-slcanpty.c-Reformat-help-usage-output-to-be-compatib.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov d89b38de8a jcat.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0028-jcat.c-Reformat-help-usage-output-to-be-compatible-w.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov d39cb046d1 testj1939.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0025-testj1939.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 9e491bc553 slcand.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0024-slcand.c-Reformat-help-usage-output-to-be-compatible.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 09f6dc6d17 slcan_attach.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0023-slcan_attach.c-Reformat-help-usage-output-to-be-comp.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 8e6c11128d log2asc.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0022-log2asc.c-Reformat-help-usage-output-to-be-compatibl.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 276688f2ad jsr.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0021-jsr.c-Reformat-help-usage-output-to-be-compatible-wi.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 0155472ee0 jspy.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0020-jspy.c-Reformat-help-usage-output-to-be-compatible-w.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov 211c5cea49 can-calc-bit-timing.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0020-can-calc-bit-timing.c-Reformat-help-usage-output-to-.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov c1fdfb09fc jcat.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander GQ Gerasiov <gq@cs.msu.su>

Gbp-Pq: Name 0019-jcat.c-Reformat-help-usage-output-to-be-compatible-w.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 506252e9bc jacd.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0019-jacd.c-Reformat-help-usage-output-to-be-compatible-w.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 89c66aba5f isotptun.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0018-isotptun.c-Reformat-help-usage-output-to-be-compatib.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov c61c9bc030 isotpsniffer.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0017-isotpsniffer.c-Reformat-help-usage-output-to-be-comp.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov 9240ccfcb7 isotpserver.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0016-isotpserver.c-Reformat-help-usage-output-to-be-compa.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 3d6a53550e isotpsend.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0015-isotpsend.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov 1cf4d86874 isotprecv.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0014-isotprecv.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 4db63e4b55 isotpperf.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0013-isotpperf.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:09 +03:00
Alexander GQ GerasiovandAlexander Gerasiov 24af048812 isotpdump.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0012-isotpdump.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 4568d4a180 cansniffer.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0011-cansniffer.c-Reformat-help-usage-output-to-be-compat.patch
2020-04-27 08:20:09 +03:00
Alexander GerasiovandAlexander Gerasiov 3e2c1d3cbd canplayer.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0009-canplayer.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:08 +03:00
Alexander GerasiovandAlexander Gerasiov 65399166c1 canlogserver.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0008-canlogserver.c-Reformat-help-usage-output-to-be-comp.patch
2020-04-27 08:20:08 +03:00
Alexander GQ GerasiovandAlexander Gerasiov 1127609357 cangw.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0007-cangw.c-Reformat-help-usage-output-to-be-compatible-.patch
2020-04-27 08:20:08 +03:00
Alexander GerasiovandAlexander Gerasiov f503097a38 cangen.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0006-cangen.c-Reformat-help-usage-output-to-be-compatible.patch
2020-04-27 08:20:08 +03:00
Alexander GerasiovandAlexander Gerasiov c56259ab33 canfdtest.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0005-canfdtest.c-Reformat-help-usage-output-to-be-compati.patch
2020-04-27 08:20:08 +03:00
Alexander GQ GerasiovandAlexander Gerasiov 6db632531d candump.c: Reformat help/usage output to be compatible with help2man.
Gbp-Pq: Name 0004-candump.c-Reformat-help-usage-output-to-be-compatibl.patch
2020-04-27 08:20:08 +03:00
Alexander GerasiovandAlexander Gerasiov f4a9e5b57d can-calc-bit-timing.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0003-can-calc-bit-timing.c-Reformat-help-usage-output-to-.patch
2020-04-27 08:20:08 +03:00
Alexander GerasiovandAlexander Gerasiov 69865c8247 canbusload.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0002-canbusload.c-Reformat-help-usage-output-to-be-compat.patch
2020-04-27 08:20:08 +03:00
Alexander GerasiovandAlexander Gerasiov b740fb7fab asc2log.c: Reformat help/usage output to be compatible with help2man.
Signed-off-by: Alexander Gerasiov <gq@debian.org>

Gbp-Pq: Name 0001-asc2log.c-Reformat-help-usage-output-to-be-compatibl.patch
2020-04-27 08:20:08 +03:00
Oliver Hartkopp bceadb8696 cansniffer: fix colorization when notching relevant bits
When notching marked (and colored) bits with the interactive '#' command
the binary output omits colored bits - as intended.

But when switching back to the hex and ASCII output the bytes with
notched bits remained uncolored even when some bits inside the hex bytes
would have needed to be colored.

The check for the colored output was a logical AND operation which is
fine for the binary representation but needed to be a bit-wise operation
in the hex/ASCII byte mode case.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-26 15:56:08 +02:00
Oliver Hartkopp eb639c1b3d cansniffer: fix gap calculation output
The gap between two consecutive frames of a specific has been calculated in
handle_timeo() instead of handle_bcm() which lead to values that where
at minimum the loop time of the display refresh.

The effect can be seen when displaying a 10ms gap CAN frame with a 200ms
display refresh (option -l 20 => default) in opposite to a 10ms display
refresh (option -l 1).

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-04-26 08:30:55 +02:00
Marc Kleine-BuddeandGitHub 6cdccbbafc Merge pull request #199 from gerasiov/j1939rename
Rename j* to j1939\1
2020-04-24 13:01:51 +02:00
Alexander GQ Gerasiov 8106214b55 Rename j* to j1939\1
Using j*smthng* for j1939-related tools is not very good for 2 reasons:
1. j prefix is not very informative;
2. jcat name is used by journal cat tool from popular sleuthkit toolkit;
2`. jacd sounds very similar to jackd.
2``. Possible future name conflicts for new tools.

Thus I renamed j* to j1939\1 to deal with this issue.

Signed-off-by: Alexander GQ Gerasiov <gq@cs.msu.su>
2020-04-20 10:18:13 +03:00
Oliver Hartkopp da65fdfe0d isotpsniffer: only invoke LL_OPTS setsockopt when set on commandline
In commit da33f96edf ("isotpsniffer: Add support for llopts") the
setsockopt() syscall for the link layer options CAN_ISOTP_LL_OPTS
has been added.

Unfortunately the syscall has been invoked even if there were no values
given on the command line and 'zero values' have been passed to the
kernel which correctly answered with -EINVAL.

And a missing check for a mandatory non-zero value for the MTU.

Fixes: da33f96edf ("isotpsniffer: Add support for llopts")
Reported by: https://github.com/ikuyas
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-02-04 17:28:11 +01:00
Oliver Hartkopp ae69062657 isotpsniffer: remove duplicated code
In commit da33f96edf ("isotpsniffer: Add support for llopts") the setsockopt
call has been executed twice. (copy & paste issue?)

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2020-02-04 08:31:48 +01:00
Marc Kleine-Budde 506f6f3043 canfdtest: can_echo_gen(): initialize tx_frames with zero
This avoids having the padding in the struct can_fame contain bogus
values, which are interpreted by "candump -x" as CAN-FD BRS and ESI
values.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2020-02-03 23:58:34 +01:00
60 changed files with 5377 additions and 1737 deletions
+7 -4
View File
@@ -20,6 +20,7 @@ GNUmakefile.in
/config/m4/ltsugar.m4
/config/m4/ltversion.m4
/config/m4/lt~obsolete.m4
/mcp251xfd/.dirstamp
/asc2log
/bcmserver
@@ -32,6 +33,7 @@ GNUmakefile.in
/canlogserver
/canplayer
/cansend
/cansequence
/cansniffer
/isotpdump
/isotpperf
@@ -40,12 +42,13 @@ GNUmakefile.in
/isotpserver
/isotpsniffer
/isotptun
/jacd
/jcat
/jspy
/jsr
/j1939acd
/j1939cat
/j1939spy
/j1939sr
/log2asc
/log2long
/mcp251xfd-dump
/slcan_attach
/slcand
/slcanpty
+64 -6
View File
@@ -2,6 +2,9 @@ language: c
matrix:
include:
# native
- env: test="x64 4.8.4 (make)"
os: linux
dist: trusty
@@ -27,7 +30,7 @@ matrix:
before_script:
- mkdir gcc_rel && cd gcc_rel
- cmake ..
script: make
script: make
- env: test="x64 5.0 (CMake clang)"
os: linux
@@ -36,7 +39,7 @@ matrix:
before_script:
- mkdir clang_rel && cd clang_rel
- cmake ..
script: make
script: make
- env: test="x64 5.0 (CMake clang - Ninja) Debug"
os: linux
@@ -45,15 +48,70 @@ matrix:
before_script:
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
script: ninja
script: ninja
# ppc64le
- env: test="ppc64le 4.8.4 (make)"
os: linux
dist: trusty
compiler: gcc
script: make
arch: ppc64le
- env: test="ppc64le 4.8.4 (autotools)"
os: linux
dist: trusty
compiler: gcc
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
arch: ppc64le
- env: test="ppc64le 5.0 (autotools)"
os: linux
dist: trusty
compiler: clang
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
arch: ppc64le
- env: test="ppc64le 4.8.4 (CMake gcc)"
os: linux
dist: trusty
compiler: gcc
before_script:
- mkdir gcc_rel && cd gcc_rel
- cmake ..
script: make
arch: ppc64le
- env: test="ppc64le 5.0 (CMake clang)"
os: linux
dist: trusty
compiler: clang
before_script:
- mkdir clang_rel && cd clang_rel
- cmake ..
script: make
arch: ppc64le
- env: test="ppc64le 5.0 (CMake clang - Ninja) Debug"
os: linux
dist: trusty
compiler: clang
before_script:
- mkdir clang_ninja_dbg && cd clang_ninja_dbg
- cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug
script: ninja
arch: ppc64le
# Android
- env: test="Android NDK (CMake)"
os: linux
language: android
android:
components:
- build-tools-25.0.2
install:
components:
- build-tools-25.0.2
install:
- echo y | sdkmanager "ndk-bundle"
- echo y | sdkmanager "cmake;3.6.4111459"
before_script:
+150 -2
View File
@@ -1,6 +1,7 @@
LOCAL_PATH := $(call my-dir)
PRIVATE_LOCAL_CFLAGS := -O2 -g -W -Wall \
-Wno-error=unused-parameter \
-DSO_RXQ_OVFL=40 \
-DPF_CAN=29 \
-DAF_CAN=PF_CAN
@@ -15,9 +16,104 @@ LOCAL_SRC_FILES := lib.c canframelen.c
LOCAL_MODULE := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_STATIC_LIBRARY)
#
# j1939lib
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libj1939.c
LOCAL_MODULE := libj1939
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_STATIC_LIBRARY)
#
# j1939acd
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := j1939acd.c
LOCAL_MODULE := j1939acd
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libj1939
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# j1939cat
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := j1939cat.c
LOCAL_MODULE := j1939cat
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libj1939
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# j1939spy
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := j1939spy.c
LOCAL_MODULE := j1939spy
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libj1939
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# j1939sr
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := j1939sr.c
LOCAL_MODULE := j1939sr
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libj1939
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# testj1939
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := testj1939.c
LOCAL_MODULE := testj1939
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libj1939
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# candump
#
@@ -30,6 +126,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -45,6 +142,21 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# cansequence
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cansequence.c
LOCAL_MODULE := cansequence
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
include $(BUILD_EXECUTABLE)
@@ -59,10 +171,10 @@ LOCAL_MODULE := bcmserver
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# can-calc-bit-timing
#
@@ -74,6 +186,7 @@ LOCAL_MODULE := can-calc-bit-timing
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -89,6 +202,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -103,6 +217,7 @@ LOCAL_MODULE := canfdtest
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -118,6 +233,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -132,6 +248,7 @@ LOCAL_MODULE := cangw
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -147,6 +264,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -162,6 +280,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -176,6 +295,7 @@ LOCAL_MODULE := cansniffer
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -190,6 +310,7 @@ LOCAL_MODULE := isotpdump
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -204,6 +325,7 @@ LOCAL_MODULE := isotprecv
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -218,6 +340,7 @@ LOCAL_MODULE := isotpsend
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -232,6 +355,7 @@ LOCAL_MODULE := isotpserver
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -242,10 +366,11 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotpsniffer.c
LOCAL_MODULE := isotpsniffer.c
LOCAL_MODULE := isotpsniffer
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -260,6 +385,7 @@ LOCAL_MODULE := isotptun
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -274,6 +400,7 @@ LOCAL_MODULE := isotpperf
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -289,6 +416,23 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# asc2log
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := asc2log.c
LOCAL_MODULE := asc2log
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -304,6 +448,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libcan
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -318,6 +463,7 @@ LOCAL_MODULE := slcan_attach
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -332,6 +478,7 @@ LOCAL_MODULE := slcand
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
@@ -346,5 +493,6 @@ LOCAL_MODULE := slcanpty
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
+15 -5
View File
@@ -2,13 +2,15 @@ cmake_minimum_required(VERSION 3.3)
project(can-utils LANGUAGES C)
include (CheckSymbolExists)
include (GNUInstallDirs)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE)
if(_GNU_SOURCE)
add_definitions(-D_GNU_SOURCE)
endif()
@@ -31,15 +33,16 @@ set(PROGRAMS_CANLIB
canlogserver
canplayer
cansend
cansequence
log2asc
log2long
)
set(PROGRAMS_J1939
jacd
jcat
jspy
jsr
j1939acd
j1939cat
j1939spy
j1939sr
testj1939
)
@@ -62,6 +65,13 @@ set(PROGRAMS
slcanpty
)
add_executable(mcp251xfd-dump
mcp251xfd/mcp251xfd-dev-coredump.c
mcp251xfd/mcp251xfd-dump.c
mcp251xfd/mcp251xfd-main.c
mcp251xfd/mcp251xfd-regmap.c
)
if(NOT ANDROID)
list(APPEND PROGRAMS ${PROGRAMS_J1939})
+23 -9
View File
@@ -24,6 +24,7 @@ noinst_HEADERS = \
include/linux/can/raw.h \
include/linux/can/vxcan.h \
include/linux/errqueue.h \
include/linux/kernel.h \
include/linux/net_tstamp.h \
include/linux/netlink.h
@@ -38,6 +39,15 @@ libcan_la_SOURCES = \
libj1939_la_SOURCES = \
libj1939.c
mcp251xfd_dump_SOURCES = \
mcp251xfd/mcp251xfd-dev-coredump.c \
mcp251xfd/mcp251xfd-dump-userspace.h \
mcp251xfd/mcp251xfd-dump.c \
mcp251xfd/mcp251xfd-dump.h \
mcp251xfd/mcp251xfd-main.c \
mcp251xfd/mcp251xfd-regmap.c \
mcp251xfd/mcp251xfd.h
bin_PROGRAMS = \
asc2log \
bcmserver \
@@ -50,6 +60,7 @@ bin_PROGRAMS = \
canlogserver \
canplayer \
cansend \
cansequence \
cansniffer \
isotpdump \
isotpperf \
@@ -58,21 +69,22 @@ bin_PROGRAMS = \
isotpserver \
isotpsniffer \
isotptun \
jacd \
jcat \
jspy \
jsr \
j1939acd \
j1939cat \
j1939spy \
j1939sr \
log2asc \
log2long \
mcp251xfd-dump \
slcan_attach \
slcand \
slcanpty \
testj1939
jacd_LDADD = libj1939.la
jcat_LDADD = libj1939.la
jspy_LDADD = libj1939.la
jsr_LDADD = libj1939.la
j1939acd_LDADD = libj1939.la
j1939cat_LDADD = libj1939.la
j1939spy_LDADD = libj1939.la
j1939sr_LDADD = libj1939.la
testj1939_LDADD = libj1939.la
EXTRA_DIST = \
@@ -81,7 +93,9 @@ EXTRA_DIST = \
README.md \
autogen.sh \
can-j1939-kickstart.md \
can-j1939.md
can-j1939.md \
mcp251xfd/99-devcoredump.rules \
mcp251xfd/devcoredump
MAINTAINERCLEANFILES = \
configure \
+19 -12
View File
@@ -67,10 +67,10 @@ PROGRAMS_ISOTP := \
isotptun
PROGRAMS_J1939 := \
jacd \
jcat \
jspy \
jsr \
j1939acd \
j1939cat \
j1939spy \
j1939sr \
testj1939
PROGRAMS_SLCAN := \
@@ -89,12 +89,14 @@ PROGRAMS := \
candump \
canfdtest \
cangen \
cansequence \
canlogserver \
canplayer \
cansend \
cansniffer \
log2asc \
log2long \
mcp251xfd-dump \
slcanpty
all: $(PROGRAMS)
@@ -116,12 +118,13 @@ cangen.o: lib.h
canlogserver.o: lib.h
canplayer.o: lib.h
cansend.o: lib.h
cansequence.o: lib.h
log2asc.o: lib.h
log2long.o: lib.h
jacd.o: libj1939.h
jcat.o: libj1939.h
jspy.o: libj1939.h
jsr.o: libj1939.h
j1939acd.o: libj1939.h
j1939cat.o: libj1939.h
j1939spy.o: libj1939.h
j1939sr.o: libj1939.h
testj1939.o: libj1939.h
canframelen.o: canframelen.h
@@ -131,11 +134,15 @@ cangen: cangen.o lib.o
canlogserver: canlogserver.o lib.o
canplayer: canplayer.o lib.o
cansend: cansend.o lib.o
cansequence: cansequence.o lib.o
log2asc: log2asc.o lib.o
log2long: log2long.o lib.o
jacd: jacd.o libj1939.o
jcat: jcat.o libj1939.o
jspy: jspy.o libj1939.o
jsr: jsr.o libj1939.o
j1939acd: j1939acd.o libj1939.o
j1939cat: j1939cat.o libj1939.o
j1939spy: j1939spy.o libj1939.o
j1939sr: j1939sr.o libj1939.o
testj1939: testj1939.o libj1939.o
canbusload: canbusload.o canframelen.o
mcp251xfd-dump: mcp251xfd/mcp251xfd-dev-coredump.o mcp251xfd/mcp251xfd-dump.o mcp251xfd/mcp251xfd-main.o mcp251xfd/mcp251xfd-regmap.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
+12 -1
View File
@@ -13,7 +13,8 @@ subsystem (aka SocketCAN):
* canplayer : replay CAN logfiles
* cansend : send a single frame
* cangen : generate (random) CAN traffic
* cansniffer : display CAN data content differences (just 11bit CAN IDs)
* cansequence : send and check sequence of CAN frames with incrementing payload
* cansniffer : display CAN data content differences
#### CAN access via IP sockets
* canlogserver : log CAN frames from a remote/local host
@@ -38,6 +39,16 @@ subsystem (aka SocketCAN):
* isotpperf : ISO15765-2 protocol performance visualisation
* isotptun : create a bi-directional IP tunnel on CAN via ISO-TP
#### J1939/ISOBus tools
* j1939acd : address claim daemon
* j1939cat : take a file and send and receive it over CAN
* j1939spy : spy on J1939 messages using SOC_J1939
* j1939sr : send/recv from stdin or to stdout
* testj1939 : send/receive test packet
Follow the link to see examples on how this tools can be used:
[Kickstart guide to can-j1939 on linux](https://github.com/linux-can/can-utils/blob/master/can-j1939-kickstart.md)
#### Log file converters
* asc2log : convert ASC logfile to compact CAN frame logfile
* log2asc : convert compact CAN frame logfile to ASC logfile
+282 -109
View File
@@ -42,44 +42,47 @@
*
*/
#include <libgen.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <libgen.h>
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/error.h>
#include <net/if.h>
#include "lib.h"
#define BUFLEN 400 /* CAN FD mode lines can be pretty long */
extern int optind, opterr, optopt;
void print_usage(char *prg)
{
fprintf(stderr, "%s - convert ASC logfile to compact CAN frame logfile.\n", prg);
fprintf(stderr, "Usage: %s\n", prg);
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
fprintf(stderr, " -O <outfile> (default stdout)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, "\t-I <infile>\t(default stdin)\n");
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
}
void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) {
void prframe(FILE *file, struct timeval *tv, int dev, struct canfd_frame *cf, unsigned int max_dlen, char *extra_info) {
fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
fprintf(file, "(%lu.%06lu) ", tv->tv_sec, tv->tv_usec);
if (dev > 0)
fprintf(file, "can%d ", dev-1);
else
fprintf(file, "canX ");
/* no CAN FD support so far */
fprint_canframe(file, (struct canfd_frame *)cf, "\n", 0, CAN_MAX_DLEN);
fprint_canframe(file, cf, extra_info, 0, max_dlen);
}
void get_can_id(struct can_frame *cf, char *idstring, int base) {
void get_can_id(struct canfd_frame *cf, char *idstring, int base) {
if (idstring[strlen(idstring)-1] == 'x') {
cf->can_id = CAN_EFF_FLAG;
@@ -116,20 +119,239 @@ void calc_tv(struct timeval *tv, struct timeval *read_tv,
tv->tv_usec += read_tv->tv_usec;
}
if (tv->tv_usec > 1000000) {
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
}
void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, int dplace, FILE *outfile) {
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct canfd_frame cf;
char rtr;
int dlc = 0;
int data[8];
char tmp1[BUFLEN];
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
char *extra_info;
int i, items, found;
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
found = 0; /* found valid CAN frame ? */
if (base == 'h') { /* check for CAN frames with hexadecimal values */
items = sscanf(buf, "%lu.%lu %d %s %2s %c %d %x %x %x %x %x %x %x %x",
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
tmp1, dir, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]);
if ((items == dlc + 7 ) || /* data frame */
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
found = 1;
get_can_id(&cf, tmp1, 16);
}
} else { /* check for CAN frames with decimal values */
items = sscanf(buf, "%lu.%lu %d %s %2s %c %d %d %d %d %d %d %d %d %d",
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
tmp1, dir, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]);
if ((items == dlc + 7 ) || /* data frame */
((items == 6) && (rtr == 'r')) || /* RTR without DLC */
((items == 7) && (rtr == 'r'))) { /* RTR with DLC */
found = 1;
get_can_id(&cf, tmp1, 10);
}
}
if (found) {
if (dlc > CAN_MAX_DLC)
return;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (dir[0] == 'R')
extra_info = " R\n";
else
extra_info = " T\n";
cf.len = dlc;
if (rtr == 'r')
cf.can_id |= CAN_RTR_FLAG;
else
for (i = 0; i < dlc; i++)
cf.data[i] = data[i] & 0xFFU;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, extra_info);
fflush(outfile);
return;
}
/* check for ErrorFrames */
if (sscanf(buf, "%lu.%lu %d %s",
&read_tv.tv_sec, &read_tv.tv_usec,
&interface, tmp1) == 4) {
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
memset(&cf, 0, sizeof(cf));
/* do not know more than 'Error' */
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
cf.len = CAN_ERR_DLC;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, "\n");
fflush(outfile);
}
}
}
void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace, FILE *outfile) {
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct canfd_frame cf = { 0 };
unsigned char brs, esi, ctmp;
unsigned int flags;
int dlc, dlen = 0;
char tmp1[BUFLEN];
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
char *extra_info;
char *ptr;
int i;
/* The CANFD format is mainly in hex representation but <DataLength>
and probably some content we skip anyway. Don't trust the docs! */
/* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \
100000 214 223040 80000000 46500250 460a0250 20011736 20010205 */
/* check for valid line without symbolic name */
if (sscanf(buf, "%lu.%lu %*s %d %2s %s %hhx %hhx %x %d ",
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
/* check for valid line with a symbolic name */
if (sscanf(buf, "%lu.%lu %*s %d %2s %s %*s %hhx %hhx %x %d ",
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
/* no valid CANFD format pattern */
return;
}
}
/* check for allowed (unsigned) value ranges */
if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC) ||
(brs > 1) || (esi > 1))
return;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (dir[0] == 'R')
extra_info = " R\n";
else
extra_info = " T\n";
/* don't trust ASCII content - sanitize data length */
if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen)))
return;
get_can_id(&cf, tmp1, 16);
/* now search for the beginning of the data[] content */
sprintf(tmp1, " %x %x %x %2d ", brs, esi, dlc, dlen);
/* search for the pattern generated by real data */
ptr = strcasestr(buf, tmp1);
if (ptr == NULL)
return;
ptr += strlen(tmp1); /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip MessageDuration and MessageLength to get Flags value */
if (sscanf(ptr, " %*x %*x %x ", &flags) != 1)
return;
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
if (flags & ASC_F_FDF) {
dlen = CANFD_MAX_DLEN;
if (flags & ASC_F_BRS)
cf.flags |= CANFD_BRS;
if (flags & ASC_F_ESI)
cf.flags |= CANFD_ESI;
} else {
/* yes. The 'CANFD' format supports classic CAN content! */
dlen = CAN_MAX_DLEN;
if (flags & ASC_F_RTR) {
cf.can_id |= CAN_RTR_FLAG;
/* dlen is always 0 for classic CAN RTR frames
but the DLC value is valid in RTR cases */
cf.len = dlc;
/* sanitize payload length value */
if (dlc > CAN_MAX_DLEN)
cf.len = CAN_MAX_DLEN;
}
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((cf.len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
struct can_frame *ccf = (struct can_frame *)&cf;
ccf->len8_dlc = dlc;
}
}
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf, dlen, extra_info);
fflush(outfile);
/* No support for really strange CANFD ErrorFrames format m( */
}
int get_date(struct timeval *tv, char *date) {
char ctmp[10];
int itmp;
struct tm tms;
unsigned int msecs = 0;
if (sscanf(date, "%9s %d %9s %9s %d", ctmp, &itmp, ctmp, ctmp, &itmp) == 5) {
if (strcasestr(date, " pm ") != NULL) {
/* assume EN/US date due to existing am/pm field */
if (!setlocale(LC_TIME, "en_US")) {
@@ -137,29 +359,39 @@ int get_date(struct timeval *tv, char *date) {
return 1;
}
if (!strptime(date, "%B %d %r %Y", &tms))
return 1;
if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) {
/* The string might contain a milliseconds value which strptime()
does not support. So we read the ms value into the year variable
before parsing the real year value (hack) */
if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms))
return 1;
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
}
} else {
/* assume DE date due to non existing am/pm field */
if (sscanf(date, "%9s %d %9s %d", ctmp, &itmp, ctmp, &itmp) != 4)
return 1;
if (!setlocale(LC_TIME, "de_DE")) {
fprintf(stderr, "Setting locale to 'de_DE' failed!\n");
return 1;
}
if (!strptime(date, "%B %d %T %Y", &tms))
return 1;
if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) {
/* The string might contain a milliseconds value which strptime()
does not support. So we read the ms value into the year variable
before parsing the real year value (hack) */
if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms))
return 1;
sscanf(date, "%*s %*d %*d:%*d:%*d.%3u ", &msecs);
}
}
//printf("h %d m %d s %d d %d m %d y %d\n",
//tms.tm_hour, tms.tm_min, tms.tm_sec,
//printf("h %d m %d s %d ms %03d d %d m %d y %d\n",
//tms.tm_hour, tms.tm_min, tms.tm_sec, msecs,
//tms.tm_mday, tms.tm_mon+1, tms.tm_year+1900);
tv->tv_sec = mktime(&tms);
tv->tv_usec = msecs * 1000;
if (tv->tv_sec < 0)
return 1;
@@ -169,24 +401,17 @@ int get_date(struct timeval *tv, char *date) {
int main(int argc, char **argv)
{
char buf[100], tmp1[100], tmp2[100];
char buf[BUFLEN], tmp1[BUFLEN], tmp2[BUFLEN];
FILE *infile = stdin;
FILE *outfile = stdout;
static int verbose;
struct can_frame cf;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
static struct timeval tmp_tv; /* tmp frame timestamp from ASC file */
static struct timeval date_tv; /* date of the ASC file */
static int dplace; /* decimal place 4, 5 or 6 or uninitialized */
static char base; /* 'd'ec or 'h'ex */
static char timestamps; /* 'a'bsolute or 'r'elative */
int interface;
char rtr;
int dlc = 0;
int data[8];
int i, found, opt;
int opt;
while ((opt = getopt(argc, argv, "I:O:v?")) != -1) {
switch (opt) {
@@ -224,7 +449,7 @@ int main(int argc, char **argv)
}
while (fgets(buf, 99, infile)) {
while (fgets(buf, BUFLEN-1, infile)) {
if (!dplace) { /* the representation of a valid CAN frame not known */
@@ -259,87 +484,35 @@ int main(int argc, char **argv)
gettimeofday(&date_tv, NULL);
}
if (verbose)
printf("date %ld => %s", date_tv.tv_sec, ctime(&date_tv.tv_sec));
printf("date %lu => %s", date_tv.tv_sec, ctime(&date_tv.tv_sec));
continue;
}
/* check for decimal places length in valid CAN frames */
if (sscanf(buf, "%ld.%s %d ", &tv.tv_sec, tmp2, &i) == 3){
dplace = strlen(tmp2);
if (verbose)
printf("decimal place %d, e.g. '%s'\n", dplace, tmp2);
if (dplace < 4 || dplace > 6) {
printf("invalid dplace %d (must be 4, 5 or 6)!\n", dplace);
return 1;
}
} else
if (sscanf(buf, "%lu.%s %s ", &tmp_tv.tv_sec, tmp2,
tmp1) != 3)
continue; /* dplace remains zero until first found CAN frame */
}
dplace = strlen(tmp2);
if (verbose)
printf("decimal place %d, e.g. '%s'\n", dplace,
tmp2);
if (dplace < 4 || dplace > 6) {
printf("invalid dplace %d (must be 4, 5 or 6)!\n",
dplace);
return 1;
}
}
/* the representation of a valid CAN frame is known here */
/* so try to get CAN frames and ErrorFrames and convert them */
/* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */
found = 0; /* found valid CAN frame ? */
if (base == 'h') { /* check for CAN frames with hexadecimal values */
if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %x %x %x %x %x %x %x %x",
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
tmp1, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]
) == dlc + 6 ) {
found = 1;
get_can_id(&cf, tmp1, 16);
}
} else { /* check for CAN frames with decimal values */
if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %d %d %d %d %d %d %d %d",
&read_tv.tv_sec, &read_tv.tv_usec, &interface,
tmp1, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]
) == dlc + 6 ) {
found = 1;
get_can_id(&cf, tmp1, 10);
}
}
if (found) {
if (rtr == 'r')
cf.can_id |= CAN_RTR_FLAG;
cf.can_dlc = dlc & 0x0FU;
for (i=0; i<dlc; i++)
cf.data[i] = data[i] & 0xFFU;
calc_tv(&tv, &read_tv, &date_tv, timestamps, dplace);
prframe(outfile, &tv, interface, &cf);
fflush(outfile);
continue;
}
/* check for ErrorFrames */
if (sscanf(buf, "%ld.%ld %d %s",
&read_tv.tv_sec, &read_tv.tv_usec,
&interface, tmp1) == 4) {
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
memset(&cf, 0, sizeof(cf));
/* do not know more than 'Error' */
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
cf.can_dlc = CAN_ERR_DLC;
calc_tv(&tv, &read_tv, &date_tv, timestamps, dplace);
prframe(outfile, &tv, interface, &cf);
fflush(outfile);
}
/* check classic CAN format or the CANFD tag which can take both types */
if (sscanf(buf, "%lu.%lu %s ", &tmp_tv.tv_sec, &tmp_tv.tv_usec, tmp1) == 3){
if (!strncmp(tmp1, "CANFD", 5))
eval_canfd(buf, &date_tv, timestamps, dplace, outfile);
else
eval_can(buf, &date_tv, timestamps, base, dplace, outfile);
}
}
fclose(outfile);
+17 -14
View File
@@ -108,20 +108,21 @@
*
*/
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <linux/can.h>
#include <linux/can/bcm.h>
@@ -135,7 +136,7 @@ void childdied(int i)
wait(NULL);
}
int main(int argc, char **argv)
int main(void)
{
int sl, sa, sc;
@@ -180,8 +181,12 @@ int main(int argc, char **argv)
saddr.sin_port = htons(PORT);
while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
struct timespec f = {
.tv_nsec = 100 * 1000 * 1000,
};
printf(".");fflush(NULL);
usleep(100000);
nanosleep(&f, NULL);
}
if (listen(sl,3) != 0) {
@@ -192,11 +197,9 @@ int main(int argc, char **argv)
while (1) {
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
if (sa > 0 ){
if (fork())
close(sa);
else
if (!fork())
break;
close(sa);
}
else {
if (errno != EINTR) {
+261 -74
View File
@@ -2,7 +2,7 @@
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
*
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
* Copyright (C) 2016 Marc Kleine-Budde <mkl@pengutronix.de>
* Copyright (C) 2016, 2021 Marc Kleine-Budde <mkl@pengutronix.de>
*
* Derived from:
* can_baud.c - CAN baudrate calculation
@@ -18,6 +18,7 @@
#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
@@ -25,8 +26,19 @@
#include <stdlib.h>
#include <string.h>
#include <linux/types.h>
#include <linux/can/netlink.h>
#include <linux/types.h>
enum {
OPT_TQ = UCHAR_MAX + 1,
OPT_PROP_SEG,
OPT_PHASE_SEG1,
OPT_PHASE_SEG2,
OPT_SJW,
OPT_BRP,
OPT_TSEG1,
OPT_TSEG2,
};
/* imported from kernel */
@@ -131,17 +143,26 @@ static inline void *netdev_priv(const struct net_device *dev)
static void print_usage(char *cmd)
{
printf("%s - calculate CAN bit timing parameters.\n", cmd);
printf("Usage: %s [options] [<CAN-contoller-name>]\n"
"\tOptions:\n"
"\t-q : don't print header line\n"
"\t-l : list all support CAN controller names\n"
"\t-b <bitrate> : bit-rate in bits/sec\n"
"\t-s <samp_pt> : sample-point in one-tenth of a percent\n"
"Options:\n"
"\t-q don't print header line\n"
"\t-l list all support CAN controller names\n"
"\t-b <bitrate> bit-rate in bits/sec\n"
"\t-s <samp_pt> sample-point in one-tenth of a percent\n"
"\t or 0 for CIA recommended sample points\n"
"\t-c <clock> : real CAN system clock in Hz\n",
"\t-c <clock> real CAN system clock in Hz\n"
"\n"
"Or supply low level bit timing parameters to decode them:\n"
"\n"
"\t--prop-seg Propagation segment in TQs\n"
"\t--phase-seg1 Phase buffer segment 1 in TQs\n"
"\t--phase-seg2 Phase buffer segment 2 in TQs\n"
"\t--sjw Synchronisation jump width in TQs\n"
"\t--brp Bit-rate prescaler\n"
"\t--tseg1 Time segment 1 = prop-seg + phase-seg1\n"
"\t--tseg2 Time segment 2 = phase_seg2\n",
cmd);
exit(EXIT_FAILURE);
}
static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
@@ -201,6 +222,19 @@ static void printf_btr_mcp251x(struct can_bittiming *bt, bool hdr)
}
}
static void printf_btr_mcp251xfd(struct can_bittiming *bt, bool hdr)
{
if (hdr) {
printf("NBTCFG");
} else {
uint32_t nbtcfg = ((bt->brp - 1) << 24) |
((bt->prop_seg + bt->phase_seg1 - 1) << 16) |
((bt->phase_seg2 - 1) << 8) |
(bt->sjw - 1);
printf("0x%08x", nbtcfg);
}
}
static void printf_btr_ti_hecc(struct can_bittiming *bt, bool hdr)
{
if (hdr) {
@@ -276,7 +310,6 @@ static struct calc_bittiming_const can_calc_consts[] = {
{ .clk = 66660000, .name = "mpc5121", },
{ .clk = 66666666, .name = "mpc5121" },
},
.printf_btr = printf_btr_sja1000,
}, {
.bittiming_const = {
.name = "at91",
@@ -329,10 +362,29 @@ static struct calc_bittiming_const can_calc_consts[] = {
.brp_inc = 1,
},
.ref_clk = {
{ .clk = 8000000, },
{ .clk = 16000000, },
/* The mcp251x uses half of the external OSC clock as the base clock */
{ .clk = 8000000 / 2, .name = "8 MHz OSC" },
{ .clk = 16000000 / 2, .name = "16 MHz OSC" },
{ .clk = 20000000 / 2, .name = "20 MHz OSC" },
},
.printf_btr = printf_btr_mcp251x,
}, {
.bittiming_const = {
.name = "mcp251xfd",
.tseg1_min = 2,
.tseg1_max = 256,
.tseg2_min = 1,
.tseg2_max = 128,
.sjw_max = 128,
.brp_min = 1,
.brp_max = 256,
.brp_inc = 1,
},
.ref_clk = {
{ .clk = 20000000, },
{ .clk = 40000000, },
},
.printf_btr = printf_btr_mcp251xfd,
}, {
.bittiming_const = {
.name = "ti_hecc",
@@ -444,7 +496,7 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
unsigned int spt_nominal; /* nominal sample point */
unsigned int best_tseg = 0; /* current best value for tseg */
unsigned int best_brp = 0; /* current best value for brp */
unsigned int brp, tsegall, tseg, tseg1, tseg2;
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
u64 v64;
/* Use CiA recommended sample points */
@@ -540,6 +592,46 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
return 0;
}
static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{
struct can_priv *priv = netdev_priv(dev);
int tseg1, alltseg;
u64 brp64, v64;
tseg1 = bt->prop_seg + bt->phase_seg1;
if (!bt->sjw)
bt->sjw = 1;
if (bt->sjw > btc->sjw_max ||
tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
return -ERANGE;
if (!bt->brp) {
brp64 = (u64)priv->clock.freq * (u64)bt->tq;
if (btc->brp_inc > 1)
do_div(brp64, btc->brp_inc);
brp64 += 500000000UL - 1;
do_div(brp64, 1000000000UL); /* the practicable BRP */
if (btc->brp_inc > 1)
brp64 *= btc->brp_inc;
bt->brp = brp64;
}
v64 = bt->brp * 1000 * 1000 * 1000;
do_div(v64, priv->clock.freq);
bt->tq = v64;
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
return -EINVAL;
alltseg = CAN_CALC_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2;
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
bt->sample_point = ((CAN_CALC_SYNC_SEG + tseg1) * 1000) / alltseg;
return 0;
}
static __u32 get_cia_sample_point(__u32 bitrate)
{
__u32 sampl_pt;
@@ -555,6 +647,7 @@ static __u32 get_cia_sample_point(__u32 bitrate)
}
static void print_bit_timing(const struct calc_bittiming_const *btc,
const struct can_bittiming *ref_bt,
const struct calc_ref_clk *ref_clk,
unsigned int bitrate_nominal,
unsigned int spt_nominal,
@@ -579,13 +672,23 @@ static void print_bit_timing(const struct calc_bittiming_const *btc,
ref_clk->name ? ")" : "",
ref_clk->clk / 1000000.0);
btc->printf_btr(&bt, true);
if (btc->printf_btr)
btc->printf_btr(&bt, true);
printf("\n");
}
if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
printf("%7d ***bitrate not possible***\n", bitrate_nominal);
return;
if (ref_bt) {
bt = *ref_bt;
if (can_fixup_bittiming(&dev, &bt, &btc->bittiming_const)) {
printf("%7d ***parameters exceed controller's range***\n", bitrate_nominal);
return;
}
} else {
if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
printf("%7d ***bitrate not possible***\n", bitrate_nominal);
return;
}
}
/* get nominal sample point */
@@ -595,23 +698,33 @@ static void print_bit_timing(const struct calc_bittiming_const *btc,
rate_error = abs(bitrate_nominal - bt.bitrate);
spt_error = abs(spt_nominal - bt.sample_point);
printf("%7d "
"%6d %3d %4d %4d "
"%3d %3d "
"%7d %4.1f%% "
"%4.1f%% %4.1f%% %4.1f%% ",
printf("%7d " /* Bitrate */
"%6d %3d %4d %4d " /* TQ[ns], PrS, PhS1, PhS2 */
"%3d %3d " /* SJW, BRP */
"%7d ", /* real Bitrate */
bitrate_nominal,
bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2,
bt.sjw, bt.brp,
bt.bitrate);
bt.bitrate,
100.0 * rate_error / bitrate_nominal,
if (100.0 * rate_error / bitrate_nominal > 99.9)
printf("≥100%% ");
else
printf("%4.1f%% ",
100.0 * rate_error / bitrate_nominal);
printf("%4.1f%% %4.1f%% ", /* nom SampP, real SampP */
spt_nominal / 10.0,
bt.sample_point / 10.0,
100.0 * spt_error / spt_nominal);
bt.sample_point / 10.0);
btc->printf_btr(&bt, false);
if (100.0 * spt_error / spt_nominal > 99.9)
printf("≥100%% ");
else
printf("%4.1f%% ", /* SampP Error */
100.0 * spt_error / spt_nominal);
if (btc->printf_btr)
btc->printf_btr(&bt, false);
printf("\n");
}
@@ -623,22 +736,81 @@ static void do_list(void)
printf("%s\n", can_calc_consts[i].bittiming_const.name);
}
static void do_calc(const char *name,
const struct can_bittiming *opt_ref_bt,
__u32 bitrate_nominal, unsigned int spt_nominal,
struct calc_ref_clk *opt_ref_clk, bool quiet)
{
const struct calc_bittiming_const *btc;
const struct calc_ref_clk *ref_clk;
unsigned int i, j, k;
bool found = false;
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
if (name &&
strcmp(can_calc_consts[i].bittiming_const.name, name) != 0)
continue;
found = true;
btc = &can_calc_consts[i];
for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) {
if (opt_ref_clk)
ref_clk = opt_ref_clk;
else
ref_clk = &btc->ref_clk[j];
if (!ref_clk->clk)
break;
if (bitrate_nominal) {
print_bit_timing(btc, opt_ref_bt, ref_clk, bitrate_nominal,
spt_nominal, quiet);
} else {
for (k = 0; k < ARRAY_SIZE(common_bitrates); k++)
print_bit_timing(btc, opt_ref_bt, ref_clk,
common_bitrates[k],
spt_nominal, k);
}
printf("\n");
if (opt_ref_clk)
break;
}
}
if (!found) {
printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
do_list();
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
__u32 bitrate_nominal = 0;
unsigned int spt_nominal = 0;
struct calc_ref_clk opt_ref_clk = {
.name = "cmd-line",
};
const struct calc_ref_clk *ref_clk;
unsigned int spt_nominal = 0;
bool quiet = false, list = false, found = false;
char *name = NULL;
unsigned int i, j, k;
struct can_bittiming bt = { 0 };
bool quiet = false, list = false;
const char *name = NULL;
int opt;
const struct calc_bittiming_const *btc;
const struct option long_options[] = {
{ "tq", required_argument, 0, OPT_TQ, },
{ "prop-seg", required_argument, 0, OPT_PROP_SEG, },
{ "phase-seg1", required_argument, 0, OPT_PHASE_SEG1, },
{ "phase-seg2", required_argument, 0, OPT_PHASE_SEG2, },
{ "sjw", required_argument, 0, OPT_SJW, },
{ "brp", required_argument, 0, OPT_BRP, },
{ "tseg1", required_argument, 0, OPT_TSEG1, },
{ "tseg2", required_argument, 0, OPT_TSEG2, },
{ 0, 0, 0, 0 },
};
while ((opt = getopt(argc, argv, "b:c:lqs:")) != -1) {
while ((opt = getopt_long(argc, argv, "b:c:lqs:?", long_options, NULL)) != -1) {
switch (opt) {
case 'b':
bitrate_nominal = atoi(optarg);
@@ -660,14 +832,59 @@ int main(int argc, char *argv[])
spt_nominal = strtoul(optarg, NULL, 10);
break;
case '?':
print_usage(basename(argv[0]));
exit(EXIT_SUCCESS);
break;
case OPT_TQ:
bt.tq = strtoul(optarg, NULL, 10);
break;
case OPT_PROP_SEG:
bt.prop_seg = strtoul(optarg, NULL, 10);
break;
case OPT_PHASE_SEG1:
bt.phase_seg1 = strtoul(optarg, NULL, 10);
break;
case OPT_PHASE_SEG2:
bt.phase_seg2 = strtoul(optarg, NULL, 10);
break;
case OPT_SJW:
bt.sjw = strtoul(optarg, NULL, 10);
break;
case OPT_BRP:
bt.brp = strtoul(optarg, NULL, 10);
break;
case OPT_TSEG1: {
__u32 tseg1;
tseg1 = strtoul(optarg, NULL, 10);
bt.prop_seg = tseg1 / 2;
bt.phase_seg1 = tseg1 - bt.prop_seg;
break;
}
case OPT_TSEG2:
bt.phase_seg2 = strtoul(optarg, NULL, 10);
break;
default:
print_usage(argv[0]);
print_usage(basename(argv[0]));
exit(EXIT_FAILURE);
break;
}
}
if (argc > optind + 1)
if (argc > optind + 1) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
if (argc == optind + 1)
name = argv[optind];
@@ -677,46 +894,16 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100))
if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100)) {
print_usage(argv[0]);
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
if (name && strcmp(can_calc_consts[i].bittiming_const.name, name))
continue;
found = true;
btc = &can_calc_consts[i];
for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) {
if (opt_ref_clk.clk)
ref_clk = &opt_ref_clk;
else
ref_clk = &btc->ref_clk[j];
if (!ref_clk->clk)
break;
if (bitrate_nominal) {
print_bit_timing(btc, ref_clk, bitrate_nominal,
spt_nominal, quiet);
} else {
for (k = 0; k < ARRAY_SIZE(common_bitrates); k++)
print_bit_timing(btc, ref_clk,
common_bitrates[k],
spt_nominal, k);
}
printf("\n");
if (opt_ref_clk.clk)
break;
}
}
if (!found) {
printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
do_list();
exit(EXIT_FAILURE);
}
do_calc(name,
bt.prop_seg ? &bt: NULL,
bitrate_nominal, spt_nominal,
opt_ref_clk.clk ? &opt_ref_clk : NULL,
quiet);
exit(EXIT_SUCCESS);
}
+180
View File
@@ -0,0 +1,180 @@
# can-j1939 kernel module installation #
### Problem
You already have **can0** or **vcan0** up and working, **can-utils** downloaded and compiled to **~/can/can-utils** and you can send and receive frames without problems. However, when you want to bring up **can-j1939** you get error like this:
```bash
avra@vm-debian:~/can/can-utils$ sudo modprobe can-j1939
modprobe: FATAL: Module can-j1939 not found in directory /lib/modules/5.7.0.0.bpo.2-amd64
```
and also this:
```bash
avra@vm-debian:~/can/can-utils$ testj1939
testj1939: socket(j1939): Protocol not supported
```
### Solution
Above errors mean that **can-j1939** was not enabled in your kernel and you need to compile it manually. There are several ways to do it. Any Linux kernel since 5.4 has **can-j1939** module, but you will probably want to install fresher version, which leads to downloading kernel sources, enabling **can-j1939** module, recompiling kernel and installing it. I will be using Debian 10.5 x64 (buster testing) virtual machine.
#### 1. Download kernel source ####
We will download Debian patched kernel 5.8. First update your sources
```
avra@vm-debian:~$ sudo apt update
```
and then look at available Debian patched kernel source packages
```
avra@vm-debian:~$ apt-cache search linux-source
linux-source-4.19 - Linux kernel source for version 4.19 with Debian patches
linux-source - Linux kernel source (meta-package)
linux-source-5.4 - Linux kernel source for version 5.4 with Debian patches
linux-source-5.5 - Linux kernel source for version 5.5 with Debian patches
linux-source-5.6 - Linux kernel source for version 5.6 with Debian patches
linux-source-5.7 - Linux kernel source for version 5.7 with Debian patches
linux-source-5.8 - Linux kernel source for version 5.8 with Debian patches
```
If kernel 5.8 does not show in your linux-sources list (it shows above in mine since I have already upgraded stock 4.19 kernel to backported 5.7), then you will need to add backports to your sources list. It is best to do it like this
```
echo 'deb http://deb.debian.org/debian buster-backports main contrib' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list
```
Alternatively, or in case you have problems with installation of some packages, or you just want to have everything in a single list, here is what my **/etc/apt/sources.list** looks like (you will need to append at least last line to yours)
```
deb http://security.debian.org/debian-security buster/updates main contrib
deb-src http://security.debian.org/debian-security buster/updates main contrib
deb http://deb.debian.org/debian/ buster main contrib non-free
deb-src http://deb.debian.org/debian/ buster main contrib non-free
deb http://deb.debian.org/debian buster-backports main contrib
```
After adding backports in one way or another, try **sudo apt update** again, and after that **apt-cache search linux-source** should show kernel 5.8 in the list, so you can install it's source package
```
sudo apt install linux-source-5.8
```
and unpack it
```
avra@vm-debian:~$ cd /usr/src
avra@vm-debian:/usr/src$ sudo tar -xaf linux-source-5.8.tar.xz
avra@vm-debian:/usr/src$ cd linux-source-5.8
```
#### 2. Add can-j1939 module to kernel ####
First we need some packages for **menuconfig**
```
sudo apt-get install libncurses5 libncurses5-dev
```
copy and use our old configuration to run **menuconfig**
```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo cp /boot/config-$(uname -r) .config
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make menuconfig
```
where we enable SAE J1939 kernel module as shown
```
- Networking Support
- Can bus subsystem support
- <M> SAE J1939
```
Now edit **/usr/src/linux-source-5.8/.config**, find CONFIG_SYSTEM_TRUSTED_KEYS, change it as following
```
CONFIG_SYSTEM_TRUSTED_KEYS=""
```
and save the file.
#### 3. Compile and install kernel and modules
We will have to download necessary packages
```
sudo apt install build-essential libssl-dev libelf-dev bison flex
```
compile kernel (using threads to make it faster)
```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make -j $(nproc)
```
install
```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make modules_install
avra@vm-debian:/usr/src/linux-source-5.8$ sudo make install
```
and update grub
```
avra@vm-debian:/usr/src/linux-source-5.8$ sudo update-grub
avra@vm-debian:/usr/src/linux-source-5.8$ sudo reboot
```
Check if installation is correct with
```
sudo modprobe can-j1939
```
and if you get no error then you can enjoy **can-j1939**. If you get some error then you might check if this alternative command works:
```
sudo insmod /lib/modules/5.8.10/kernel/net/can/j1939/can-j1939.ko
```
If it does then all you need to do is
```
sudo depmod -av
```
reboot once, and **modprobe** command from the above should finally work.
#### 4. Install headers if needed
You might have a problem with headers not being updated. To check that open file **/usr/include/linux/can.h** with
```
nano /usr/include/linux/can.h
```
If in the struct **sockaddr_can** you dont see **j1939**, then header files did not upgrade and you need to do it manually
```
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can.h /usr/include/linux/can.h
sudo cp /usr/src/linux-source-5.8/include/uapi/linux/can/j1939.h /usr/include/linux/can/
```
That is the minimum for compiling some **J1939** C code, but you might want to upgrade other header files as well. That's up to you. Enjoy!
+1 -1
View File
@@ -44,7 +44,7 @@ You should have this output in terminal 1
40 02300: 01 23
This means, from NAME 0, SA 40, PGN 02300 was received,
with 2 databytes, *01* & *02*.
with 2 databytes, *01* & *23*.
now emit this CAN message:
+21 -19
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* canbusload.c
* canbusload.c - monitor CAN bus load
*
* Copyright (c) 2002-2008 Volkswagen Group Electronic Research
* All rights reserved.
@@ -42,21 +42,21 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
@@ -91,14 +91,16 @@ static char *prg;
void print_usage(char *prg)
{
fprintf(stderr, "%s - monitor CAN bus load.\n", prg);
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
fprintf(stderr, "Options: -t (show current time on the first line)\n");
fprintf(stderr, " -c (colorize lines)\n");
fprintf(stderr, " -b (show bargraph in %d%% resolution)\n", PERCENTRES);
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -t (show current time on the first line)\n");
fprintf(stderr, " -c (colorize lines)\n");
fprintf(stderr, " -b (show bargraph in %d%% resolution)\n", PERCENTRES);
fprintf(stderr, " -r (redraw the terminal - similar to top)\n");
fprintf(stderr, " -i (ignore bitstuffing in bandwidth calculation)\n");
fprintf(stderr, " -e (exact calculation of stuffed bits)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXSOCK);
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>\n\n");
@@ -107,7 +109,7 @@ void print_usage(char *prg)
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
fprintf(stderr, "For each given interface the data is presented in one line which contains:\n\n");
fprintf(stderr, "(interface) (received CAN frames) (used bits total) (used bits for payload)\n");
fprintf(stderr, "\nExample:\n");
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000 can2@500000 can3@500000 -r -t -b -c\n\n");
fprintf(stderr, "%s 2014-02-01 21:13:16 (worst case bitstuffing)\n", prg);
fprintf(stderr, " can0@100000 805 74491 36656 74%% |XXXXXXXXXXXXXX......|\n");
@@ -298,7 +300,7 @@ int main(int argc, char **argv)
ptr = argv[optind+i];
nbytes = strlen(ptr);
if (nbytes >= IFNAMSIZ+sizeof("@1000000")+1) {
if (nbytes >= (int)(IFNAMSIZ+sizeof("@1000000")+1)) {
printf("name of CAN device '%s' is too long!\n", ptr);
return 1;
}
@@ -322,7 +324,7 @@ int main(int argc, char **argv)
nbytes = nptr - ptr; /* interface name is up the first '@' */
if (nbytes >= IFNAMSIZ) {
if (nbytes >= (int)IFNAMSIZ) {
printf("name of CAN device '%s' is too long!\n", ptr);
return 1;
}
@@ -394,7 +396,7 @@ int main(int argc, char **argv)
return 1;
}
if (nbytes < sizeof(struct can_frame)) {
if (nbytes < (int)sizeof(struct can_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
+323 -275
View File
@@ -42,23 +42,24 @@
*
*/
#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <libgen.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
@@ -72,9 +73,10 @@
#endif
/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
#define SOF_TIMESTAMPING_SOFTWARE (1 << 4)
#define SOF_TIMESTAMPING_RX_SOFTWARE (1 << 3)
#define SOF_TIMESTAMPING_RAW_HARDWARE (1 << 6)
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
@@ -85,40 +87,47 @@
#define SILENT_INI 42 /* detect user setting on commandline */
#define SILENT_OFF 0 /* no silent mode */
#define SILENT_ANI 1 /* silent mode with animation */
#define SILENT_ON 2 /* silent mode (completely silent) */
#define SILENT_ON 2 /* silent mode (completely silent) */
#define BOLD ATTBOLD
#define RED ATTBOLD FGRED
#define GREEN ATTBOLD FGGREEN
#define YELLOW ATTBOLD FGYELLOW
#define BLUE ATTBOLD FGBLUE
#define MAGENTA ATTBOLD FGMAGENTA
#define CYAN ATTBOLD FGCYAN
#define BOLD ATTBOLD
#define RED (ATTBOLD FGRED)
#define GREEN (ATTBOLD FGGREEN)
#define YELLOW (ATTBOLD FGYELLOW)
#define BLUE (ATTBOLD FGBLUE)
#define MAGENTA (ATTBOLD FGMAGENTA)
#define CYAN (ATTBOLD FGCYAN)
const char col_on [MAXCOL][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
const char col_off [] = ATTRESET;
static const char col_on[MAXCOL][19] = { BLUE, RED, GREEN, BOLD, MAGENTA, CYAN };
static const char col_off[] = ATTRESET;
struct if_info { /* bundled information per open socket */
int s; /* socket */
char *cmdlinename;
__u32 dropcnt;
__u32 last_dropcnt;
};
static struct if_info sock_info[MAXSOCK];
static char *cmdlinename[MAXSOCK];
static __u32 dropcnt[MAXSOCK];
static __u32 last_dropcnt[MAXSOCK];
static char devname[MAXIFNAMES][IFNAMSIZ+1];
static int dindex[MAXIFNAMES];
static int max_devname_len; /* to prevent frazzled device name output */
const int canfd_on = 1;
static int dindex[MAXIFNAMES];
static int max_devname_len; /* to prevent frazzled device name output */
static const int canfd_on = 1;
#define MAXANI 4
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
extern int optind, opterr, optopt;
static volatile int running = 1;
void print_usage(char *prg)
static void print_usage(char *prg)
{
fprintf(stderr, "%s - dump CAN bus traffic.\n", prg);
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
fprintf(stderr, "Options: -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -H (read hardware timestamps instead of system timestamps)\n");
fprintf(stderr, " -c (increment color mode level)\n");
fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n");
@@ -132,41 +141,44 @@ void print_usage(char *prg)
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
fprintf(stderr, " -d (monitor dropped CAN frames)\n");
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n");
fprintf(stderr, " -8 (display raw DLC values in {} for Classical CAN)\n");
fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n");
fprintf(stderr, " -T <msecs> (terminate after <msecs> without any reception)\n");
fprintf(stderr, " -T <msecs> (terminate after <msecs> if no frames were received)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
fprintf(stderr, "on the commandline in the form: <ifname>[,filter]*\n");
fprintf(stderr, "\nComma separated filters can be specified for each given CAN interface:\n");
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
fprintf(stderr, " #<error_mask> (set error frame filter, see include/linux/can/error.h)\n");
fprintf(stderr, " [j|J] (join the given CAN filters - logical AND semantic)\n");
fprintf(stderr, "\nFilters:\n");
fprintf(stderr, " Comma separated filters can be specified for each given CAN interface:\n");
fprintf(stderr, " <can_id>:<can_mask>\n (matches when <received_can_id> & mask == can_id & mask)\n");
fprintf(stderr, " <can_id>~<can_mask>\n (matches when <received_can_id> & mask != can_id & mask)\n");
fprintf(stderr, " #<error_mask>\n (set error frame filter, see include/linux/can/error.h)\n");
fprintf(stderr, " [j|J]\n (join the given CAN filters - logical AND semantic)\n");
fprintf(stderr, "\nCAN IDs, masks and data content are given and expected in hexadecimal values.\n");
fprintf(stderr, "When the can_id is 8 digits long the CAN_EFF_FLAG is set for 29 bit EFF format.\n");
fprintf(stderr, "Without any given filter all data frames are received ('0:0' default filter).\n");
fprintf(stderr, "\nUse interface name '%s' to receive from all CAN interfaces.\n", ANYDEV);
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n", prg);
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF (log only error frames but no(!) data frames)\n", prg);
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF (log error frames and also all data frames)\n", prg);
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF (match only for extended CAN ID 12345678)\n", prg);
fprintf(stderr, "%s vcan2,123:7FF (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
fprintf(stderr, "%s vcan2,123:C00007FF (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n\n", prg);
fprintf(stderr, "%s -l any,0~0,#FFFFFFFF\n (log only error frames but no(!) data frames)\n", prg);
fprintf(stderr, "%s -l any,0:0,#FFFFFFFF\n (log error frames and also all data frames)\n", prg);
fprintf(stderr, "%s vcan2,12345678:DFFFFFFF\n (match only for extended CAN ID 12345678)\n", prg);
fprintf(stderr, "%s vcan2,123:7FF\n (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
fprintf(stderr, "%s vcan2,123:C00007FF\n (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
fprintf(stderr, "\n");
}
void sigterm(int signo)
static void sigterm(int signo)
{
running = 0;
}
int idx2dindex(int ifidx, int socket) {
static int idx2dindex(int ifidx, int socket)
{
int i;
struct ifreq ifr;
for (i=0; i < MAXIFNAMES; i++) {
for (i = 0; i < MAXIFNAMES; i++) {
if (dindex[i] == ifidx)
return i;
}
@@ -174,7 +186,7 @@ int idx2dindex(int ifidx, int socket) {
/* create new interface index cache entry */
/* remove index cache zombies first */
for (i=0; i < MAXIFNAMES; i++) {
for (i = 0; i < MAXIFNAMES; i++) {
if (dindex[i]) {
ifr.ifr_ifindex = dindex[i];
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
@@ -182,13 +194,13 @@ int idx2dindex(int ifidx, int socket) {
}
}
for (i=0; i < MAXIFNAMES; i++)
for (i = 0; i < MAXIFNAMES; i++)
if (!dindex[i]) /* free entry */
break;
if (i == MAXIFNAMES) {
fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
MAXIFNAMES);
MAXIFNAMES);
exit(1);
}
@@ -198,7 +210,7 @@ int idx2dindex(int ifidx, int socket) {
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFNAME");
if (max_devname_len < strlen(ifr.ifr_name))
if (max_devname_len < (int)strlen(ifr.ifr_name))
max_devname_len = strlen(ifr.ifr_name);
strcpy(devname[i], ifr.ifr_name);
@@ -210,11 +222,69 @@ int idx2dindex(int ifidx, int socket) {
return i;
}
static inline void sprint_timestamp(const char timestamp, const struct timeval *tv,
struct timeval *const last_tv, char *ts_buffer)
{
switch (timestamp) {
case 'a': /* absolute with timestamp */
sprintf(ts_buffer, "(%010lu.%06lu) ", tv->tv_sec, tv->tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv->tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
sprintf(ts_buffer, "(%s.%06lu) ", timestring, tv->tv_usec);
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
if (last_tv->tv_sec == 0) /* first init */
*last_tv = *tv;
diff.tv_sec = tv->tv_sec - last_tv->tv_sec;
diff.tv_usec = tv->tv_usec - last_tv->tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
sprintf(ts_buffer, "(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
*last_tv = *tv; /* update for delta calculation */
}
break;
default: /* no timestamp output */
break;
}
}
static inline void print_timestamp(const char timestamp, const struct timeval *tv,
struct timeval *const last_tv)
{
static char buffer[TIMESTAMPSZ];
sprint_timestamp(timestamp, tv, last_tv, buffer);
printf("%s", buffer);
}
int main(int argc, char **argv)
{
fd_set rdfs;
int s[MAXSOCK];
int fd_epoll;
struct epoll_event events_pending[MAXSOCK];
struct epoll_event event_setup = {
.events = EPOLLIN, /* prepare the common part */
};
unsigned char timestamp = 0;
unsigned char logtimestamp = 'a';
unsigned char hwtimestamp = 0;
unsigned char down_causes_exit = 1;
unsigned char dropmonitor = 0;
@@ -227,12 +297,12 @@ int main(int argc, char **argv)
unsigned char logfrmt = 0;
int count = 0;
int rcvbuf_size = 0;
int opt, ret;
int opt, num_events;
int currmax, numfilter;
int join_filter;
char *ptr, *nptr;
struct sockaddr_can addr;
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3 * sizeof(struct timespec) + sizeof(__u32))];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
@@ -242,26 +312,30 @@ int main(int argc, char **argv)
int nbytes, i, maxdlen;
struct ifreq ifr;
struct timeval tv, last_tv;
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
int timeout_ms = -1; /* default to no timeout */
FILE *logfile = NULL;
signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
last_tv.tv_sec = 0;
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:heT:?")) != -1) {
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:he8T:?")) != -1) {
switch (opt) {
case 't':
timestamp = optarg[0];
logtimestamp = optarg[0];
if ((timestamp != 'a') && (timestamp != 'A') &&
(timestamp != 'd') && (timestamp != 'z')) {
fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
basename(argv[0]), optarg[0]);
basename(argv[0]), optarg[0]);
timestamp = 0;
}
if ((logtimestamp != 'a') && (logtimestamp != 'z')) {
logtimestamp = 'a';
}
break;
case 'H':
@@ -288,6 +362,10 @@ int main(int argc, char **argv)
view |= CANLIB_VIEW_ERROR;
break;
case '8':
view |= CANLIB_VIEW_LEN8_DLC;
break;
case 's':
silent = atoi(optarg);
if (silent > SILENT_ON) {
@@ -334,14 +412,11 @@ int main(int argc, char **argv)
case 'T':
errno = 0;
timeout_config.tv_usec = strtol(optarg, NULL, 0);
timeout_ms = strtol(optarg, NULL, 0);
if (errno != 0) {
print_usage(basename(argv[0]));
exit(1);
}
timeout_config.tv_sec = timeout_config.tv_usec / 1000;
timeout_config.tv_usec = (timeout_config.tv_usec % 1000) * 1000;
timeout_current = &timeout;
break;
default:
print_usage(basename(argv[0]));
@@ -354,9 +429,9 @@ int main(int argc, char **argv)
print_usage(basename(argv[0]));
exit(0);
}
if (logfrmt && view) {
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP/RAWDLC options!\n");
exit(0);
}
@@ -375,8 +450,14 @@ int main(int argc, char **argv)
return 1;
}
for (i=0; i < currmax; i++) {
fd_epoll = epoll_create(1);
if (fd_epoll < 0) {
perror("epoll_create");
return 1;
}
for (i = 0; i < currmax; i++) {
struct if_info* obj = &sock_info[i];
ptr = argv[optind+i];
nptr = strchr(ptr, ',');
@@ -384,13 +465,19 @@ int main(int argc, char **argv)
printf("open %d '%s'.\n", i, ptr);
#endif
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s[i] < 0) {
obj->s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (obj->s < 0) {
perror("socket");
return 1;
}
cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
event_setup.data.ptr = obj; /* remember the instance as private data */
if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, obj->s, &event_setup)) {
perror("failed to add socket to epoll");
return 1;
}
obj->cmdlinename = ptr; /* save pointer to cmdline name of this socket */
if (nptr)
nbytes = nptr - ptr; /* interface name is up the first ',' */
@@ -414,8 +501,8 @@ int main(int argc, char **argv)
printf("using interface name '%s'.\n", ifr.ifr_name);
#endif
if (strcmp(ANYDEV, ifr.ifr_name)) {
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
if (strcmp(ANYDEV, ifr.ifr_name) != 0) {
if (ioctl(obj->s, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
exit(1);
}
@@ -448,44 +535,44 @@ int main(int argc, char **argv)
while (nptr) {
ptr = nptr+1; /* hop behind the ',' */
ptr = nptr + 1; /* hop behind the ',' */
nptr = strchr(ptr, ','); /* update exit condition */
if (sscanf(ptr, "%x:%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr+8) == ':')
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr + 8) == ':')
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
numfilter++;
} else if (sscanf(ptr, "%x~%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_id |= CAN_INV_FILTER;
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr+8) == '~')
rfilter[numfilter].can_id |= CAN_INV_FILTER;
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
if (*(ptr + 8) == '~')
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
numfilter++;
} else if (*ptr == 'j' || *ptr == 'J') {
join_filter = 1;
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
return 1;
}
}
if (err_mask)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
&err_mask, sizeof(err_mask));
if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
if (join_filter && setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
&join_filter, sizeof(join_filter)) < 0) {
perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
return 1;
}
if (numfilter)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FILTER,
rfilter, numfilter * sizeof(struct can_filter));
free(rfilter);
@@ -493,26 +580,25 @@ int main(int argc, char **argv)
} /* if (nptr) */
/* try to switch the socket into CAN FD mode */
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
if (rcvbuf_size) {
int curr_rcvbuf_size;
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUFFORCE,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
#ifdef DEBUG
printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
#endif
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
perror("setsockopt SO_RCVBUF");
return 1;
}
if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
if (getsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
&curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
perror("getsockopt SO_RCVBUF");
return 1;
@@ -520,28 +606,27 @@ int main(int argc, char **argv)
/* Only print a warning the first time we detect the adjustment */
/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
if (!i && curr_rcvbuf_size < rcvbuf_size*2)
if (!i && curr_rcvbuf_size < rcvbuf_size * 2)
fprintf(stderr, "The socket receive buffer size was "
"adjusted due to /proc/sys/net/core/rmem_max.\n");
}
}
if (timestamp || log || logfrmt) {
if (hwtimestamp) {
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
SOF_TIMESTAMPING_RX_SOFTWARE | \
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_RAW_HARDWARE);
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
&timestamping_flags, sizeof(timestamping_flags)) < 0) {
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMPING,
&timestamping_flags, sizeof(timestamping_flags)) < 0) {
perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
return 1;
}
} else {
const int timestamp_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMP,
&timestamp_on, sizeof(timestamp_on)) < 0) {
perror("setsockopt SO_TIMESTAMP");
return 1;
@@ -550,17 +635,16 @@ int main(int argc, char **argv)
}
if (dropmonitor) {
const int dropmonitor_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
if (setsockopt(obj->s, SOL_SOCKET, SO_RXQ_OVFL,
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
return 1;
}
}
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (bind(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
@@ -606,196 +690,160 @@ int main(int argc, char **argv)
msg.msg_control = &ctrlmsg;
while (running) {
FD_ZERO(&rdfs);
for (i=0; i<currmax; i++)
FD_SET(s[i], &rdfs);
if (timeout_current)
*timeout_current = timeout_config;
if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
//perror("select");
running = 0;
num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms);
if (num_events == -1) {
if (errno != EINTR)
running = 0;
continue;
}
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
for (i = 0; i < num_events; i++) { /* check waiting CAN RAW sockets */
struct if_info* obj = events_pending[i].data.ptr;
int idx;
char *extra_info = "";
if (FD_ISSET(s[i], &rdfs)) {
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
int idx;
nbytes = recvmsg(obj->s, &msg, 0);
idx = idx2dindex(addr.can_ifindex, obj->s);
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
nbytes = recvmsg(s[i], &msg, 0);
idx = idx2dindex(addr.can_ifindex, s[i]);
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
}
perror("read");
return 1;
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
}
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
maxdlen = CANFD_MAX_DLEN;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
if (count && (--count == 0))
running = 0;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/*
* stamp[0] is the software timestamp
* stamp[1] is deprecated
* stamp[2] is the raw hardware timestamp
* See chapter 2.1.2 Receive timestamps in
* linux/Documentation/networking/timestamping.txt
*/
tv.tv_sec = stamp[2].tv_sec;
tv.tv_usec = stamp[2].tv_nsec/1000;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
}
/* check for (unlikely) dropped frames on this specific socket */
if (dropcnt[i] != last_dropcnt[i]) {
__u32 frames = dropcnt[i] - last_dropcnt[i];
if (silent != SILENT_ON)
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
if (log)
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
last_dropcnt[i] = dropcnt[i];
}
/* once we detected a EFF frame indent SFF frames accordingly */
if (frame.can_id & CAN_EFF_FLAG)
view |= CANLIB_VIEW_INDENT_SFF;
if (log) {
char buf[CL_CFSZ]; /* max length */
/* log CAN frame with absolute timestamp & device */
sprint_canframe(buf, &frame, 0, maxdlen);
fprintf(logfile, "(%010ld.%06ld) %*s %s\n",
tv.tv_sec, tv.tv_usec,
max_devname_len, devname[idx], buf);
}
if ((logfrmt) && (silent == SILENT_OFF)){
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
sprint_canframe(buf, &frame, 0, maxdlen);
printf("(%010ld.%06ld) %*s %s\n",
tv.tv_sec, tv.tv_usec,
max_devname_len, devname[idx], buf);
goto out_fflush; /* no other output to stdout */
}
if (silent != SILENT_OFF){
if (silent == SILENT_ANI) {
printf("%c\b", anichar[silentani%=MAXANI]);
silentani++;
}
goto out_fflush; /* no other output to stdout */
}
printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv.tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
printf("(%s.%06ld) ", timestring, tv.tv_usec);
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
if (last_tv.tv_sec == 0) /* first init */
last_tv = tv;
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
last_tv = tv; /* update for delta calculation */
}
break;
default: /* no timestamp output */
break;
}
printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
printf("%*s", max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
printf (" TX %s", extra_m_info[frame.flags & 3]);
else
printf (" RX %s", extra_m_info[frame.flags & 3]);
}
printf("%s ", (color==1)?col_off:"");
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
printf("%s", (color>1)?col_off:"");
printf("\n");
perror("read");
return 1;
}
out_fflush:
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
maxdlen = CANFD_MAX_DLEN;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
if (count && (--count == 0))
running = 0;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/*
* stamp[0] is the software timestamp
* stamp[1] is deprecated
* stamp[2] is the raw hardware timestamp
* See chapter 2.1.2 Receive timestamps in
* linux/Documentation/networking/timestamping.txt
*/
tv.tv_sec = stamp[2].tv_sec;
tv.tv_usec = stamp[2].tv_nsec/1000;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
}
/* check for (unlikely) dropped frames on this specific socket */
if (obj->dropcnt != obj->last_dropcnt) {
__u32 frames = obj->dropcnt - obj->last_dropcnt;
if (silent != SILENT_ON)
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
if (log)
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
obj->last_dropcnt = obj->dropcnt;
}
/* once we detected a EFF frame indent SFF frames accordingly */
if (frame.can_id & CAN_EFF_FLAG)
view |= CANLIB_VIEW_INDENT_SFF;
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
extra_info = " T";
else
extra_info = " R";
}
if (log) {
char buf[CL_CFSZ]; /* max length */
char ts_buf[TIMESTAMPSZ];
sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf);
/* log CAN frame with absolute timestamp & device */
sprint_canframe(buf, &frame, 0, maxdlen);
fprintf(logfile, "%s%*s %s%s\n", ts_buf,
max_devname_len, devname[idx], buf,
extra_info);
}
if ((logfrmt) && (silent == SILENT_OFF)){
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
sprint_canframe(buf, &frame, 0, maxdlen);
print_timestamp(logtimestamp, &tv, &last_tv);
printf("%*s %s%s\n",
max_devname_len, devname[idx], buf,
extra_info);
goto out_fflush; /* no other output to stdout */
}
if (silent != SILENT_OFF){
if (silent == SILENT_ANI) {
printf("%c\b", anichar[silentani %= MAXANI]);
silentani++;
}
goto out_fflush; /* no other output to stdout */
}
printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : "");
print_timestamp(timestamp, &tv, &last_tv);
printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : "");
printf("%*s", max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
printf (" TX %s", extra_m_info[frame.flags & 3]);
else
printf (" RX %s", extra_m_info[frame.flags & 3]);
}
printf("%s ", (color == 1) ? col_off : "");
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
printf("%s", (color > 1) ? col_off : "");
printf("\n");
out_fflush:
fflush(stdout);
}
}
for (i=0; i<currmax; i++)
close(s[i]);
for (i = 0; i < currmax; i++)
close(sock_info[i].s);
close(fd_epoll);
if (log)
fclose(logfile);
+137 -73
View File
@@ -17,23 +17,24 @@
* Send feedback to <linux-can@vger.kernel.org>
*/
#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <libgen.h>
#include <getopt.h>
#include <time.h>
#include <sched.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/raw.h>
@@ -48,31 +49,37 @@ static int verbose;
static int sockfd;
static int test_loops;
static int exit_sig;
static int inflight_count = CAN_MSG_COUNT;
static void print_usage(char *prg)
{
fprintf(stderr,
"%s - Full-duplex test program (DUT and host part).\n"
"Usage: %s [options] <can-interface>\n"
"\n"
"Options: -v (low verbosity)\n"
" -vv (high verbosity)\n"
"Options:\n"
" -f COUNT (number of frames in flight, default: %d)\n"
" -g (generate messages)\n"
" -l COUNT (test loop count)\n"
" -v (low verbosity)\n"
" -vv (high verbosity)\n"
"\n"
"With the option '-g' CAN messages are generated and checked\n"
"on <can-interface>, otherwise all messages received on the\n"
"<can-interface> are sent back incrementing the CAN id and\n"
"all data bytes. The program can be aborted with ^C.\n"
"\n"
"Example:\n"
"\ton DUT : %s -v can0\n"
"\ton Host: %s -g -v can2\n",
prg, prg, prg);
"Examples:\n"
"\ton DUT:\n"
"%s -v can0\n"
"\ton Host:\n"
"%s -g -v can2\n",
prg, prg, CAN_MSG_COUNT, prg, prg);
exit(1);
}
static void print_frame(struct can_frame *frame, int inc)
static void print_frame(const struct can_frame *frame, int inc)
{
int i;
@@ -82,12 +89,12 @@ static void print_frame(struct can_frame *frame, int inc)
} else {
printf("[%d]", frame->can_dlc);
for (i = 0; i < frame->can_dlc; i++)
printf(" %02x", frame->data[i] + inc);
printf(" %02x", (uint8_t)(frame->data[i] + inc));
}
printf("\n");
}
static void print_compare(struct can_frame *exp, struct can_frame *rec, int inc)
static void print_compare(const struct can_frame *exp, const struct can_frame *rec, int inc)
{
printf("expected: ");
print_frame(exp, inc);
@@ -109,8 +116,8 @@ static void compare_frame(struct can_frame *exp, struct can_frame *rec, int inc)
running = 0;
} else {
for (i = 0; i < rec->can_dlc; i++) {
if (rec->data[i] != ((exp->data[i] + inc) & 0xff)) {
printf("Databyte %x mismatch !\n", i);
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
printf("Databyte %x mismatch!\n", i);
print_compare(exp,
rec, inc);
running = 0;
@@ -174,29 +181,63 @@ static int send_frame(struct can_frame *frame)
while ((ret = send(sockfd, frame, sizeof(*frame), 0))
!= sizeof(*frame)) {
if (ret < 0) {
if (errno != ENOBUFS) {
perror("send failed");
return -1;
} else {
if (verbose) {
printf("N");
fflush(stdout);
}
}
} else {
if (ret >= 0) {
fprintf(stderr, "send returned %d", ret);
return -1;
}
if (errno != ENOBUFS) {
perror("send failed");
return -1;
}
if (verbose) {
printf("N");
fflush(stdout);
}
}
return 0;
}
static int check_frame(const struct can_frame *frame)
{
int err = 0;
int i;
if (frame->can_id != CAN_MSG_ID) {
printf("unexpected Message ID 0x%04x!\n", frame->can_id);
err = -1;
}
if (frame->can_dlc != CAN_MSG_LEN) {
printf("unexpected Message length %d!\n", frame->can_dlc);
err = -1;
}
for (i = 1; i < frame->can_dlc; i++) {
if (frame->data[i] != (uint8_t)(frame->data[i-1] + 1)) {
printf("Frame inconsistent!\n");
print_frame(frame, 0);
err = -1;
goto out;
}
}
out:
return err;
}
static void inc_frame(struct can_frame *frame)
{
int i;
frame->can_id++;
for (i = 0; i < frame->can_dlc; i++)
frame->data[i]++;
}
static int can_echo_dut(void)
{
unsigned int frame_count = 0;
struct can_frame frame;
int i;
while (running) {
if (recv_frame(&frame))
@@ -205,19 +246,11 @@ static int can_echo_dut(void)
if (verbose == 1) {
echo_progress(frame.data[0]);
} else if (verbose > 1) {
printf("%04x: ", frame.can_id);
if (frame.can_id & CAN_RTR_FLAG) {
printf("remote request");
} else {
printf("[%d]", frame.can_dlc);
for (i = 0; i < frame.can_dlc; i++)
printf(" %02x", frame.data[i]);
}
printf("\n");
print_frame(&frame, 0);
}
frame.can_id++;
for (i = 0; i < frame.can_dlc; i++)
frame.data[i]++;
check_frame(&frame);
inc_frame(&frame);
if (send_frame(&frame))
return -1;
@@ -236,15 +269,26 @@ static int can_echo_dut(void)
static int can_echo_gen(void)
{
struct can_frame tx_frames[CAN_MSG_COUNT];
int recv_tx[CAN_MSG_COUNT];
struct can_frame *tx_frames;
int *recv_tx;
struct can_frame rx_frame;
unsigned char counter = 0;
int send_pos = 0, recv_rx_pos = 0, recv_tx_pos = 0, unprocessed = 0, loops = 0;
int err = 0;
int i;
tx_frames = calloc(inflight_count, sizeof(* tx_frames));
if (!tx_frames)
return -1;
recv_tx = calloc(inflight_count, sizeof(* recv_tx));
if (!recv_tx) {
err = -1;
goto out_free_tx_frames;
}
while (running) {
if (unprocessed < CAN_MSG_COUNT) {
if (unprocessed < inflight_count) {
/* still send messages */
tx_frames[send_pos].can_dlc = CAN_MSG_LEN;
tx_frames[send_pos].can_id = CAN_MSG_ID;
@@ -252,11 +296,13 @@ static int can_echo_gen(void)
for (i = 0; i < CAN_MSG_LEN; i++)
tx_frames[send_pos].data[i] = counter + i;
if (send_frame(&tx_frames[send_pos]))
return -1;
if (send_frame(&tx_frames[send_pos])) {
err = -1;
goto out_free;
}
send_pos++;
if (send_pos == CAN_MSG_COUNT)
if (send_pos == inflight_count)
send_pos = 0;
unprocessed++;
if (verbose == 1)
@@ -268,8 +314,10 @@ static int can_echo_gen(void)
else
millisleep(1);
} else {
if (recv_frame(&rx_frame))
return -1;
if (recv_frame(&rx_frame)) {
err = -1;
goto out_free;
}
if (verbose > 1)
print_frame(&rx_frame, 0);
@@ -279,21 +327,22 @@ static int can_echo_gen(void)
compare_frame(&tx_frames[recv_tx_pos], &rx_frame, 0);
recv_tx[recv_tx_pos] = 1;
recv_tx_pos++;
if (recv_tx_pos == CAN_MSG_COUNT)
if (recv_tx_pos == inflight_count)
recv_tx_pos = 0;
continue;
} else {
if (!recv_tx[recv_rx_pos]) {
printf("RX before TX!\n");
running = 0;
}
/* compare with expected */
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
recv_rx_pos++;
if (recv_rx_pos == CAN_MSG_COUNT)
recv_rx_pos = 0;
}
if (!recv_tx[recv_rx_pos]) {
printf("RX before TX!\n");
print_frame(&rx_frame, 0);
running = 0;
}
/* compare with expected */
compare_frame(&tx_frames[recv_rx_pos], &rx_frame, 1);
recv_rx_pos++;
if (recv_rx_pos == inflight_count)
recv_rx_pos = 0;
loops++;
if (test_loops && loops >= test_loops)
break;
@@ -304,7 +353,12 @@ static int can_echo_gen(void)
printf("\nTest messages sent and received: %d\n", loops);
return 0;
out_free:
free(recv_tx);
out_free_tx_frames:
free(tx_frames);
return err;
}
int main(int argc, char *argv[])
@@ -320,20 +374,25 @@ int main(int argc, char *argv[])
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
while ((opt = getopt(argc, argv, "gl:v")) != -1) {
while ((opt = getopt(argc, argv, "f:gl:v?")) != -1) {
switch (opt) {
case 'v':
verbose++;
break;
case 'l':
test_loops = atoi(optarg);;
case 'f':
inflight_count = atoi(optarg);
break;
case 'g':
echo_gen = 1;
break;
case 'l':
test_loops = atoi(optarg);
break;
case 'v':
verbose++;
break;
case '?':
default:
print_usage(basename(argv[0]));
break;
@@ -362,6 +421,11 @@ int main(int argc, char *argv[])
addr.can_family = family;
addr.can_ifindex = if_nametoindex(intf_name);
if (!addr.can_ifindex) {
perror("if_nametoindex");
close(sockfd);
return 1;
}
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
+7 -6
View File
@@ -44,13 +44,14 @@
*
*/
#include "canframelen.h"
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "canframelen.h"
/**
* Functions and types for CRC checks.
+116 -46
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* cangen.c - CAN frames generator for testing purposes
* cangen.c - CAN frames generator
*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
@@ -42,34 +42,38 @@
*
*/
#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <poll.h>
#include <ctype.h>
#include <libgen.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "lib.h"
#define DEFAULT_GAP 200 /* ms */
#define DEFAULT_BURST_COUNT 1
#define MODE_RANDOM 0
#define MODE_INCREMENT 1
#define MODE_FIX 2
#define MODE_RANDOM_EVEN 3
#define MODE_RANDOM_ODD 4
extern int optind, opterr, optopt;
@@ -78,17 +82,21 @@ static unsigned long long enobufs_count;
void print_usage(char *prg)
{
fprintf(stderr, "\n%s: generate CAN frames\n\n", prg);
fprintf(stderr, "%s - CAN frames generator.\n\n", prg);
fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: -g <ms> (gap in milli seconds "
fprintf(stderr, "Options:\n");
fprintf(stderr, " -g <ms> (gap in milli seconds "
"- default: %d ms)\n", DEFAULT_GAP);
fprintf(stderr, " -e (generate extended frame mode "
"(EFF) CAN frames)\n");
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
fprintf(stderr, " -b (generate CAN FD CAN frames"
" with bitrate switch (BRS))\n");
fprintf(stderr, " -R (send RTR frame)\n");
fprintf(stderr, " -m (mix -e -f -b -R frames)\n");
fprintf(stderr, " -E (generate CAN FD CAN frames"
" with error state (ESI))\n");
fprintf(stderr, " -R (generate RTR frames)\n");
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
fprintf(stderr, " -m (mix -e -f -b -E -R frames)\n");
fprintf(stderr, " -I <mode> (CAN ID"
" generation mode - see below)\n");
fprintf(stderr, " -L <mode> (CAN data length code (dlc)"
@@ -103,28 +111,32 @@ void print_usage(char *prg)
" write() syscalls)\n");
fprintf(stderr, " -x (disable local loopback of "
"generated CAN frames)\n");
fprintf(stderr, " -c <count> (number of messages to send in burst, "
"default 1)\n");
fprintf(stderr, " -v (increment verbose level for "
"printing sent CAN frames)\n\n");
fprintf(stderr, "Generation modes:\n");
fprintf(stderr, "'r' => random values (default)\n");
fprintf(stderr, "'i' => increment values\n");
fprintf(stderr, "<hexvalue> => fix value using <hexvalue>\n\n");
fprintf(stderr, " 'r' => random values (default)\n");
fprintf(stderr, " 'e' => random values, even ID\n");
fprintf(stderr, " 'o' => random values, odd ID\n");
fprintf(stderr, " 'i' => increment values\n");
fprintf(stderr, " <value> => fixed value (in hexadecimal for -I and -D)\n\n");
fprintf(stderr, "When incrementing the CAN data the data length code "
"minimum is set to 1.\n");
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v ", prg);
fprintf(stderr, "(fixed CAN ID and length, inc. data)\n");
fprintf(stderr, "%s vcan0 -e -L i -v -v -v ", prg);
fprintf(stderr, "(generate EFF frames, incr. length)\n");
fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8 ", prg);
fprintf(stderr, "(fixed CAN data payload and length)\n");
fprintf(stderr, "%s vcan0 -g 0 -i -x ", prg);
fprintf(stderr, "(full load test ignoring -ENOBUFS)\n");
fprintf(stderr, "%s vcan0 -g 0 -p 10 -x ", prg);
fprintf(stderr, "(full load test with polling, 10ms timeout)\n");
fprintf(stderr, "%s vcan0 ", prg);
fprintf(stderr, "(my favourite default :)\n\n");
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v\n", prg);
fprintf(stderr, "\t(fixed CAN ID and length, inc. data)\n");
fprintf(stderr, "%s vcan0 -e -L i -v -v -v\n", prg);
fprintf(stderr, "\t(generate EFF frames, incr. length)\n");
fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8\n", prg);
fprintf(stderr, "\t(fixed CAN data payload and length)\n");
fprintf(stderr, "%s vcan0 -g 0 -i -x\n", prg);
fprintf(stderr, "\t(full load test ignoring -ENOBUFS)\n");
fprintf(stderr, "%s vcan0 -g 0 -p 10 -x\n", prg);
fprintf(stderr, "\t(full load test with polling, 10ms timeout)\n");
fprintf(stderr, "%s vcan0\n", prg);
fprintf(stderr, "\t(my favourite default :)\n\n");
}
void sigterm(int signo)
@@ -135,11 +147,13 @@ void sigterm(int signo)
int main(int argc, char **argv)
{
double gap = DEFAULT_GAP;
unsigned long burst_count = DEFAULT_BURST_COUNT;
unsigned long polltimeout = 0;
unsigned char ignore_enobufs = 0;
unsigned char extended = 0;
unsigned char canfd = 0;
unsigned char brs = 0;
unsigned char esi = 0;
unsigned char mix = 0;
unsigned char id_mode = MODE_RANDOM;
unsigned char data_mode = MODE_RANDOM;
@@ -147,7 +161,9 @@ int main(int argc, char **argv)
unsigned char loopback_disable = 0;
unsigned char verbose = 0;
unsigned char rtr_frame = 0;
unsigned char len8_dlc = 0;
int count = 0;
unsigned long burst_sent_count = 0;
int mtu, maxdlen;
uint64_t incdata = 0;
int incdlc = 0;
@@ -160,6 +176,7 @@ int main(int argc, char **argv)
struct sockaddr_can addr;
static struct canfd_frame frame;
struct can_frame *ccf = (struct can_frame *)&frame;
int nbytes;
int i;
struct ifreq ifr;
@@ -175,7 +192,7 @@ int main(int argc, char **argv)
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
while ((opt = getopt(argc, argv, "ig:ebfmI:L:D:xp:n:vRh?")) != -1) {
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vR8h?")) != -1) {
switch (opt) {
case 'i':
@@ -199,6 +216,11 @@ int main(int argc, char **argv)
canfd = 1;
break;
case 'E':
esi = 1; /* error state indicator implies CAN FD */
canfd = 1;
break;
case 'm':
mix = 1;
canfd = 1; /* to switch the socket into CAN FD mode */
@@ -209,6 +231,10 @@ int main(int argc, char **argv)
id_mode = MODE_RANDOM;
} else if (optarg[0] == 'i') {
id_mode = MODE_INCREMENT;
} else if (optarg[0] == 'e') {
id_mode = MODE_RANDOM_EVEN;
} else if (optarg[0] == 'o') {
id_mode = MODE_RANDOM_ODD;
} else {
id_mode = MODE_FIX;
frame.can_id = strtoul(optarg, NULL, 16);
@@ -240,6 +266,10 @@ int main(int argc, char **argv)
}
break;
case 'c':
burst_count = strtoul(optarg, NULL, 10);
break;
case 'v':
verbose++;
break;
@@ -252,6 +282,10 @@ int main(int argc, char **argv)
rtr_frame = 1;
break;
case '8':
len8_dlc = 1;
break;
case 'p':
polltimeout = strtoul(optarg, NULL, 10);
break;
@@ -279,7 +313,7 @@ int main(int argc, char **argv)
}
ts.tv_sec = gap / 1000;
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000ll);
ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000LL);
/* recognize obviously missing commandline option */
if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) {
@@ -341,11 +375,19 @@ int main(int argc, char **argv)
}
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
frame.len = can_dlc2len(can_len2dlc(frame.len));
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
} else {
/* sanitize CAN 2.0 frame length */
if (frame.len > 8)
frame.len = 8;
/* sanitize Classical CAN 2.0 frame length */
if (len8_dlc) {
if (frame.len > CAN_MAX_RAW_DLC)
frame.len = CAN_MAX_RAW_DLC;
if (frame.len > CAN_MAX_DLEN)
ccf->len8_dlc = frame.len;
}
if (frame.len > CAN_MAX_DLEN)
frame.len = CAN_MAX_DLEN;
}
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
@@ -369,6 +411,8 @@ int main(int argc, char **argv)
maxdlen = CANFD_MAX_DLEN;
if (brs)
frame.flags |= CANFD_BRS;
if (esi)
frame.flags |= CANFD_ESI;
} else {
mtu = CAN_MTU;
maxdlen = CAN_MAX_DLEN;
@@ -376,6 +420,10 @@ int main(int argc, char **argv)
if (id_mode == MODE_RANDOM)
frame.can_id = random();
else if (id_mode == MODE_RANDOM_EVEN)
frame.can_id = random() & ~0x1;
else if (id_mode == MODE_RANDOM_ODD)
frame.can_id = random() | 0x1;
if (extended) {
frame.can_id &= CAN_EFF_MASK;
@@ -389,11 +437,19 @@ int main(int argc, char **argv)
if (dlc_mode == MODE_RANDOM) {
if (canfd)
frame.len = can_dlc2len(random() & 0xF);
frame.len = can_fd_dlc2len(random() & 0xF);
else {
frame.len = random() & 0xF;
if (frame.len & 8)
if (frame.len > CAN_MAX_DLEN) {
/* generate Classic CAN len8 DLCs? */
if (len8_dlc)
ccf->len8_dlc = frame.len;
frame.len = 8; /* for about 50% of the frames */
} else {
ccf->len8_dlc = 0;
}
}
}
@@ -448,8 +504,8 @@ resend:
if (poll(&fds, 1, polltimeout) < 0) {
perror("poll");
return 1;
} else
goto resend;
}
goto resend;
} else
enobufs_count++;
@@ -458,22 +514,34 @@ resend:
return 1;
}
if (gap) /* gap == 0 => performance test :-] */
burst_sent_count++;
if (gap && burst_sent_count >= burst_count) /* gap == 0 => performance test :-] */
if (nanosleep(&ts, NULL))
return 1;
if (burst_sent_count >= burst_count)
burst_sent_count = 0;
if (id_mode == MODE_INCREMENT)
frame.can_id++;
if (dlc_mode == MODE_INCREMENT) {
incdlc++;
incdlc %= CAN_MAX_RAW_DLC + 1;
if (canfd && !mix) {
incdlc &= 0xF;
frame.len = can_dlc2len(incdlc);
if (canfd && !mix)
frame.len = can_fd_dlc2len(incdlc);
else if (len8_dlc) {
if (incdlc > CAN_MAX_DLEN) {
frame.len = CAN_MAX_DLEN;
ccf->len8_dlc = incdlc;
} else {
frame.len = incdlc;
ccf->len8_dlc = 0;
}
} else {
incdlc %= 9;
incdlc %= CAN_MAX_DLEN + 1;
frame.len = incdlc;
}
}
@@ -490,8 +558,10 @@ resend:
i = random();
extended = i&1;
canfd = i&2;
if (canfd)
if (canfd) {
brs = i&4;
esi = i&8;
}
rtr_frame = ((i&24) == 24); /* reduce RTR frames to 1/4 */
}
}
+59 -56
View File
@@ -42,17 +42,17 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <net/if.h>
#include <libgen.h>
#include <linux/can/gw.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/can/gw.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
enum {
UNSPEC,
@@ -80,7 +80,7 @@ struct fdmodattr {
/* some netlink helpers stolen from iproute2 package */
#define NLMSG_TAIL(nmsg) \
((struct rtattr *)(((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
((struct rtattr *)(((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
int alen)
@@ -88,7 +88,7 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
int len = RTA_LENGTH(alen);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen) {
fprintf(stderr, "addattr_l: message exceeded bound of %d\n",
maxlen);
return -1;
@@ -222,55 +222,60 @@ void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8)
void print_usage(char *prg)
{
fprintf(stderr, "%s - manage PF_CAN netlink gateway.\n", prg);
fprintf(stderr, "\nUsage: %s [options]\n\n", prg);
fprintf(stderr, "Commands: -A (add a new rule)\n");
fprintf(stderr, " -D (delete a rule)\n");
fprintf(stderr, " -F (flush / delete all rules)\n");
fprintf(stderr, " -L (list all rules)\n");
fprintf(stderr, "Mandatory: -s <src_dev> (source netdevice)\n");
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
fprintf(stderr, "Options: -X (this is a CAN FD rule)\n");
fprintf(stderr, " -t (preserve src_dev rx timestamp)\n");
fprintf(stderr, " -e (echo sent frames - recommended on vcanx)\n");
fprintf(stderr, " -i (allow to route to incoming interface)\n");
fprintf(stderr, " -u <uid> (user defined modification identifier)\n");
fprintf(stderr, " -l <hops> (limit the number of frame hops / routings)\n");
fprintf(stderr, " -f <filter> (set CAN filter)\n");
fprintf(stderr, " -m <mod> (set Classic CAN frame modifications)\n");
fprintf(stderr, " -M <MOD> (set CAN FD frame modifications)\n");
fprintf(stderr, " -x <from_idx>:<to_idx>:<result_idx>:<init_xor_val> (XOR checksum)\n");
fprintf(stderr, " -c <from>:<to>:<result>:<init_val>:<xor_val>:<crctab[256]> (CRC8 cs)\n");
fprintf(stderr, " -p <profile>:[<profile_data>] (CRC8 checksum profile & parameters)\n");
fprintf(stderr, "Commands:\n");
fprintf(stderr, " -A (add a new rule)\n");
fprintf(stderr, " -D (delete a rule)\n");
fprintf(stderr, " -F (flush / delete all rules)\n");
fprintf(stderr, " -L (list all rules)\n");
fprintf(stderr, "Mandatory:\n");
fprintf(stderr, " -s <src_dev> (source netdevice)\n");
fprintf(stderr, " -d <dst_dev> (destination netdevice)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -X (this is a CAN FD rule)\n");
fprintf(stderr, " -t (preserve src_dev rx timestamp)\n");
fprintf(stderr, " -e (echo sent frames - recommended on vcanx)\n");
fprintf(stderr, " -i (allow to route to incoming interface)\n");
fprintf(stderr, " -u <uid> (user defined modification identifier)\n");
fprintf(stderr, " -l <hops> (limit the number of frame hops / routings)\n");
fprintf(stderr, " -f <filter> (set CAN filter)\n");
fprintf(stderr, " -m <mod> (set Classical CAN frame modifications)\n");
fprintf(stderr, " -M <MOD> (set CAN FD frame modifications)\n");
fprintf(stderr, " -x <from_idx>:<to_idx>:<result_idx>:<init_xor_val> (XOR checksum)\n");
fprintf(stderr, " -c <from>:<to>:<result>:<init_val>:<xor_val>:<crctab[256]> (CRC8 cs)\n");
fprintf(stderr, " -p <profile>:[<profile_data>] (CRC8 checksum profile & parameters)\n");
fprintf(stderr, "\nValues are given and expected in hexadecimal values. Leading 0s can be omitted.\n");
fprintf(stderr, "\n");
fprintf(stderr, "<filter> is a <value><mask> CAN identifier filter\n");
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
fprintf(stderr, "<filter> is a <value><mask> CAN identifier filter:\n");
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
fprintf(stderr, "\n");
fprintf(stderr, "<mod> is a CAN frame modification instruction consisting of\n");
fprintf(stderr, "<mod> is a Classical CAN frame modification instruction consisting of\n");
fprintf(stderr, "<instruction>:<can_frame-elements>:<can_id>.<can_dlc>.<can_data>\n");
fprintf(stderr, " - <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
fprintf(stderr, " - <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
fprintf(stderr, " - <can_id> is an u32 value containing the CAN Identifier\n");
fprintf(stderr, " - <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
fprintf(stderr, " - <can_data> is always eight(!) u8 values containing the CAN frames data\n");
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
fprintf(stderr, " <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
fprintf(stderr, " <can_id> is an u32 value containing the CAN Identifier\n");
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code in hex (0 .. F)\n");
fprintf(stderr, " <can_data> is always eight(!) u8 values containing the CAN frames data\n");
fprintf(stderr, "\n");
fprintf(stderr, "<MOD> is a CAN FD frame modification instruction consisting of\n");
fprintf(stderr, "<instruction>:<canfd_frame-elements>:<can_id>.<flags>.<len>.<can_data>\n");
fprintf(stderr, " - <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
fprintf(stderr, " - <canfd_frame-elements> is _one_ or _more_ of 'I'd 'F'lags 'L'ength 'D'ata\n");
fprintf(stderr, " - <can_id> is an u32 value containing the CAN FD Identifier\n");
fprintf(stderr, " - <flags> is an u8 value containing CAN FD flags (CANFD_BRS, CANFD_ESI)\n");
fprintf(stderr, " - <len> is an u8 value containing the data length (0 .. 64)\n");
fprintf(stderr, " - <can_data> is always 64(!) u8 values containing the CAN FD frames data\n");
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
fprintf(stderr, " <canfd_frame-elements> is _one_ or _more_ of 'I'd 'F'lags 'L'ength 'D'ata\n");
fprintf(stderr, " <can_id> is an u32 value containing the CAN FD Identifier\n");
fprintf(stderr, " <flags> is an u8 value containing CAN FD flags (CANFD_BRS, CANFD_ESI)\n");
fprintf(stderr, " <len> is an u8 value containing the data length in hex (0 .. 40)\n");
fprintf(stderr, " <can_data> is always 64(!) u8 values containing the CAN FD frames data\n");
fprintf(stderr, "The max. four modifications are performed in the order AND -> OR -> XOR -> SET\n");
fprintf(stderr, "\n");
fprintf(stderr, "Example:\n");
fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
fprintf(stderr, "\n");
fprintf(stderr, "Supported CRC 8 profiles:\n");
fprintf(stderr, "Profile '%d' (1U8) - add one additional u8 value\n", CGW_CRC8PRF_1U8);
fprintf(stderr, "Profile '%d' (16U8) - add u8 value from table[16] indexed by (data[1] & 0xF)\n", CGW_CRC8PRF_16U8);
fprintf(stderr, "Profile '%d' (SFFID_XOR) - add u8 value (can_id & 0xFF) ^ (can_id >> 8 & 0xFF)\n", CGW_CRC8PRF_SFFID_XOR);
fprintf(stderr, " Profile '%d' (1U8) add one additional u8 value\n", CGW_CRC8PRF_1U8);
fprintf(stderr, " Profile '%d' (16U8) add u8 value from table[16] indexed by (data[1] & 0xF)\n", CGW_CRC8PRF_16U8);
fprintf(stderr, " Profile '%d' (SFFID_XOR) add u8 value (can_id & 0xFF) ^ (can_id >> 8 & 0xFF)\n", CGW_CRC8PRF_SFFID_XOR);
fprintf(stderr, "\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, "%s -A -s can0 -d vcan3 -e -f 123:C00007FF -m SET:IL:333.4.1122334455667788\n", prg);
fprintf(stderr, "\n");
}
@@ -290,14 +295,14 @@ int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8)
int ret = 1;
char *ptr;
if (sscanf(optarg, "%hhd:", &crc8->profile) != 1)
if (sscanf(optarg, "%hhu:", &crc8->profile) != 1)
return ret;
switch (crc8->profile) {
case CGW_CRC8PRF_1U8:
if (sscanf(optarg, "%hhd:%2hhx", &crc8->profile, &crc8->profile_data[0]) == 2)
if (sscanf(optarg, "%hhu:%2hhx", &crc8->profile, &crc8->profile_data[0]) == 2)
ret = 0;
break;
@@ -701,8 +706,8 @@ int main(int argc, char **argv)
struct can_filter filter;
struct sockaddr_nl nladdr;
struct cgw_csum_xor cs_xor;
struct cgw_csum_crc8 cs_crc8;
struct cgw_csum_xor cs_xor = { 0 };
struct cgw_csum_crc8 cs_crc8 = { 0 };
char crc8tab[513] = {0};
struct modattr modmsg[CGW_MOD_FUNCS];
@@ -712,8 +717,6 @@ int main(int argc, char **argv)
int i;
memset(&req, 0, sizeof(req));
memset(&cs_xor, 0, sizeof(cs_xor));
memset(&cs_crc8, 0, sizeof(cs_crc8));
while ((opt = getopt(argc, argv, "ADFLs:d:Xteiu:l:f:c:p:x:m:M:?")) != -1) {
switch (opt) {
@@ -767,7 +770,7 @@ int main(int argc, char **argv)
break;
case 'l':
if (sscanf(optarg, "%hhd", &limit_hops) != 1 || !(limit_hops)) {
if (sscanf(optarg, "%hhu", &limit_hops) != 1 || !(limit_hops)) {
printf("Bad hop limit definition '%s'.\n", optarg);
exit(1);
}
+27 -24
View File
@@ -42,29 +42,29 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <errno.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
#include <signal.h>
#include <errno.h>
#include "lib.h"
@@ -89,7 +89,8 @@ void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg);
fprintf(stderr, "Options: -m <mask> (ID filter mask. Default 0x00000000) *\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -m <mask> (ID filter mask. Default 0x00000000) *\n");
fprintf(stderr, " -v <value> (ID filter value. Default 0x00000000) *\n");
fprintf(stderr, " -i <0|1> (invert the specified ID filter) *\n");
fprintf(stderr, " -e <emask> (mask for error frames)\n");
@@ -139,7 +140,7 @@ int idx2dindex(int ifidx, int socket)
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFNAME");
if (max_devname_len < strlen(ifr.ifr_name))
if (max_devname_len < (int)strlen(ifr.ifr_name))
max_devname_len = strlen(ifr.ifr_name);
strcpy(devname[i], ifr.ifr_name);
@@ -161,7 +162,7 @@ void childdied(int i)
}
/*
* This is a Signalhandler for a cought SIGTERM
* This is a Signalhandler for a caught SIGTERM
*/
void shutdown_gra(int i)
{
@@ -280,8 +281,12 @@ int main(int argc, char **argv)
inaddr.sin_port = htons(port);
while(bind(socki, (struct sockaddr*)&inaddr, sizeof(inaddr)) < 0) {
struct timespec f = {
.tv_nsec = 100 * 1000 * 1000,
};
printf(".");fflush(NULL);
usleep(100000);
nanosleep(&f, NULL);
}
if (listen(socki, 3) != 0) {
@@ -295,15 +300,14 @@ int main(int argc, char **argv)
//printf("accepted\n");
if (!fork())
break;
else
close(accsocket);
close(accsocket);
}
else if (errno != EINTR) {
perror("accept");
exit(1);
}
}
for (i=0; i<currmax; i++) {
#ifdef DEBUG
@@ -352,15 +356,14 @@ int main(int argc, char **argv)
addr.can_family = AF_CAN;
if (strcmp(ANYDEV, argv[optind+i])) {
if (strcmp(ANYDEV, argv[optind + i]) != 0) {
strcpy(ifr.ifr_name, argv[optind+i]);
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
exit(1);
}
addr.can_ifindex = ifr.ifr_ifindex;
}
else
} else
addr.can_ifindex = 0; /* any can interface */
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
@@ -409,7 +412,7 @@ int main(int argc, char **argv)
idx = idx2dindex(addr.can_ifindex, s[i]);
sprintf(temp, "(%ld.%06ld) %*s ",
sprintf(temp, "(%lu.%06lu) %*s ",
tv.tv_sec, tv.tv_usec, max_devname_len, devname[idx]);
sprint_canframe(temp+strlen(temp), &frame, 0, maxdlen);
strcat(temp, "\n");
@@ -421,7 +424,7 @@ int main(int argc, char **argv)
#if 0
/* print CAN frame in log file style to stdout */
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
printf("%*s ", max_devname_len, devname[idx]);
fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
#endif
+55 -36
View File
@@ -42,19 +42,19 @@
*
*/
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libgen.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "lib.h"
@@ -77,30 +77,34 @@ extern int optind, opterr, optopt;
void print_usage(char *prg)
{
fprintf(stderr, "%s - replay a compact CAN frame logfile to CAN devices.\n", prg);
fprintf(stderr, "\nUsage: %s <options> [interface assignment]*\n\n", prg);
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
fprintf(stderr, " -l <num> "
"(process input file <num> times)\n"
" "
"(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS);
fprintf(stderr, " -t (ignore timestamps: "
"send frames immediately)\n");
fprintf(stderr, " -g <ms> (gap in milli "
"seconds - default: %d ms)\n", DEFAULT_GAP);
fprintf(stderr, " -s <s> (skip gaps in "
"timestamps > 's' seconds)\n");
fprintf(stderr, " -x (disable local "
"loopback of sent CAN frames)\n");
fprintf(stderr, " -v (verbose: print "
"sent CAN frames)\n\n");
fprintf(stderr, "Interface assignment: 0..n assignments like "
"<write-if>=<log-if>\n");
fprintf(stderr, "e.g. vcan2=can0 ( send frames received from can0 on "
"vcan2 )\n");
fprintf(stderr, "extra hook: stdout=can0 ( print logfile line marked with can0 on "
"stdout )\n");
fprintf(stderr, "No assignments => send frames to the interface(s) they "
"had been received from.\n\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -I <infile> (default stdin)\n");
fprintf(stderr, " -l <num> "
"(process input file <num> times)\n"
" "
"(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS);
fprintf(stderr, " -t (ignore timestamps: "
"send frames immediately)\n");
fprintf(stderr, " -i (interactive - wait "
"for ENTER key to process next frame)\n");
fprintf(stderr, " -g <ms> (gap in milli "
"seconds - default: %d ms)\n", DEFAULT_GAP);
fprintf(stderr, " -s <s> (skip gaps in "
"timestamps > 's' seconds)\n");
fprintf(stderr, " -x (disable local "
"loopback of sent CAN frames)\n");
fprintf(stderr, " -v (verbose: print "
"sent CAN frames)\n\n");
fprintf(stderr, "Interface assignment:\n");
fprintf(stderr, " 0..n assignments like <write-if>=<log-if>\n\n");
fprintf(stderr, " e.g. vcan2=can0 (send frames received from can0 on "
"vcan2)\n");
fprintf(stderr, " extra hook: stdout=can0 (print logfile line marked with can0 on "
"stdout)\n");
fprintf(stderr, " No assignments => send frames to the interface(s) they "
"had been received from\n\n");
fprintf(stderr, "Lines in the logfile not beginning with '(' (start of "
"timestamp) are ignored.\n\n");
}
@@ -137,7 +141,7 @@ static inline int frames_to_send(struct timeval *today, struct timeval *diff,
cmp.tv_sec = log->tv_sec + diff->tv_sec;
cmp.tv_usec = log->tv_usec + diff->tv_usec;
if (cmp.tv_usec > 1000000) {
if (cmp.tv_usec >= 1000000) {
cmp.tv_usec -= 1000000;
cmp.tv_sec++;
}
@@ -213,7 +217,7 @@ int add_assignment(char *mode, int socket, char *txname, char *rxname,
}
strcpy(asgn[i].rxif, rxname);
if (strcmp(txname, "stdout")) {
if (strcmp(txname, "stdout") != 0) {
strcpy(ifr.ifr_name, txname);
if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
@@ -242,6 +246,7 @@ int main(int argc, char **argv)
FILE *infile = stdin;
unsigned long gap = DEFAULT_GAP;
int use_timestamps = 1;
int interactive = 0; /* wait for ENTER keypress to process next frame */
static int verbose, opt, delay_loops;
static unsigned long skipgap;
static int loopback_disable = 0;
@@ -252,7 +257,7 @@ int main(int argc, char **argv)
int eof, txmtu, i, j;
char *fret;
while ((opt = getopt(argc, argv, "I:l:tg:s:xv?")) != -1) {
while ((opt = getopt(argc, argv, "I:l:tig:s:xv?")) != -1) {
switch (opt) {
case 'I':
infile = fopen(optarg, "r");
@@ -276,6 +281,10 @@ int main(int argc, char **argv)
use_timestamps = 0;
break;
case 'i':
interactive = 1;
break;
case 'g':
gap = strtoul(optarg, NULL, 10);
break;
@@ -318,6 +327,12 @@ int main(int argc, char **argv)
printf("%d loops\n", loops);
}
/* ignore timestamps from logfile when in single step keypress mode */
if (interactive) {
use_timestamps = 0;
printf("interactive mode: press ENTER to process next CAN frame ...\n");
}
sleep_ts.tv_sec = gap / 1000;
sleep_ts.tv_nsec = (gap % 1000) * 1000000;
@@ -357,7 +372,7 @@ int main(int argc, char **argv)
return 1;
}
strcpy(buf, argv[optind+i]);
for (j=0; j<BUFSZ; j++) { /* find '=' in assignment */
for (j=0; j<(int)BUFSZ; j++) { /* find '=' in assignment */
if (buf[j] == '=')
break;
}
@@ -393,7 +408,7 @@ int main(int argc, char **argv)
eof = 0;
if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
if (sscanf(buf, "(%lu.%lu) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
device, ascframe) != 4) {
fprintf(stderr, "incorrect line format in logfile\n");
return 1;
@@ -411,6 +426,10 @@ int main(int argc, char **argv)
while ((!use_timestamps) ||
(frames_to_send(&today_tv, &diff_tv, &log_tv) < 0)) {
/* wait for keypress to process next frame */
if (interactive)
getchar();
/* log_tv/device/ascframe are valid here */
if (strlen(device) >= IFNAMSIZ) {
@@ -472,7 +491,7 @@ int main(int argc, char **argv)
break;
}
if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
if (sscanf(buf, "(%lu.%lu) %s %s", &log_tv.tv_sec, &log_tv.tv_usec,
device, ascframe) != 4) {
fprintf(stderr, "incorrect line format in logfile\n");
return 1;
@@ -493,7 +512,7 @@ int main(int argc, char **argv)
/* test for logfile timestamps jumping backwards OR */
/* if the user likes to skip long gaps in the timestamps */
if ((last_log_tv.tv_sec > log_tv.tv_sec) ||
(skipgap && labs(last_log_tv.tv_sec - log_tv.tv_sec) > skipgap))
(skipgap && labs(last_log_tv.tv_sec - log_tv.tv_sec) > (long)skipgap))
create_diff_tv(&today_tv, &diff_tv, &log_tv);
last_log_tv = log_tv;
+33 -18
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets
* cansend.c - send CAN-frames via CAN_RAW sockets
*
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
* All rights reserved.
@@ -56,6 +56,33 @@
#include "lib.h"
void print_usage(char *prg)
{
fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
fprintf(stderr, "\n<can_frame>:\n");
fprintf(stderr, " <can_id>#{data} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#R{len} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#{data}_{dlc} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#R{len}_{dlc} for Classical CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
fprintf(stderr, "<can_id>:\n"
" 3 (SFF) or 8 (EFF) hex chars\n");
fprintf(stderr, "{data}:\n"
" 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
fprintf(stderr, "{len}:\n"
" an optional 0..8 value as RTR frames can contain a valid dlc field\n");
fprintf(stderr, "_{dlc}:\n"
" an optional 9..F data length code value when payload length is 8\n");
fprintf(stderr, "<flags>:\n"
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E\n\n");
}
int main(int argc, char **argv)
{
int s; /* can raw socket */
@@ -68,27 +95,15 @@ int main(int argc, char **argv)
/* check command line options */
if (argc != 3) {
fprintf(stderr, "Usage: %s <device> <can_frame>.\n", argv[0]);
print_usage(argv[0]);
return 1;
}
/* parse CAN frame */
required_mtu = parse_canframe(argv[2], &frame);
if (!required_mtu){
fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n");
fprintf(stderr, " <can_id>#{data} for 'classic' CAN 2.0 data frames\n");
fprintf(stderr, " <can_id>#R{len} for 'classic' CAN 2.0 RTR frames\n");
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
fprintf(stderr, "<can_id> can have 3 (SFF) or 8 (EFF) hex chars\n");
fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally");
fprintf(stderr, " separated by '.')\n");
fprintf(stderr, "{len} is an optional 0..8 value as RTR frames can contain a");
fprintf(stderr, " valid dlc field\n");
fprintf(stderr, "<flags> a single ASCII Hex value (0 .. F) which defines");
fprintf(stderr, " canfd_frame.flags\n\n");
fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / ");
fprintf(stderr, "123##1 / 213##311223344\n 1F334455#1122334455667788 / ");
fprintf(stderr, "123#R / 00000123#R3\n\n");
fprintf(stderr, "\nWrong CAN-frame format!\n\n");
print_usage(argv[0]);
return 1;
}
@@ -110,7 +125,7 @@ int main(int argc, char **argv)
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (required_mtu > CAN_MTU) {
if (required_mtu > (int)CAN_MTU) {
/* check if the frame fits into the CAN netdevice */
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
@@ -132,7 +147,7 @@ int main(int argc, char **argv)
}
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
frame.len = can_dlc2len(can_len2dlc(frame.len));
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
}
/* disable default receive filter on this RAW socket */
+367
View File
@@ -0,0 +1,367 @@
/* SPDX-License-Identifier: GPL-2.0-only */
// Copyright (c) 2007, 2008, 2009, 2010, 2014, 2015, 2019 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (c) 2005 Pengutronix,
// Sascha Hauer <kernel@pengutronix.de>
#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#define CAN_ID_DEFAULT (2)
extern int optind, opterr, optopt;
static int s = -1;
static bool running = true;
static bool infinite = true;
static unsigned int drop_until_quit;
static unsigned int drop_count;
static bool use_poll = false;
static unsigned int loopcount = 1;
static int verbose;
static struct can_frame frame = {
.can_dlc = 1,
};
static struct can_filter filter[] = {
{ .can_id = CAN_ID_DEFAULT, },
};
static void print_usage(char *prg)
{
fprintf(stderr, "Usage: %s [<can-interface>] [Options]\n"
"\n"
"cansequence sends CAN messages with a rising sequence number as payload.\n"
"When the -r option is given, cansequence expects to receive these messages\n"
"and prints an error message if a wrong sequence number is encountered.\n"
"The main purpose of this program is to test the reliability of CAN links.\n"
"\n"
"Options:\n"
" -e, --extended send extended frame\n"
" -i, --identifier=ID CAN Identifier (default = %u)\n"
" --loop=COUNT send message COUNT times\n"
" -p, --poll use poll(2) to wait for buffer space while sending\n"
" -q, --quit <num> quit if <num> wrong sequences are encountered\n"
" -r, --receive work as receiver\n"
" -v, --verbose be verbose (twice to be even more verbose\n"
" -h, --help this help\n"
" --version print version information and exit\n",
prg, CAN_ID_DEFAULT);
}
static void sig_handler(int signo)
{
running = false;
}
static void do_receive()
{
uint8_t ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
struct iovec iov = {
.iov_base = &frame,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = &ctrlmsg,
};
const int dropmonitor_on = 1;
bool sequence_init = true;
unsigned int sequence_wrap = 0;
uint32_t sequence_mask = 0xff;
uint32_t sequence_rx = 0;
uint32_t sequence_delta = 0;
uint32_t sequence = 0;
unsigned int overflow_old = 0;
can_err_mask_t err_mask = CAN_ERR_MASK;
if (setsockopt(s, SOL_SOCKET, SO_RXQ_OVFL,
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
perror("setsockopt() SO_RXQ_OVFL not supported by your Linux Kernel");
}
/* enable recv. of error messages */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask))) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
/* enable recv. now */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, filter, sizeof(filter))) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
while ((infinite || loopcount--) && running) {
ssize_t nbytes;
msg.msg_iov[0].iov_len = sizeof(frame);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
nbytes = recvmsg(s, &msg, 0);
if (nbytes < 0) {
perror("read()");
exit(EXIT_FAILURE);
}
if (frame.can_id & CAN_ERR_FLAG) {
fprintf(stderr,
"sequence CNT: %6u, ERRORFRAME %7x %02x %02x %02x %02x %02x %02x %02x %02x\n",
sequence, frame.can_id,
frame.data[0], frame.data[1], frame.data[2], frame.data[3],
frame.data[4], frame.data[5], frame.data[6], frame.data[7]);
continue;
}
sequence_rx = frame.data[0];
if (sequence_init) {
sequence_init = false;
sequence = sequence_rx;
}
sequence_delta = (sequence_rx - sequence) & sequence_mask;
if (sequence_delta) {
struct cmsghdr *cmsg;
uint32_t overflow = 0;
uint32_t overflow_delta;
drop_count++;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_RXQ_OVFL) {
memcpy(&overflow, CMSG_DATA(cmsg), sizeof(overflow));
break;
}
}
overflow_delta = overflow - overflow_old;
fprintf(stderr,
"sequence CNT: %6u, RX: %6u expected: %3u missing: %4u skt overfl d: %4u a: %4u delta: %3u incident: %u\n",
sequence, sequence_rx,
sequence & sequence_mask, sequence_delta,
overflow_delta, overflow,
sequence_delta - overflow_delta,
drop_count);
if (drop_count == drop_until_quit)
exit(EXIT_FAILURE);
sequence = sequence_rx;
overflow_old = overflow;
} else if (verbose > 1) {
printf("sequence CNT: %6u, RX: %6u\n", sequence, sequence_rx);
}
sequence++;
if (verbose && !(sequence & sequence_mask))
printf("sequence wrap around (%d)\n", sequence_wrap++);
}
}
static void do_send()
{
unsigned int seq_wrap = 0;
uint8_t sequence = 0;
while ((infinite || loopcount--) && running) {
ssize_t len;
if (verbose > 1)
printf("sending frame. sequence number: %d\n", sequence);
again:
len = write(s, &frame, sizeof(frame));
if (len == -1) {
switch (errno) {
case ENOBUFS: {
int err;
struct pollfd fds[] = {
{
.fd = s,
.events = POLLOUT,
},
};
if (!use_poll) {
perror("write");
exit(EXIT_FAILURE);
}
err = poll(fds, 1, 1000);
if (err == -1 && errno != -EINTR) {
perror("poll()");
exit(EXIT_FAILURE);
}
}
case EINTR: /* fallthrough */
goto again;
default:
perror("write");
exit(EXIT_FAILURE);
}
}
frame.data[0]++;
sequence++;
if (verbose && !sequence)
printf("sequence wrap around (%d)\n", seq_wrap++);
}
}
int main(int argc, char **argv)
{
struct sigaction act = {
.sa_handler = sig_handler,
};
struct ifreq ifr;
struct sockaddr_can addr;
char *interface = "can0";
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
int extended = 0;
int receive = 0;
int opt;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGHUP, &act, NULL);
struct option long_options[] = {
{ "extended", no_argument, 0, 'e' },
{ "identifier", required_argument, 0, 'i' },
{ "loop", required_argument, 0, 'l' },
{ "poll", no_argument, 0, 'p' },
{ "quit", optional_argument, 0, 'q' },
{ "receive", no_argument, 0, 'r' },
{ "verbose", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0},
};
while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) {
switch (opt) {
case 'e':
extended = true;
break;
case 'i':
filter->can_id = strtoul(optarg, NULL, 0);
break;
case 'r':
receive = true;
break;
case 'l':
if (optarg) {
loopcount = strtoul(optarg, NULL, 0);
infinite = false;
} else {
infinite = true;
}
break;
case 'p':
use_poll = true;
break;
case 'q':
if (optarg)
drop_until_quit = strtoul(optarg, NULL, 0);
else
drop_until_quit = 1;
break;
case 'v':
verbose++;
break;
case 'h':
print_usage(basename(argv[0]));
exit(EXIT_SUCCESS);
break;
default:
print_usage(basename(argv[0]));
exit(EXIT_FAILURE);
break;
}
}
if (argv[optind] != NULL)
interface = argv[optind];
if (extended) {
filter->can_mask = CAN_EFF_MASK;
filter->can_id &= CAN_EFF_MASK;
filter->can_id |= CAN_EFF_FLAG;
} else {
filter->can_mask = CAN_SFF_MASK;
filter->can_id &= CAN_SFF_MASK;
}
frame.can_id = filter->can_id;
filter->can_mask |= CAN_EFF_FLAG;
printf("interface = %s, family = %d, type = %d, proto = %d\n",
interface, family, type, proto);
s = socket(family, type, proto);
if (s < 0) {
perror("socket()");
exit(EXIT_FAILURE);
}
addr.can_family = family;
strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFINDEX, &ifr)) {
perror("ioctl()");
exit(EXIT_FAILURE);
}
addr.can_ifindex = ifr.ifr_ifindex;
/* first don't recv. any msgs */
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0)) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind()");
exit(EXIT_FAILURE);
}
if (receive)
do_receive();
else
do_send();
exit(EXIT_SUCCESS);
}
+386 -295
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -19,7 +19,7 @@ CFLAGS="${CFLAGS} -Wall"
AC_PROG_CC
LT_INIT(win32-dll)
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2])
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2 subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
#
+35 -16
View File
@@ -84,6 +84,7 @@ typedef __u32 can_err_mask_t;
/* CAN payload length and DLC definitions according to ISO 11898-1 */
#define CAN_MAX_DLC 8
#define CAN_MAX_RAW_DLC 15
#define CAN_MAX_DLEN 8
/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
@@ -91,30 +92,39 @@ typedef __u32 can_err_mask_t;
#define CANFD_MAX_DLEN 64
/**
* struct can_frame - basic CAN frame structure
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
* mapping of the 'data length code' to the real payload length
* @__pad: padding
* @__res0: reserved / padding
* @__res1: reserved / padding
* @data: CAN frame payload (up to 8 byte)
* struct can_frame - Classical CAN frame structure (aka CAN 2.0B)
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
* @len: CAN frame payload length in byte (0 .. 8)
* @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8)
* @__pad: padding
* @__res0: reserved / padding
* @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length
* len8_dlc contains values from 9 .. 15 when the payload length is
* 8 bytes but the DLC value (see ISO 11898-1) is greater then 8.
* CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver.
* @data: CAN frame payload (up to 8 byte)
*/
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 __res1; /* reserved / padding */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
union {
/* CAN frame payload length in byte (0 .. CAN_MAX_DLEN)
* was previously named can_dlc so we need to carry that
* name for legacy support
*/
__u8 len;
__u8 can_dlc; /* deprecated */
} __attribute__((packed)); /* disable padding added in some ABIs */
__u8 __pad; /* padding */
__u8 __res0; /* reserved / padding */
__u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
};
/*
* defined bits for canfd_frame.flags
*
* The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
* be set in the CAN frame bitstream on the wire. The EDL bit switch turns
* The use of struct canfd_frame implies the FD Frame (FDF) bit to
* be set in the CAN frame bitstream on the wire. The FDF bit switch turns
* the CAN controllers bitstream processor into the CAN FD mode which creates
* two new options within the CAN FD frame specification:
*
@@ -125,9 +135,18 @@ struct can_frame {
* controller only the CANFD_BRS bit is relevant for real CAN controllers when
* building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
* sense for virtual CAN interfaces to test applications with echoed frames.
*
* The struct can_frame and struct canfd_frame intentionally share the same
* layout to be able to write CAN frame content into a CAN FD frame structure.
* When this is done the former differentiation via CAN_MTU / CANFD_MTU gets
* lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of
* using struct canfd_frame for mixed CAN / CAN FD content (dual use).
* N.B. the Kernel APIs do NOT provide mixed CAN / CAN FD content inside of
* struct canfd_frame therefore the CANFD_FDF flag is disregarded by Linux.
*/
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
#define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */
/**
* struct canfd_frame - CAN flexible data rate frame structure
+2 -2
View File
@@ -98,8 +98,8 @@ enum {
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
#define CGW_MOD_ID 0x01
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */
#define CGW_MOD_DLC 0x02 /* Classical CAN data length code */
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD (plain) data length */
#define CGW_MOD_DATA 0x04
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
+9 -11
View File
@@ -1,10 +1,10 @@
/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* linux/can/isotp.h
*
* Definitions for isotp CAN sockets
* Definitions for isotp CAN sockets (ISO 15765-2:2016)
*
* Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
* Copyright (c) 2008 Volkswagen Group Electronic Research
* Copyright (c) 2020 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,13 +39,12 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* Send feedback to <linux-can@vger.kernel.org>
*/
#ifndef CAN_ISOTP_H
#define CAN_ISOTP_H
#ifndef _UAPI_CAN_ISOTP_H
#define _UAPI_CAN_ISOTP_H
#include <linux/types.h>
#include <linux/can.h>
#define SOL_CAN_ISOTP (SOL_CAN_BASE + CAN_ISOTP)
@@ -123,7 +122,6 @@ struct can_isotp_ll_options {
/* by the CAN netdriver configuration */
};
/* flags for isotp behaviour */
#define CAN_ISOTP_LISTEN_MODE 0x001 /* listen only (do not send FC) */
@@ -136,7 +134,8 @@ struct can_isotp_ll_options {
#define CAN_ISOTP_FORCE_TXSTMIN 0x080 /* ignore stmin from received FC */
#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */
#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */
#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */
#define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */
/* default values */
@@ -161,7 +160,6 @@ struct can_isotp_ll_options {
* these default settings can be changed via sockopts.
* For that reason the STmin value is intentionally _not_ checked for
* consistency and copied directly into the flow control (FC) frame.
*
*/
#endif
#endif /* !_UAPI_CAN_ISOTP_H */
+1
View File
@@ -100,6 +100,7 @@ struct can_ctrlmode {
#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
/*
* CAN device statistics
+3
View File
@@ -49,6 +49,9 @@
#include <linux/can.h>
#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW)
enum {
SCM_CAN_RAW_ERRQUEUE = 1,
};
/* for socket options affecting the socket (not the global system) */
+96
View File
@@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_KERNEL_H
#define _LINUX_KERNEL_H
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <linux/can.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint32_t __le32;
struct mcp251xfd_mem;
struct regmap {
struct mcp251xfd_mem *mem;
};
#define pr_info(...) fprintf(stdout, ## __VA_ARGS__)
#define pr_cont(...) fprintf(stdout, ## __VA_ARGS__)
#define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__)
#define BUILD_BUG_ON(...)
#define BITS_PER_LONG (sizeof(long) * 8)
#define ____cacheline_aligned
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int regmap_bulk_read(struct regmap *map, unsigned int reg,
void *val, size_t val_count);
#define SZ_2K 0x00000800
#define __packed __attribute__((__packed__))
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
#define BIT(nr) (UL(1) << (nr))
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
#ifdef __ASSEMBLY__
#define _AC(X,Y) X
#define _AT(T,X) X
#else
#define __AC(X,Y) (X##Y)
#define _AC(X,Y) __AC(X,Y)
#define _AT(T,X) ((T)(X))
#endif
#define _UL(x) (_AC(x, UL))
#define _ULL(x) (_AC(x, ULL))
#define UL(x) (_UL(x))
#define ULL(x) (_ULL(x))
#define GENMASK(h, l) \
(((~UL(0)) - (UL(1) << (l)) + 1) & \
(~UL(0) >> (BITS_PER_LONG - 1 - (h))))
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
#define FIELD_PREP(_mask, _val) \
({ \
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
})
#define FIELD_GET(_mask, _reg) \
({ \
(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
})
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1 : __min2; })
#define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 12, 16, 20, 24, 32, 48, 64};
/* get data length from can_dlc with sanitized can_dlc */
static inline u8 can_dlc2len(u8 can_dlc)
{
return dlc2len[can_dlc & 0x0F];
}
#endif /* _LINUX_KERNEL_H */
+1 -1
View File
@@ -96,7 +96,7 @@ struct nlmsghdr {
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
(nlh)->nlmsg_len <= (len))
(int)((nlh)->nlmsg_len) <= (len))
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
#define NLMSG_NOOP 0x1 /* Nothing. */
+71 -67
View File
@@ -42,22 +42,23 @@
*
*/
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h>
#include <time.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/sockios.h>
#include "terminal.h"
#define NO_CAN_ID 0xFFFFFFFFU
@@ -68,20 +69,23 @@ const int canfd_on = 1;
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
fprintf(stderr, " -c (color mode)\n");
fprintf(stderr, " -a (print data also in ASCII-chars)\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -u (print uds messages)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
fprintf(stderr, " -c (color mode)\n");
fprintf(stderr, " -a (print data also in ASCII-chars)\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -u (print uds messages)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "\nUDS output contains a flag which provides information about the type of the message.\n");
fprintf(stderr, "Flags: [SRQ] = Service Request\n");
fprintf(stderr, " [PSR] = Positive Service Response\n");
fprintf(stderr, " [NRC] = Negative Response Code\n");
fprintf(stderr, " [???] = Unknown (not specified)\n");
fprintf(stderr, "\nUDS output contains a flag which provides information about the type of the \n");
fprintf(stderr, "message.\n\n");
fprintf(stderr, "Flags:\n");
fprintf(stderr, " [SRQ] = Service Request\n");
fprintf(stderr, " [PSR] = Positive Service Response\n");
fprintf(stderr, " [NRC] = Negative Response Code\n");
fprintf(stderr, " [???] = Unknown (not specified)\n");
fprintf(stderr, "\n");
}
@@ -332,65 +336,66 @@ int main(int argc, char **argv)
if (nbytes < 0) {
perror("read");
return 1;
} else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
}
if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
fprintf(stderr, "read: incomplete CAN frame %zu %d\n", sizeof(frame), nbytes);
return 1;
} else {
}
if (frame.can_id == src && ext && !extany &&
extaddr != frame.data[0])
continue;
if (frame.can_id == src && ext && !extany && extaddr != frame.data[0])
continue;
if (frame.can_id == dst && rx_ext && !rx_extany &&
rx_extaddr != frame.data[0])
continue;
if (frame.can_id == dst && rx_ext && !rx_extany && rx_extaddr != frame.data[0])
continue;
if (color)
printf("%s", (frame.can_id == src) ? FGRED : FGBLUE);
if (color)
printf("%s", (frame.can_id == src)? FGRED:FGBLUE);
if (timestamp) {
ioctl(s, SIOCGSTAMP, &tv);
if (timestamp) {
ioctl(s, SIOCGSTAMP, &tv);
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv.tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
printf("(%s.%06ld) ", timestring, tv.tv_usec);
}
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
if (last_tv.tv_sec == 0) /* first init */
last_tv = tv;
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
tm = *localtime(&tv.tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S",
&tm);
printf("(%s.%06lu) ", timestring, tv.tv_usec);
} break;
if (timestamp == 'd')
last_tv = tv; /* update for delta calculation */
}
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
if (last_tv.tv_sec == 0) /* first init */
last_tv = tv;
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%lu.%06lu) ", diff.tv_sec,
diff.tv_usec);
if (timestamp == 'd')
last_tv =
tv; /* update for delta calculation */
} break;
default: /* no timestamp output */
break;
default: /* no timestamp output */
break;
}
}
}
if (frame.can_id & CAN_EFF_FLAG)
printf(" %s %8X", argv[optind], frame.can_id & CAN_EFF_MASK);
@@ -407,7 +412,7 @@ int main(int argc, char **argv)
datidx = 0;
n_pci = frame.data[ext];
switch (n_pci & 0xF0) {
case 0x00:
is_ff = 1;
@@ -498,7 +503,6 @@ int main(int argc, char **argv)
printf("%s", ATTRESET);
printf("\n");
fflush(stdout);
}
}
close(s);
+30 -27
View File
@@ -42,18 +42,18 @@
*
*/
#include <libgen.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/raw.h>
@@ -65,11 +65,13 @@
void print_usage(char *prg)
{
fprintf(stderr, "%s - ISO15765-2 protocol performance visualisation.\n", prg);
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode)\n");
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr))\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode)\n");
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr))\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "\n");
}
@@ -221,19 +223,21 @@ int main(int argc, char **argv)
ret = nbytes;
running = 0;
continue;
} else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
}
if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
fprintf(stderr, "read: incomplete CAN frame %zu %d\n", sizeof(frame), nbytes);
ret = nbytes;
running = 0;
continue;
} else {
if (rcvlen) {
/* make sure to process only the detected PDU CAN frame type */
if (canfd_on && (nbytes != CANFD_MTU))
continue;
if (!canfd_on && (nbytes != CAN_MTU))
continue;
}
}
if (rcvlen) {
/* make sure to process only the detected PDU CAN frame type */
if (canfd_on && (nbytes != CANFD_MTU))
continue;
if (!canfd_on && (nbytes != CAN_MTU))
continue;
}
/* check extended address if provided */
if (ext && extaddr != frame.data[0])
@@ -247,13 +251,13 @@ int main(int argc, char **argv)
n_pci = frame.data[rx_ext];
/* check flow control PCI only */
if ((n_pci & 0xF0) == 0x30) {
bs = frame.data[rx_ext+1];
stmin = frame.data[rx_ext+2];
} else
if ((n_pci & 0xF0) != 0x30)
continue;
bs = frame.data[rx_ext + 1];
stmin = frame.data[rx_ext + 2];
}
/* data content starts and index datidx */
datidx = 0;
@@ -353,7 +357,7 @@ int main(int argc, char **argv)
if (rcvlen) {
if (rcvlen > fflen)
rcvlen = fflen;
percent = (rcvlen * 100 / fflen);
printf("\r %3lu%% ", percent);
@@ -363,7 +367,7 @@ int main(int argc, char **argv)
percent = 100;
for (i=0; i < NUMBAR; i++){
if (i < percent/PERCENTRES)
if (i < (int)(percent/PERCENTRES))
printf("X");
else
printf(".");
@@ -395,7 +399,7 @@ int main(int argc, char **argv)
/* check devisor to be not zero */
if (diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000){
printf("%ld.%06lds ", diff_tv.tv_sec, diff_tv.tv_usec);
printf("%lu.%06lus ", diff_tv.tv_sec, diff_tv.tv_usec);
printf("=> %lu byte/s", (fflen * 1000) /
(diff_tv.tv_sec * 1000 + diff_tv.tv_usec / 1000));
} else
@@ -406,7 +410,6 @@ int main(int argc, char **argv)
fflen = rcvlen = 0;
}
fflush(stdout);
}
}
close(s);
+16 -15
View File
@@ -42,16 +42,16 @@
*
*/
#include <libgen.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/isotp.h>
@@ -62,17 +62,18 @@
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -f <time ns> (force rx stmin value in nanosecs)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
fprintf(stderr, " -l (loop: do not exit after pdu reception.)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -f <time ns> (force rx stmin value in nanosecs)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
fprintf(stderr, " -l (loop: do not exit after pdu reception.)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "The pdu data is written on STDOUT in space separated ASCII hex values.\n");
fprintf(stderr, "\n");
+26 -14
View File
@@ -42,16 +42,16 @@
*
*/
#include <libgen.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/isotp.h>
@@ -62,15 +62,18 @@
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
fprintf(stderr, " -b (block until the PDU transmission is completed)\n");
fprintf(stderr, " -S (SF broadcast mode for functional addressing)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
fprintf(stderr, "\n");
@@ -92,7 +95,7 @@ int main(int argc, char **argv)
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:L:?")) != -1) {
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bSL:?")) != -1) {
switch (opt) {
case 's':
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -175,6 +178,14 @@ int main(int argc, char **argv)
}
break;
case 'b':
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
break;
case 'S':
opts.flags |= CAN_ISOTP_SF_BROADCAST;
break;
case 'L':
if (sscanf(optarg, "%hhu:%hhu:%hhu",
&llopts.mtu,
@@ -201,7 +212,8 @@ int main(int argc, char **argv)
if ((argc - optind != 1) ||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
(addr.can_addr.tp.rx_id == NO_CAN_ID)) {
((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
(!(opts.flags & CAN_ISOTP_SF_BROADCAST)))) {
print_usage(basename(argv[0]));
exit(1);
}
+33 -29
View File
@@ -57,21 +57,22 @@
*
*/
#include <errno.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <linux/can.h>
#include <linux/can/isotp.h>
@@ -100,28 +101,29 @@ void childdied(int i)
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s -l <port> -s <can_id> -d <can_id> [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: (* = mandatory)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, "ip addressing:\n");
fprintf(stderr, " * -l <port> (local port for the server)\n");
fprintf(stderr, " -l <port> * (local port for the server)\n");
fprintf(stderr, "\n");
fprintf(stderr, "isotp addressing:\n");
fprintf(stderr, " * -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " * -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -s <can_id> * (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> * (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, "\n");
fprintf(stderr, "padding:\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, "\n");
fprintf(stderr, "rx path: (config, which is sent to the sender / data source)\n");
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions)\n");
fprintf(stderr, "rx path:\n (config, which is sent to the sender / data source)\n");
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions)\n");
fprintf(stderr, "\n");
fprintf(stderr, "tx path: (config, which changes local tx settings)\n");
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
fprintf(stderr, "tx path:\n (config, which changes local tx settings)\n");
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
fprintf(stderr, "\n");
fprintf(stderr, "(* = mandatory option)\n");
fprintf(stderr, "\n");
fprintf(stderr, "All values except for '-l' and '-t' are expected in hexadecimal values.\n");
fprintf(stderr, "\n");
@@ -298,9 +300,13 @@ int main(int argc, char **argv)
saddr.sin_port = htons(local_port);
while(bind(sl,(struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
struct timespec f = {
.tv_nsec = 100 * 1000 * 1000,
};
printf(".");
fflush(NULL);
usleep(100000);
nanosleep(&f, NULL);
}
if (listen(sl, 3) != 0) {
@@ -311,11 +317,9 @@ int main(int argc, char **argv)
while (1) {
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
if (sa > 0 ){
if (fork())
close(sa);
else
if (!fork())
break;
close(sa);
}
else {
if (errno != EINTR) {
+19 -23
View File
@@ -42,23 +42,23 @@
*
*/
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "terminal.h"
#include <linux/can.h>
#include <linux/can/isotp.h>
#include <linux/sockios.h>
#include "terminal.h"
#define NO_CAN_ID 0xFFFFFFFFU
@@ -69,14 +69,15 @@
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode)\n");
fprintf(stderr, " -X <addr> (extended addressing mode - rx addr)\n");
fprintf(stderr, " -c (color mode)\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode)\n");
fprintf(stderr, " -X <addr> (extended addressing mode - rx addr)\n");
fprintf(stderr, " -c (color mode)\n");
fprintf(stderr, " -t <type> (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "\n");
@@ -100,7 +101,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
printf("(%lu.%06lu) ", tv->tv_sec, tv->tv_usec);
break;
case 'A': /* absolute with date */
@@ -110,7 +111,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
tm = *localtime(&tv->tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
printf("(%s.%06ld) ", timestring, tv->tv_usec);
printf("(%s.%06lu) ", timestring, tv->tv_usec);
}
break;
@@ -127,7 +128,7 @@ void printbuf(unsigned char *buffer, int nbytes, int color, int timestamp,
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
printf("(%lu.%06lu) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
*last_tv = *tv; /* update for delta calculation */
@@ -322,12 +323,7 @@ int main(int argc, char **argv)
goto out;
}
if ((setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
perror("setsockopt");
r = 1;
goto out;
}
if ((setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
if ((llopts.mtu) && (setsockopt(t, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts))) < 0) {
perror("setsockopt");
r = 1;
goto out;
+24 -22
View File
@@ -48,21 +48,21 @@
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/isotp.h>
@@ -102,23 +102,25 @@ void perror_syslog(const char *s)
void print_usage(char *prg)
{
fprintf(stderr, "%s - IP over CAN ISO-TP (ISO15765-2) tunnel / proof-of-concept.\n", prg);
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n\n", prg);
fprintf(stderr, "This program creates a Linux tunnel netdevice 'ctunX' and transfers the\n");
fprintf(stderr, "ethernet frames inside ISO15765-2 (unreliable) datagrams on CAN.\n\n");
fprintf(stderr, "Options: -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -n <name> (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
fprintf(stderr, " -D (daemonize to background when tun device created)\n");
fprintf(stderr, " -h (half duplex mode.)\n");
fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -s <can_id> (source can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -d <can_id> (destination can_id. Use 8 digits for extended IDs)\n");
fprintf(stderr, " -n <name> (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
fprintf(stderr, " -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
fprintf(stderr, " -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
fprintf(stderr, " -P <mode> (check rx padding for (l)ength (c)ontent (a)ll)\n");
fprintf(stderr, " -t <time ns> (transmit time in nanosecs)\n");
fprintf(stderr, " -b <bs> (blocksize. 0 = off)\n");
fprintf(stderr, " -m <val> (STmin in ms/ns. See spec.)\n");
fprintf(stderr, " -w <num> (max. wait frame transmissions.)\n");
fprintf(stderr, " -D (daemonize to background when tun device created)\n");
fprintf(stderr, " -h (half duplex mode.)\n");
fprintf(stderr, " -v (verbose mode. Print symbols for tunneled msgs.)\n");
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
fprintf(stderr, "Use e.g. 'ifconfig ctun0 123.123.123.1 pointopoint 123.123.123.2 up'\n");
fprintf(stderr, "to create a point-to-point IP connection on CAN.\n");
+56 -54
View File
@@ -10,29 +10,29 @@
* as published by the Free Software Foundation
*/
#include <signal.h>
#include <time.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/if.h>
#include <getopt.h>
#include <linux/can.h>
#include <linux/can/j1939.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include "libj1939.h"
static const char help_msg[] =
"jacd: An SAE J1939 address claiming daemon" "\n"
"Usage: jacd [options] NAME [INTF]" "\n"
"\n"
"j1939acd: An SAE J1939 address claiming daemon" "\n"
"Usage: j1939acd [options] NAME [INTF]" "\n"
"Options:\n"
" -v, --verbose Increase verbosity" "\n"
" -r, --range=RANGE Ranges of source addresses" "\n"
" e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
@@ -42,8 +42,9 @@ static const char help_msg[] =
"\n"
"NAME is the 64bit nodename" "\n"
"\n"
"Example:" "\n"
"jacd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
"Examples:" "\n"
"j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788" "\n"
"j1939acd -r 100,80-120 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0" "\n"
;
#ifdef _GNU_SOURCE
@@ -182,7 +183,7 @@ static const struct j1939_filter filt[] = {
.pgn = J1939_PGN_REQUEST,
.pgn_mask = J1939_PGN_PDU1_MAX,
}, {
.pgn = 0x0fed8,
.pgn = J1939_PGN_ADDRESS_COMMANDED,
.pgn_mask = J1939_PGN_MAX,
},
};
@@ -198,7 +199,7 @@ static int open_socket(const char *device, uint64_t name)
.addr = J1939_IDLE_ADDR,
.pgn = J1939_NO_PGN,
},
.can_ifindex = if_nametoindex(s.intf),
.can_ifindex = if_nametoindex(device),
};
if (s.verbose)
@@ -251,7 +252,7 @@ static int repeat_address(int sock, uint64_t name)
ret = sendto(sock, dat, sizeof(dat), 0, (const struct sockaddr *)&saddr,
sizeof(saddr));
if (must_warn(ret))
err(1, "send address claim for 0x%02x", s.last_sa);
fprintf(stderr, "send address claim for 0x%02x\n", s.last_sa);
return ret;
}
static int claim_address(int sock, uint64_t name, int sa)
@@ -290,7 +291,7 @@ static int request_addresses(int sock)
fprintf(stderr, "- sendto(, { 0, 0xee, 0, }, %zi, 0, %s, %zi);\n", sizeof(dat), libj1939_addr2str(&saddr), sizeof(saddr));
ret = sendto(sock, dat, sizeof(dat), 0, (void *)&saddr, sizeof(saddr));
if (must_warn(ret))
err(1, "send request for address claims");
fprintf(stdout, "send request for address claims");
return ret;
}
@@ -364,7 +365,7 @@ static void install_signal(int sig)
static void schedule_itimer(int msec)
{
int ret;
struct itimerval val = {};
struct itimerval val = { 0 };
val.it_value.tv_sec = msec / 1000;
val.it_value.tv_usec = (msec % 1000) * 1000;
@@ -382,10 +383,9 @@ static inline int addr_status_mine(int sa)
{
if (sa == s.current_sa)
return '*';
else if (addr[sa].flags & F_USE)
if (addr[sa].flags & F_USE)
return '+';
else
return '-';
return '-';
}
static void dump_status(void)
@@ -471,32 +471,34 @@ int main(int argc, char *argv[])
#endif
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) {
case 'v':
++s.verbose;
break;
case 'c':
s.cachefile = optarg;
break;
case 'r':
s.ranges = optarg;
break;
case 'a':
s.current_sa = strtoul(optarg, 0, 0);
break;
case 'p':
switch (opt) {
case 'v':
++s.verbose;
break;
case 'c':
s.cachefile = optarg;
break;
case 'r':
s.ranges = optarg;
break;
case 'a':
s.current_sa = strtoul(optarg, 0, 0);
break;
case 'p':
#ifdef _GNU_SOURCE
if (asprintf(&program_invocation_name, "%s.%s", program_invocation_short_name, optarg) < 0)
err(1, "asprintf(program invocation name)");
if (asprintf(&program_invocation_name, "%s.%s",
program_invocation_short_name, optarg) < 0)
err(1, "asprintf(program invocation name)");
#else
err(0, "compile with -D_GNU_SOURCE to use -p");
err(0, "compile with -D_GNU_SOURCE to use -p");
#endif
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
if (argv[optind])
s.name = strtoull(argv[optind++], 0, 16);
if (argv[optind])
@@ -512,12 +514,12 @@ int main(int argc, char *argv[])
if ((s.current_sa < J1939_IDLE_ADDR) && !(addr[s.current_sa].flags & F_USE)) {
if (s.verbose)
err(0, "forget saved address 0x%02x", s.current_sa);
fprintf(stderr, "- forget saved address 0x%02x\n", s.current_sa);
s.current_sa = J1939_IDLE_ADDR;
}
if (s.verbose)
err(0, "ready for %s:%016llx", s.intf, (long long)s.name);
fprintf(stderr, "- ready for %s:%016llx\n", s.intf, (long long)s.name);
if (!s.intf || !s.name)
err(1, "bad arguments");
ret = sock = open_socket(s.intf, s.name);
@@ -581,7 +583,7 @@ int main(int argc, char *argv[])
break;
if (s.state == STATE_REQ_SENT) {
if (s.verbose)
err(0, "request sent, pending for 1250 ms");
fprintf(stderr, "- request sent, pending for 1250 ms\n");
schedule_itimer(1250);
s.state = STATE_REQ_PENDING;
} else if (s.state == STATE_OPERATIONAL) {
@@ -611,14 +613,14 @@ int main(int argc, char *argv[])
/* ourselves, disable itimer */
s.current_sa = sa;
if (s.verbose)
err(0, "claimed 0x%02x", sa);
fprintf(stderr, "- claimed 0x%02x\n", sa);
} else if (sa == s.current_sa) {
if (s.verbose)
err(0, "address collision for 0x%02x", sa);
fprintf(stderr, "- address collision for 0x%02x\n", sa);
if (s.name > saddr.can_addr.j1939.name) {
sa = choose_new_sa(s.name, sa);
if (sa == J1939_IDLE_ADDR) {
err(0, "no address left");
fprintf(stdout, "no address left");
/* put J1939_IDLE_ADDR in cache file */
s.current_sa = sa;
goto done;
@@ -629,7 +631,7 @@ int main(int argc, char *argv[])
schedule_itimer(50);
}
break;
case 0x0fed8:
case J1939_PGN_ADDRESS_COMMANDED:
if (!host_is_little_endian())
bswap(dat, 8);
memcpy(&cmd_name, dat, 8);
@@ -643,7 +645,7 @@ int main(int argc, char *argv[])
}
done:
if (s.verbose)
err(0, "shutdown");
fprintf(stderr, "- shutdown\n");
claim_address(sock, s.name, J1939_IDLE_ADDR);
save_cache();
return 0;
+121 -103
View File
@@ -8,19 +8,21 @@
#include <fcntl.h>
#include <inttypes.h>
#include <net/if.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <poll.h>
#include <linux/errqueue.h>
#include <linux/netlink.h>
#include <linux/net_tstamp.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include "libj1939.h"
#define J1939_MAX_ETP_PACKET_SIZE (7 * 0x00ffffff)
#define JCAT_BUF_SIZE (1000 * 1024)
@@ -36,13 +38,13 @@
_min1 < _min2 ? _min1 : _min2; })
struct jcat_stats {
struct j1939cat_stats {
int err;
uint32_t tskey;
uint32_t send;
};
struct jcat_priv {
struct j1939cat_priv {
int sock;
int infile;
int outfile;
@@ -55,6 +57,7 @@ struct jcat_priv {
bool todo_recv;
bool todo_filesize;
bool todo_connect;
int todo_broadcast;
unsigned long polltimeout;
@@ -63,12 +66,12 @@ struct jcat_priv {
struct sock_extended_err *serr;
struct scm_timestamping *tss;
struct jcat_stats stats;
struct j1939cat_stats stats;
};
static const char help_msg[] =
"jcat: netcat tool for j1939\n"
"Usage: jcat FROM TO\n"
"j1939cat: netcat-like tool for j1939\n"
"Usage: j1939cat [options] FROM TO\n"
" FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n"
"Options:\n"
" -i <infile> (default stdin)\n"
@@ -77,17 +80,18 @@ static const char help_msg[] =
" -P <timeout> poll timeout in milliseconds before sending data.\n"
" With this option send() will be used with MSG_DONTWAIT flag.\n"
" -R <count> Set send repeat count. Default: 1\n"
" -B Allow to send and receive broadcast packets.\n"
"\n"
"Example:\n"
"jcat -i some_file_to_send can0:0x80 :0x90,0x12300\n"
"jcat can0:0x90 -r > /tmp/some_file_to_receive\n"
"j1939cat -i some_file_to_send can0:0x80 :0x90,0x12300\n"
"j1939cat can0:0x90 -r > /tmp/some_file_to_receive\n"
"\n"
;
static const char optstring[] = "?i:vs:rp:P:R:";
static const char optstring[] = "?hi:vs:rp:P:R:B";
static void jcat_init_sockaddr_can(struct sockaddr_can *sac)
static void j1939cat_init_sockaddr_can(struct sockaddr_can *sac)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
@@ -95,7 +99,7 @@ static void jcat_init_sockaddr_can(struct sockaddr_can *sac)
sac->can_addr.j1939.pgn = J1939_NO_PGN;
}
static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd,
static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd,
const void *buf, size_t buf_size)
{
ssize_t num_sent;
@@ -121,7 +125,7 @@ static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd,
return -EINVAL;
}
if (num_sent > buf_size) /* Should never happen */ {
if (num_sent > (ssize_t)buf_size) /* Should never happen */ {
warn("%s: send more then read", __func__);
return -EINVAL;
}
@@ -129,10 +133,10 @@ static ssize_t jcat_send_one(struct jcat_priv *priv, int out_fd,
return num_sent;
}
static void jcat_print_timestamp(struct jcat_priv *priv, const char *name,
static void j1939cat_print_timestamp(struct j1939cat_priv *priv, const char *name,
struct timespec *cur)
{
struct jcat_stats *stats = &priv->stats;
struct j1939cat_stats *stats = &priv->stats;
if (!(cur->tv_sec | cur->tv_nsec))
return;
@@ -144,7 +148,7 @@ static void jcat_print_timestamp(struct jcat_priv *priv, const char *name,
fprintf(stderr, "\n");
}
static const char *jcat_tstype_to_str(int tstype)
static const char *j1939cat_tstype_to_str(int tstype)
{
switch (tstype) {
case SCM_TSTAMP_SCHED:
@@ -159,17 +163,17 @@ static const char *jcat_tstype_to_str(int tstype)
}
/* Check the stats of SCM_TIMESTAMPING_OPT_STATS */
static void jcat_scm_opt_stats(struct jcat_priv *priv, void *buf, int len)
static void j1939cat_scm_opt_stats(struct j1939cat_priv *priv, void *buf, int len)
{
struct jcat_stats *stats = &priv->stats;
struct j1939cat_stats *stats = &priv->stats;
int offset = 0;
while (offset < len) {
struct nlattr *nla = (struct nlattr *) (buf + offset);
struct nlattr *nla = (struct nlattr *) ((char *)buf + offset);
switch (nla->nla_type) {
case J1939_NLA_BYTES_ACKED:
stats->send = *(uint32_t *)((void *)nla + NLA_HDRLEN);
stats->send = *(uint32_t *)((char *)nla + NLA_HDRLEN);
break;
default:
warnx("not supported J1939_NLA field\n");
@@ -179,9 +183,9 @@ static void jcat_scm_opt_stats(struct jcat_priv *priv, void *buf, int len)
}
}
static int jcat_extract_serr(struct jcat_priv *priv)
static int j1939cat_extract_serr(struct j1939cat_priv *priv)
{
struct jcat_stats *stats = &priv->stats;
struct j1939cat_stats *stats = &priv->stats;
struct sock_extended_err *serr = priv->serr;
struct scm_timestamping *tss = priv->tss;
@@ -205,13 +209,12 @@ static int jcat_extract_serr(struct jcat_priv *priv)
serr->ee_errno);
stats->tskey = serr->ee_data;
jcat_print_timestamp(priv, jcat_tstype_to_str(serr->ee_info),
j1939cat_print_timestamp(priv, j1939cat_tstype_to_str(serr->ee_info),
&tss->ts[0]);
if (serr->ee_info == SCM_TSTAMP_SCHED)
return -EINTR;
else
return 0;
return 0;
case SO_EE_ORIGIN_LOCAL:
/*
* The serr->ee_origin == SO_EE_ORIGIN_LOCAL is
@@ -232,7 +235,7 @@ static int jcat_extract_serr(struct jcat_priv *priv)
warnx("serr: unknown ee_info: %i",
serr->ee_info);
jcat_print_timestamp(priv, " ABT", &tss->ts[0]);
j1939cat_print_timestamp(priv, " ABT", &tss->ts[0]);
warnx("serr: tx error: %i, %s", serr->ee_errno, strerror(serr->ee_errno));
return serr->ee_errno;
@@ -243,7 +246,7 @@ static int jcat_extract_serr(struct jcat_priv *priv)
return 0;
}
static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
static int j1939cat_parse_cm(struct j1939cat_priv *priv, struct cmsghdr *cm)
{
const size_t hdr_len = CMSG_ALIGN(sizeof(struct cmsghdr));
@@ -253,7 +256,7 @@ static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
void *jstats = (void *)CMSG_DATA(cm);
/* Activated with SOF_TIMESTAMPING_OPT_STATS */
jcat_scm_opt_stats(priv, jstats, cm->cmsg_len - hdr_len);
j1939cat_scm_opt_stats(priv, jstats, cm->cmsg_len - hdr_len);
} else if (cm->cmsg_level == SOL_CAN_J1939 &&
cm->cmsg_type == SCM_J1939_ERRQUEUE) {
priv->serr = (void *)CMSG_DATA(cm);
@@ -264,7 +267,7 @@ static int jcat_parse_cm(struct jcat_priv *priv, struct cmsghdr *cm)
return 0;
}
static int jcat_recv_err(struct jcat_priv *priv)
static int j1939cat_recv_err(struct j1939cat_priv *priv)
{
char control[100];
struct cmsghdr *cm;
@@ -285,18 +288,18 @@ static int jcat_recv_err(struct jcat_priv *priv)
for (cm = CMSG_FIRSTHDR(&msg); cm && cm->cmsg_len;
cm = CMSG_NXTHDR(&msg, cm)) {
jcat_parse_cm(priv, cm);
j1939cat_parse_cm(priv, cm);
if (priv->serr && priv->tss)
return jcat_extract_serr(priv);
return j1939cat_extract_serr(priv);
}
return 0;
}
static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf,
static int j1939cat_send_loop(struct j1939cat_priv *priv, int out_fd, char *buf,
size_t buf_size)
{
struct jcat_stats *stats = &priv->stats;
struct j1939cat_stats *stats = &priv->stats;
ssize_t count;
char *tmp_buf = buf;
unsigned int events = POLLOUT | POLLERR;
@@ -317,34 +320,32 @@ static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf,
ret = poll(&fds, 1, priv->polltimeout);
if (ret == -EINTR)
continue;
else if (ret < 0)
if (ret < 0)
return -errno;
else if (!ret)
if (!ret)
return -ETIME;
if (!(fds.revents & events)) {
warn("%s: something else is wrong", __func__);
return -EIO;
}
if (fds.revents & POLLERR) {
ret = jcat_recv_err(priv);
ret = j1939cat_recv_err(priv);
if (ret == -EINTR)
continue;
else if (ret)
if (ret)
return ret;
else if ((priv->repeat - 1) == stats->tskey)
if ((priv->repeat - 1) == stats->tskey)
tx_done = true;
}
if (fds.revents & POLLOUT) {
num_sent = jcat_send_one(priv, out_fd, tmp_buf, count);
num_sent = j1939cat_send_one(priv, out_fd, tmp_buf, count);
if (num_sent < 0)
return num_sent;
}
} else {
num_sent = jcat_send_one(priv, out_fd, tmp_buf, count);
num_sent = j1939cat_send_one(priv, out_fd, tmp_buf, count);
if (num_sent < 0)
return num_sent;
}
@@ -366,13 +367,14 @@ static int jcat_send_loop(struct jcat_priv *priv, int out_fd, char *buf,
return 0;
}
static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd,
static int j1939cat_sendfile(struct j1939cat_priv *priv, int out_fd, int in_fd,
off_t *offset, size_t count)
{
int ret = EXIT_SUCCESS;
off_t orig = 0;
char *buf;
size_t to_read, num_read, buf_size;
ssize_t num_read;
size_t to_read, buf_size;
buf_size = min(priv->max_transfer, count);
buf = malloc(buf_size);
@@ -408,7 +410,7 @@ static int jcat_sendfile(struct jcat_priv *priv, int out_fd, int in_fd,
if (num_read == 0)
break; /* EOF */
ret = jcat_send_loop(priv, out_fd, buf, num_read);
ret = j1939cat_send_loop(priv, out_fd, buf, num_read);
if (ret)
goto do_free;
@@ -437,7 +439,7 @@ do_nofree:
return ret;
}
static size_t jcat_get_file_size(int fd)
static size_t j1939cat_get_file_size(int fd)
{
off_t offset;
@@ -451,20 +453,21 @@ static size_t jcat_get_file_size(int fd)
return offset;
}
static int jcat_send(struct jcat_priv *priv)
static int j1939cat_send(struct j1939cat_priv *priv)
{
unsigned int size = 0;
int ret, i;
unsigned int i;
int ret;
if (priv->todo_filesize)
size = jcat_get_file_size(priv->infile);
size = j1939cat_get_file_size(priv->infile);
if (!size)
return EXIT_FAILURE;
for (i = 0; i < priv->repeat; i++) {
priv->round++;
ret = jcat_sendfile(priv, priv->sock, priv->infile, NULL, size);
ret = j1939cat_sendfile(priv, priv->sock, priv->infile, NULL, size);
if (ret)
break;
@@ -475,7 +478,7 @@ static int jcat_send(struct jcat_priv *priv)
return ret;
}
static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size)
static int j1939cat_recv_one(struct j1939cat_priv *priv, uint8_t *buf, size_t buf_size)
{
int ret;
@@ -494,7 +497,7 @@ static int jcat_recv_one(struct jcat_priv *priv, uint8_t *buf, size_t buf_size)
return EXIT_SUCCESS;
}
static int jcat_recv(struct jcat_priv *priv)
static int j1939cat_recv(struct j1939cat_priv *priv)
{
int ret = EXIT_SUCCESS;
size_t buf_size;
@@ -508,7 +511,7 @@ static int jcat_recv(struct jcat_priv *priv)
}
while (priv->todo_recv) {
ret = jcat_recv_one(priv, buf, buf_size);
ret = j1939cat_recv_one(priv, buf, buf_size);
if (ret)
break;
}
@@ -517,7 +520,7 @@ static int jcat_recv(struct jcat_priv *priv)
return ret;
}
static int jcat_sock_prepare(struct jcat_priv *priv)
static int j1939cat_sock_prepare(struct j1939cat_priv *priv)
{
unsigned int sock_opt;
int value;
@@ -558,6 +561,16 @@ static int jcat_sock_prepare(struct jcat_priv *priv)
(char *) &sock_opt, sizeof(sock_opt)))
err(1, "setsockopt timestamping");
if (priv->todo_broadcast) {
ret = setsockopt(priv->sock, SOL_SOCKET, SO_BROADCAST,
&priv->todo_broadcast,
sizeof(priv->todo_broadcast));
if (ret < 0) {
warn("setsockopt: filed to set broadcast");
return EXIT_FAILURE;
}
}
ret = bind(priv->sock, (void *)&priv->sockname, sizeof(priv->sockname));
if (ret < 0) {
warn("bind()");
@@ -581,55 +594,62 @@ static int jcat_sock_prepare(struct jcat_priv *priv)
return EXIT_SUCCESS;
}
static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[])
static int j1939cat_parse_args(struct j1939cat_priv *priv, int argc, char *argv[])
{
int opt;
/* argument parsing */
while ((opt = getopt(argc, argv, optstring)) != -1)
switch (opt) {
case 'i':
priv->infile = open(optarg, O_RDONLY);
if (priv->infile == -1)
err(EXIT_FAILURE, "can't open input file");
priv->todo_filesize = 1;
break;
case 's':
priv->max_transfer = strtoul(optarg, NULL, 0);
if (priv->max_transfer > J1939_MAX_ETP_PACKET_SIZE)
err(EXIT_FAILURE, "used value (%zu) is bigger then allowed maximal size: %u.\n",
priv->max_transfer, J1939_MAX_ETP_PACKET_SIZE);
break;
case 'r':
priv->todo_recv = 1;
break;
case 'p':
priv->todo_prio = strtoul(optarg, NULL, 0);
break;
case 'P':
priv->polltimeout = strtoul(optarg, NULL, 0);
break;
case 'c':
priv->todo_connect = 1;
break;
case 'R':
priv->repeat = strtoul(optarg, NULL, 0);
if (priv->repeat < 1)
err(EXIT_FAILURE, "send/repeat count can't be less then 1\n");
break;
default:
fputs(help_msg, stderr);
return EXIT_FAILURE;
}
switch (opt) {
case 'i':
priv->infile = open(optarg, O_RDONLY);
if (priv->infile == -1)
err(EXIT_FAILURE, "can't open input file");
priv->todo_filesize = 1;
break;
case 's':
priv->max_transfer = strtoul(optarg, NULL, 0);
if (priv->max_transfer > J1939_MAX_ETP_PACKET_SIZE)
err(EXIT_FAILURE,
"used value (%zu) is bigger then allowed maximal size: %u.\n",
priv->max_transfer,
J1939_MAX_ETP_PACKET_SIZE);
break;
case 'r':
priv->todo_recv = 1;
break;
case 'p':
priv->todo_prio = strtoul(optarg, NULL, 0);
break;
case 'P':
priv->polltimeout = strtoul(optarg, NULL, 0);
break;
case 'c':
priv->todo_connect = 1;
break;
case 'R':
priv->repeat = strtoul(optarg, NULL, 0);
if (priv->repeat < 1)
err(EXIT_FAILURE,
"send/repeat count can't be less then 1\n");
break;
case 'B':
priv->todo_broadcast = 1;
break;
case 'h': /*fallthrough*/
default:
fputs(help_msg, stderr);
return EXIT_FAILURE;
}
if (argv[optind]) {
if (strcmp("-", argv[optind]))
if (strcmp("-", argv[optind]) != 0)
libj1939_parse_canaddr(argv[optind], &priv->sockname);
optind++;
}
if (argv[optind]) {
if (strcmp("-", argv[optind])) {
if (strcmp("-", argv[optind]) != 0) {
libj1939_parse_canaddr(argv[optind], &priv->peername);
priv->valid_peername = 1;
}
@@ -641,15 +661,13 @@ static int jcat_parse_args(struct jcat_priv *priv, int argc, char *argv[])
int main(int argc, char *argv[])
{
struct jcat_priv *priv;
int ret;
struct j1939cat_priv *priv;
int ret = 0;
priv = malloc(sizeof(*priv));
priv = calloc(1, sizeof(*priv));
if (!priv)
err(EXIT_FAILURE, "can't allocate priv");
bzero(priv, sizeof(*priv));
priv->todo_prio = -1;
priv->infile = STDIN_FILENO;
priv->outfile = STDOUT_FILENO;
@@ -657,25 +675,25 @@ int main(int argc, char *argv[])
priv->polltimeout = 100000;
priv->repeat = 1;
jcat_init_sockaddr_can(&priv->sockname);
jcat_init_sockaddr_can(&priv->peername);
j1939cat_init_sockaddr_can(&priv->sockname);
j1939cat_init_sockaddr_can(&priv->peername);
ret = jcat_parse_args(priv, argc, argv);
ret = j1939cat_parse_args(priv, argc, argv);
if (ret)
return ret;
ret = jcat_sock_prepare(priv);
ret = j1939cat_sock_prepare(priv);
if (ret)
return ret;
if (priv->todo_recv)
ret = jcat_recv(priv);
ret = j1939cat_recv(priv);
else
ret = jcat_send(priv);
ret = j1939cat_send(priv);
close(priv->infile);
close(priv->outfile);
close(priv->sock);
return ret;
}
+38 -36
View File
@@ -10,19 +10,19 @@
* as published by the Free Software Foundation
*/
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#include <sys/socket.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include "libj1939.h"
@@ -30,9 +30,9 @@
* getopt
*/
static const char help_msg[] =
"jspy: An SAE J1939 spy utility" "\n"
"Usage: jspy [OPTION...] [[IFACE:][NAME|SA][,PGN]]" "\n"
"\n"
"j1939spy: An SAE J1939 spy utility" "\n"
"Usage: j1939spy [OPTION...] [[IFACE:][NAME|SA][,PGN]]" "\n"
"Options:\n"
" -v, --verbose Increase verbosity" "\n"
" -P, --promisc Run in promiscuous mode" "\n"
" (= receive traffic not for this ECU)" "\n"
@@ -95,8 +95,8 @@ static uint8_t *buf;
*/
int main(int argc, char **argv)
{
int ret, sock, j, opt;
unsigned int len;
int ret, sock, opt;
unsigned int j, len;
struct timeval tref, tdut, ttmp;
struct sockaddr_can src;
struct j1939_filter filt;
@@ -107,30 +107,32 @@ int main(int argc, char **argv)
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) {
case 'v':
++s.verbose;
break;
case 'b':
s.pkt_len = strtoul(optarg, 0, 0);
break;
case 'P':
++s.promisc;
break;
case 't':
if (optarg) {
if (!strchr("adzA", optarg[0]))
err(1, "unknown time option '%c'", optarg[0]);
s.time = optarg[0];
} else {
s.time = 'z';
switch (opt) {
case 'v':
++s.verbose;
break;
case 'b':
s.pkt_len = strtoul(optarg, 0, 0);
break;
case 'P':
++s.promisc;
break;
case 't':
if (optarg) {
if (!strchr("adzA", optarg[0]))
err(1, "unknown time option '%c'",
optarg[0]);
s.time = optarg[0];
} else {
s.time = 'z';
}
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
if (argv[optind]) {
optarg = argv[optind];
ret = libj1939_str2addr(optarg, 0, &s.addr);
@@ -287,7 +289,7 @@ int main(int argc, char **argv)
printf("[%i%s]", len, (msg.msg_flags & MSG_TRUNC) ? "..." : "");
for (j = 0; j < len; ) {
int end = j + 4;
unsigned int end = j + 4;
if (end > len)
end = len;
printf(" ");
+31 -31
View File
@@ -10,20 +10,20 @@
* as published by the Free Software Foundation
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#include <getopt.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "libj1939.h"
@@ -31,9 +31,9 @@
* getopt
*/
static const char help_msg[] =
"jsr: An SAE J1939 send/recv utility" "\n"
"Usage: jsr [OPTION...] SOURCE [DEST]" "\n"
"\n"
"j1939sr: An SAE J1939 send/recv utility" "\n"
"Usage: j1939sr [OPTION...] SOURCE [DEST]" "\n"
"Options:\n"
" -v, --verbose Increase verbosity" "\n"
" -p, --priority=VAL J1939 priority (0..7, default 6)" "\n"
" -S, --serialize Strictly serialize outgoing packets" "\n"
@@ -99,27 +99,27 @@ int main(int argc, char **argv)
#endif
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) {
case 'v':
++s.verbose;
break;
case 's':
s.pkt_len = strtoul(optarg, 0, 0);
if (!s.pkt_len)
err(1, "packet size of %s", optarg);
break;
case 'p':
s.priority = strtoul(optarg, 0, 0);
s.defined |= DEF_PRIO;
break;
case 'S':
s.sendflags |= MSG_SYN;
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
switch (opt) {
case 'v':
++s.verbose;
break;
case 's':
s.pkt_len = strtoul(optarg, 0, 0);
if (!s.pkt_len)
err(1, "packet size of %s", optarg);
break;
case 'p':
s.priority = strtoul(optarg, 0, 0);
s.defined |= DEF_PRIO;
break;
case 'S':
s.sendflags |= MSG_SYN;
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
if (argv[optind]) {
optarg = argv[optind++];
+71 -13
View File
@@ -42,17 +42,18 @@
*
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/socket.h> /* for sa_family_t */
#include <linux/can.h>
#include <linux/can/error.h>
#include <sys/socket.h> /* for sa_family_t */
#include "lib.h"
#define CANID_DELIM '#'
#define CC_DLC_DELIM '_'
#define DATA_SEPERATOR '.'
const char hex_asc_upper[] = "0123456789ABCDEF";
@@ -83,10 +84,10 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 12, 16, 20, 24, 32, 48, 64};
/* get data length from can_dlc with sanitized can_dlc */
unsigned char can_dlc2len(unsigned char can_dlc)
/* get data length from raw data length code (DLC) */
unsigned char can_fd_dlc2len(unsigned char dlc)
{
return dlc2len[can_dlc & 0x0F];
return dlc2len[dlc & 0x0F];
}
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
@@ -101,7 +102,7 @@ static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
/* map the sanitized data length to an appropriate data length code */
unsigned char can_len2dlc(unsigned char len)
unsigned char can_fd_len2dlc(unsigned char len)
{
if (len > 64)
return 0xF;
@@ -195,9 +196,19 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
cf->can_id |= CAN_RTR_FLAG;
/* check for optional DLC value for CAN 2.0B frames */
if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
if(cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
cf->len = tmp;
/* check for optional raw DLC value for CAN 2.0B frames */
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
tmp = asc2nibble(cs[idx]);
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) {
struct can_frame *ccf = (struct can_frame *)cf;
ccf->len8_dlc = tmp;
}
}
}
return ret;
}
@@ -232,6 +243,17 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
}
cf->len = dlen;
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
unsigned char dlc = asc2nibble(cs[idx]);
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
struct can_frame *ccf = (struct can_frame *)cf;
ccf->len8_dlc = dlc;
}
}
return ret;
}
@@ -270,9 +292,20 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
buf[offset++] = 'R';
/* print a given CAN 2.0B DLC if it's not zero */
if (cf->len && cf->len <= CAN_MAX_DLC)
if (cf->len && cf->len <= CAN_MAX_DLEN) {
buf[offset++] = hex_asc_upper_lo(cf->len);
/* check for optional raw DLC value for CAN 2.0B frames */
if (cf->len == CAN_MAX_DLEN) {
struct can_frame *ccf = (struct can_frame *)cf;
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) {
buf[offset++] = CC_DLC_DELIM;
buf[offset++] = hex_asc_upper_lo(ccf->len8_dlc);
}
}
}
buf[offset] = 0;
return;
}
@@ -292,6 +325,17 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
buf[offset++] = '.';
}
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) {
struct can_frame *ccf = (struct can_frame *)cf;
unsigned char dlc = ccf->len8_dlc;
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
buf[offset++] = CC_DLC_DELIM;
buf[offset++] = hex_asc_upper_lo(dlc);
}
}
buf[offset] = 0;
}
@@ -337,9 +381,23 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
/* The len value is sanitized by maxdlen (see above) */
if (maxdlen == CAN_MAX_DLEN) {
buf[offset + 1] = '[';
buf[offset + 2] = len + '0';
buf[offset + 3] = ']';
if (view & CANLIB_VIEW_LEN8_DLC) {
struct can_frame *ccf = (struct can_frame *)cf;
unsigned char dlc = ccf->len8_dlc;
/* fall back to len if we don't have a valid DLC > 8 */
if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) &&
(dlc <= CAN_MAX_RAW_DLC)))
dlc = len;
buf[offset + 1] = '{';
buf[offset + 2] = hex_asc_upper[dlc];
buf[offset + 3] = '}';
} else {
buf[offset + 1] = '[';
buf[offset + 2] = len + '0';
buf[offset + 3] = ']';
}
/* standard CAN frames may have RTR enabled */
if (cf->can_id & CAN_RTR_FLAG) {
@@ -583,12 +641,12 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c
if (!sep)
sep = defsep;
for (i = 0; i < ARRAY_SIZE(error_classes); i++) {
for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
mask = 1 << i;
if (class & mask) {
if (classes)
n += snprintf(buf + n, len - n, "%s", sep);
n += snprintf(buf + n, len - n, "%s", error_classes[i]);
n += snprintf(buf + n, len - n, "%s", error_classes[i]);
if (mask == CAN_ERR_LOSTARB)
n += snprintf_error_lostarb(buf + n, len - n,
cf);
+16 -10
View File
@@ -61,11 +61,11 @@
/* CAN DLC to real data length conversion helpers especially for CAN FD */
/* get data length from can_dlc with sanitized can_dlc */
unsigned char can_dlc2len(unsigned char can_dlc);
/* get data length from raw data length code (DLC) */
unsigned char can_fd_dlc2len(unsigned char dlc);
/* map the sanitized data length to an appropriate data length code */
unsigned char can_len2dlc(unsigned char len);
unsigned char can_fd_len2dlc(unsigned char len);
unsigned char asc2nibble(char c);
/*
@@ -99,10 +99,11 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
/*
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
*
* CAN 2.0 frames
* - string layout <can_id>#{R{len}|data}
* CAN 2.0 frames (aka Classical CAN)
* - string layout <can_id>#{R{len}|data}{_len8_dlc}
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
* - {len} can take values from 0 to 8 and can be omitted if zero
* - {_len8_dlc} can take hex values from '_9' to '_F' when len is CAN_MAX_DLEN
* - return value on successful parsing: CAN_MTU
*
* CAN FD frames
@@ -124,10 +125,12 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
* 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
* 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
* 123#R8_9 -> standard CAN-Id = 0x123, len = 8, dlc = 9, RTR-frame
* 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
*
* 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
@@ -155,10 +158,11 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
* The CAN data[] is separated by '.' when sep != 0.
*
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
* maxdlen = 8 -> CAN2.0 frame
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
* maxdlen = 64 -> CAN FD frame
*
* 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14, data, sep = 0
* 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
* 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
@@ -178,6 +182,7 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
#define CANLIB_VIEW_SWAP 0x4
#define CANLIB_VIEW_ERROR 0x8
#define CANLIB_VIEW_INDENT_SFF 0x10
#define CANLIB_VIEW_LEN8_DLC 0x20
#define SWAP_DELIMITER '`'
@@ -187,14 +192,15 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
* Creates a CAN frame hexadecimal output in user readable format.
*
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
* maxdlen = 8 -> CAN2.0 frame
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
* maxdlen = 64 -> CAN FD frame
*
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, dlc = 3, data
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data
* 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR
* 14B0DC51 [8] 4A 94 E8 2A EC 58 55 62 'J..*.XUb' -> (with ASCII output)
* 321 {B} 11 22 33 44 55 66 77 88 -> Classical CAN with raw '{DLC}' value B
* 20001111 [7] C6 23 7B 32 69 98 3C ERRORFRAME -> (CAN_ERR_FLAG set)
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, dlc = 3
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, len = 3
*
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == 0
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set
@@ -204,7 +210,7 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
* // CAN FD frame with eol to STDOUT
* fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
*
* // CAN 2.0 frame without eol to STDERR
* // Classical CAN 2.0 frame without eol to STDERR
* fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN);
*
*/
+9 -9
View File
@@ -10,16 +10,16 @@
* as published by the Free Software Foundation
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <net/if.h>
@@ -53,7 +53,7 @@ static const char *libj1939_ifnam(int ifindex)
fetch_names();
for (lp = saved; lp->if_index; ++lp) {
if (lp->if_index == ifindex)
if (lp->if_index == (unsigned int)ifindex)
return lp->if_name;
}
if (cached) {
@@ -64,8 +64,8 @@ static const char *libj1939_ifnam(int ifindex)
*/
libj1939_cleanup();
return libj1939_ifnam(ifindex);
} else
return NULL;
}
return NULL;
}
/* retrieve index */
@@ -88,8 +88,8 @@ static int libj1939_ifindex(const char *str)
if (cached) {
libj1939_cleanup();
return libj1939_ifindex(str);
} else
return 0;
}
return 0;
}
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr)
+146 -35
View File
@@ -42,15 +42,15 @@
*
*/
#include <libgen.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <libgen.h>
#include <unistd.h>
#include <linux/can.h>
#include <net/if.h>
#include <sys/time.h>
#include <linux/can.h>
#include "lib.h"
@@ -60,24 +60,129 @@ extern int optind, opterr, optopt;
void print_usage(char *prg)
{
fprintf(stderr, "Usage: %s [can-interfaces]\n", prg);
fprintf(stderr, "Options: -I <infile> (default stdin)\n");
fprintf(stderr, " -O <outfile> (default stdout)\n");
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
fprintf(stderr, "%s - convert compact CAN frame logfile to ASC logfile.\n", prg);
fprintf(stderr, "Usage: %s <options> [can-interfaces]\n", prg);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -I <infile> (default stdin)\n");
fprintf(stderr, " -O <outfile> (default stdout)\n");
fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n");
fprintf(stderr, " -n (set newline to cr/lf - default lf)\n");
fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n");
fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n");
}
void can_asc(struct canfd_frame *cf, int devno, int nortrdlc, char *extra_info, FILE *outfile)
{
int i;
char id[10];
char *dir = "Rx";
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
if (cf->can_id & CAN_ERR_FLAG)
fprintf(outfile, "ErrorFrame");
else {
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
/* check for extra info */
if (strlen(extra_info) > 0) {
/* only the first char is defined so far */
if (extra_info[0] == 'T')
dir = "Tx";
}
fprintf(outfile, "%-15s %s ", id, dir);
if (cf->can_id & CAN_RTR_FLAG) {
if (nortrdlc)
fprintf(outfile, "r"); /* RTR frame */
else
fprintf(outfile, "r %d", cf->len); /* RTR frame */
} else {
fprintf(outfile, "d %d", cf->len); /* data frame */
for (i = 0; i < cf->len; i++) {
fprintf(outfile, " %02X", cf->data[i]);
}
}
}
}
void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FILE *outfile)
{
int i;
char id[10];
char *dir = "Rx";
unsigned int flags = 0;
unsigned int dlen = cf->len;
unsigned int dlc = can_fd_len2dlc(dlen);
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
/* check for extra info */
if (strlen(extra_info) > 0) {
/* only the first char is defined so far */
if (extra_info[0] == 'T')
dir = "Tx";
}
fprintf(outfile, "CANFD %3d %s ", devno, dir); /* 3 column channel number right aligned */
sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK,
(cf->can_id & CAN_EFF_FLAG)?'x':' ');
fprintf(outfile, "%11s ", id);
fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0');
fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0');
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((mtu == CAN_MTU) && (dlen == CAN_MAX_DLEN)) {
struct can_frame *ccf = (struct can_frame *)cf;
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC))
dlc = ccf->len8_dlc;
}
fprintf(outfile, "%x ", dlc);
if (mtu == CAN_MTU) {
if (cf->can_id & CAN_RTR_FLAG) {
/* no data length but dlc for RTR frames */
dlen = 0;
flags = ASC_F_RTR;
}
} else {
flags = ASC_F_FDF;
if (cf->flags & CANFD_BRS)
flags |= ASC_F_BRS;
if (cf->flags & CANFD_ESI)
flags |= ASC_F_ESI;
}
fprintf(outfile, "%2d", dlen);
for (i = 0; i < (int)dlen; i++) {
fprintf(outfile, " %02X", cf->data[i]);
}
fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags);
}
int main(int argc, char **argv)
{
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10];
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], extra_info[BUFSZ];
struct canfd_frame cf;
static struct timeval tv, start_tv;
FILE *infile = stdin;
FILE *outfile = stdout;
static int maxdev, devno, i, crlf, d4, opt;
static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu;
while ((opt = getopt(argc, argv, "I:O:4n?")) != -1) {
while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) {
switch (opt) {
case 'I':
infile = fopen(optarg, "r");
@@ -99,6 +204,14 @@ int main(int argc, char **argv)
crlf = 1;
break;
case 'f':
fdfmt = 1;
break;
case 'r':
nortrdlc = 1;
break;
case '4':
d4 = 1;
break;
@@ -137,10 +250,17 @@ int main(int argc, char **argv)
if (buf[0] != '(')
continue;
if (sscanf(buf, "(%ld.%ld) %s %s", &tv.tv_sec, &tv.tv_usec,
device, ascframe) != 4) {
fprintf(stderr, "incorrect line format in logfile\n");
return 1;
if (sscanf(buf, "(%lu.%lu) %s %s %s", &tv.tv_sec, &tv.tv_usec,
device, ascframe, extra_info) != 5) {
/* do not evaluate the extra info */
extra_info[0] = 0;
if (sscanf(buf, "(%lu.%lu) %s %s", &tv.tv_sec, &tv.tv_usec,
device, ascframe) != 4) {
fprintf(stderr, "incorrect line format in logfile\n");
return 1;
}
}
if (!start_tv.tv_sec) { /* print banner */
@@ -160,9 +280,14 @@ int main(int argc, char **argv)
}
if (devno) { /* only convert for selected CAN devices */
if (parse_canframe(ascframe, &cf) != CAN_MTU) /* no CAN FD support so far */
mtu = parse_canframe(ascframe, &cf);
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU))
return 1;
/* we don't support error message frames in CAN FD */
if ((mtu == CANFD_MTU) && (cf.can_id & CAN_ERR_FLAG))
continue;
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
tv.tv_usec = tv.tv_usec - start_tv.tv_usec;
if (tv.tv_usec < 0)
@@ -171,29 +296,15 @@ int main(int argc, char **argv)
tv.tv_sec = tv.tv_usec = 0;
if (d4)
fprintf(outfile, "%4ld.%04ld ", tv.tv_sec, tv.tv_usec/100);
fprintf(outfile, "%4lu.%04lu ", tv.tv_sec, tv.tv_usec/100);
else
fprintf(outfile, "%4ld.%06ld ", tv.tv_sec, tv.tv_usec);
fprintf(outfile, "%4lu.%06lu ", tv.tv_sec, tv.tv_usec);
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
if ((mtu == CAN_MTU) && (fdfmt == 0))
can_asc(&cf, devno, nortrdlc, extra_info, outfile);
else
canfd_asc(&cf, devno, mtu, extra_info, outfile);
if (cf.can_id & CAN_ERR_FLAG)
fprintf(outfile, "ErrorFrame");
else {
sprintf(id, "%X%c", cf.can_id & CAN_EFF_MASK,
(cf.can_id & CAN_EFF_FLAG)?'x':' ');
fprintf(outfile, "%-15s Rx ", id);
if (cf.can_id & CAN_RTR_FLAG)
fprintf(outfile, "r"); /* RTR frame */
else {
fprintf(outfile, "d %d", cf.len); /* data frame */
for (i = 0; i < cf.len; i++) {
fprintf(outfile, " %02X", cf.data[i]);
}
}
}
if (crlf)
fprintf(outfile, "\r");
fprintf(outfile, "\n");
+2 -2
View File
@@ -44,15 +44,15 @@
#include <stdio.h>
#include <net/if.h>
#include <linux/can.h>
#include <net/if.h>
#include "lib.h"
#define COMMENTSZ 200
#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
int main(int argc, char **argv)
int main(void)
{
char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
struct canfd_frame cf;
+1
View File
@@ -0,0 +1 @@
ACTION=="add", SUBSYSTEM=="devcoredump", RUN+="/usr/sbin/devcoredump"
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
timestamp=$(date +%+4Y%m%d-%H%M%S)
filename=/var/log/devcoredump-${timestamp}.dump
cat /sys/${DEVPATH}/data > ${filename}
echo 1 > /sys/${DEVPATH}/data
echo "devcoredump ${DEVPATH}" | logger
+257
View File
@@ -0,0 +1,257 @@
// SPDX-License-Identifier: GPL-2.0
//
// Microchip MCP251xFD Family CAN controller debug tool
//
// Copyright (c) 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/kernel.h>
#include "mcp251xfd.h"
#include "mcp251xfd-dump-userspace.h"
#define pr_err(fmt, args...) fprintf(stderr, fmt, ##args)
#define pr_no(fmt, args...) while (0) { fprintf(stdout, fmt, ##args); }
#ifdef DEBUG
#define pr_debug(fmt, args...) pr_err(fmt, ##args)
#else
#define pr_debug(fmt, args...) pr_no(fmt, ##args)
#endif
struct mcp251xfd_dump_iter {
const void *start;
const struct mcp251xfd_dump_object_header *hdr;
const void *object_start;
const void *object_end;
};
static __attribute__((__unused__)) const char *
get_object_type_str(enum mcp251xfd_dump_object_type object_type)
{
switch (object_type) {
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
return "reg";
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
return "tef";
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
return "rx";
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
return "tx";
case MCP251XFD_DUMP_OBJECT_TYPE_END:
return "end";
default:
return "<unknown>";
}
}
static __attribute__((__unused__)) const char *
get_ring_key_str(enum mcp251xfd_dump_object_ring_key key)
{
switch (key) {
case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD:
return "head";
case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL:
return "tail";
case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE:
return "base";
case MCP251XFD_DUMP_OBJECT_RING_KEY_NR:
return "nr";
case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR:
return "fifo-nr";
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM:
return "obj-num";
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE:
return "obj-size";
default:
return "<unknown>";
}
}
static int
do_dev_coredump_read_reg(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_iter *iter,
struct mcp251xfd_mem *mem)
{
const struct mcp251xfd_dump_object_reg *object;
for (object = iter->object_start;
(void *)(object + 1) <= iter->object_end;
object++) {
uint32_t reg, val;
reg = le32toh(object->reg);
val = le32toh(object->val);
pr_debug("%s: object=0x%04zx reg=0x%04x - val=0x%08x\n",
__func__,
(void *)object - iter->start,
reg, val);
if (reg > ARRAY_SIZE(mem->buf))
return -EINVAL;
*(uint32_t *)(mem->buf + reg) = val;
}
return 0;
}
static int
do_dev_coredump_read_ring(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_iter *iter,
struct mcp251xfd_ring *ring)
{
const struct mcp251xfd_dump_object_reg *object;
for (object = iter->object_start;
(void *)(object + 1) <= iter->object_end;
object++) {
enum mcp251xfd_dump_object_ring_key key;
uint32_t val;
key = le32toh(object->reg);
val = le32toh(object->val);
pr_debug("%s: reg=0x%04zx key=0x%02x: %8s - val=0x%08x\n",
__func__,
(void *)object - iter->start,
key, get_ring_key_str(key), val);
switch (key) {
case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD:
ring->head = val;
break;
case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL:
ring->tail = val;
break;
case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE:
ring->base = val;
break;
case MCP251XFD_DUMP_OBJECT_RING_KEY_NR:
ring->nr = val;
break;
case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR:
ring->fifo_nr = val;
break;
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM:
ring->obj_num = val;
break;
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE:
ring->obj_size = val;
break;
default:
return -EINVAL;
}
}
return 0;
}
static int
do_dev_coredump_read(struct mcp251xfd_priv *priv,
struct mcp251xfd_mem *mem,
const void *dump, size_t dump_len)
{
struct mcp251xfd_dump_iter iter[] = {
{
.start = dump,
.hdr = dump,
},
};
while ((void *)(iter->hdr + 1) <= iter->start + dump_len &&
le32toh(iter->hdr->magic) == MCP251XFD_DUMP_MAGIC) {
const struct mcp251xfd_dump_object_header *hdr = iter->hdr;
enum mcp251xfd_dump_object_type object_type;
size_t object_offset, object_len;
int err;
object_type = le32toh(hdr->type);
object_offset = le32toh(hdr->offset);
object_len = le32toh(hdr->len);
if (object_offset + object_len > dump_len)
return -EFAULT;
iter->object_start = iter->start + object_offset;
iter->object_end = iter->object_start + object_len;
pr_debug("%s: hdr=0x%04zx type=0x%08x: %8s - offset=0x%04zx len=0x%04zx end=0x%04zx\n",
__func__,
(void *)iter->hdr - iter->start,
object_type, get_object_type_str(object_type),
object_offset, object_len, object_offset + object_len);
switch (object_type) {
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
err = do_dev_coredump_read_reg(priv, iter, mem);
break;
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
err = do_dev_coredump_read_ring(priv, iter, priv->tef);
break;
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
err = do_dev_coredump_read_ring(priv, iter, priv->rx);
break;
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
err = do_dev_coredump_read_ring(priv, iter, priv->tx);
break;
case MCP251XFD_DUMP_OBJECT_TYPE_END:
return 0;
default:
return -EINVAL;
}
if (err)
return err;
iter->hdr++;
}
return -EINVAL;
}
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
struct mcp251xfd_mem *mem,
const char *dump_path)
{
struct stat statbuf;
size_t dump_len;
void *dump;
int fd, err;
fd = open(dump_path, O_RDONLY);
if (fd < 0)
return -errno;
err = fstat(fd, &statbuf);
if (err < 0) {
err = -errno;
goto out_close;
}
dump_len = statbuf.st_size;
dump = mmap(NULL, dump_len, PROT_READ, MAP_SHARED, fd, 0x0);
if (dump == MAP_FAILED) {
err = -errno;
goto out_close;
}
err = do_dev_coredump_read(priv, mem, dump, dump_len);
munmap(dump, dump_len);
out_close:
close(fd);
return err;
}
+61
View File
@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Microchip MCP251xFD Family CAN controller debug tool
*
* Copyright (c) 2019, 2020 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
*/
#ifndef _MCP251XFD_DUMP_USERSPACE_H
#define _MCP251XFD_DUMP_USERSPACE_H
#include "mcp251xfd.h"
#include "mcp251xfd-dump.h"
#define MCP251XFD_TX_FIFO 1
#define MCP251XFD_RX_FIFO(x) (MCP251XFD_TX_FIFO + 1 + (x))
struct mcp251xfd_mem {
char buf[0x1000];
};
struct mcp251xfd_ring {
unsigned int head;
unsigned int tail;
u16 base;
u8 nr;
u8 fifo_nr;
u8 obj_num;
u8 obj_size;
};
struct mcp251xfd_priv {
struct regmap *map;
struct mcp251xfd_ring tef[1];
struct mcp251xfd_ring tx[1];
struct mcp251xfd_ring rx[1];
u8 rx_ring_num;
};
static inline u8 mcp251xfd_get_ring_head(const struct mcp251xfd_ring *ring)
{
return ring->head & (ring->obj_num - 1);
}
static inline u8 mcp251xfd_get_ring_tail(const struct mcp251xfd_ring *ring)
{
return ring->tail & (ring->obj_num - 1);
}
void mcp251xfd_dump(struct mcp251xfd_priv *priv);
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
struct mcp251xfd_mem *mem,
const char *file_path);
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
struct mcp251xfd_mem *mem,
const char *file_path);
#endif
+863
View File
@@ -0,0 +1,863 @@
// SPDX-License-Identifier: GPL-2.0
//
// Microchip MCP251xFD Family CAN controller debug tool
//
// Copyright (c) 2019, 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
#include <linux/kernel.h>
#include "mcp251xfd-dump-userspace.h"
struct mcp251xfd_dump_regs_fifo {
u32 con;
u32 sta;
u32 ua;
};
struct mcp251xfd_dump_regs_filter {
u32 obj;
u32 mask;
};
struct mcp251xfd_dump_regs {
u32 con;
u32 nbtcfg;
u32 dbtcfg;
u32 tdc;
u32 tbc;
u32 tscon;
u32 vec;
u32 intf;
u32 rxif;
u32 txif;
u32 rxovif;
u32 txatif;
u32 txreq;
u32 trec;
u32 bdiag0;
u32 bdiag1;
union {
struct {
u32 tefcon;
u32 tefsta;
u32 tefua;
};
struct mcp251xfd_dump_regs_fifo tef;
};
u32 reserved0;
union {
struct {
struct mcp251xfd_dump_regs_fifo txq;
struct mcp251xfd_dump_regs_fifo tx_fifo;
struct mcp251xfd_dump_regs_fifo rx_fifo;
};
struct mcp251xfd_dump_regs_fifo fifo[32];
};
u32 fltcon[8];
struct mcp251xfd_dump_regs_filter filter[32];
};
struct mcp251xfd_dump_ram {
u8 ram[MCP251XFD_RAM_SIZE];
};
struct mcp251xfd_dump_regs_mcp251xfd {
u32 osc;
u32 iocon;
u32 crc;
u32 ecccon;
u32 eccstat;
u32 devid;
};
#define __dump_bit(val, prefix, bit, desc) \
pr_info("%16s %s\t\t%s\n", __stringify(bit), \
(val) & prefix##_##bit ? "x" : " ", desc)
#define __dump_mask(val, prefix, mask, fmt, desc) \
pr_info("%16s = " fmt "\t\t%s\n", \
__stringify(mask), \
FIELD_GET(prefix##_##mask##_MASK, (val)), \
desc)
static void mcp251xfd_dump_reg_con(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("CON: con(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_CON, TXBWS, "0x%02lx", "Transmit Bandwidth Sharing");
__dump_bit(val, MCP251XFD_REG_CON, ABAT, "Abort All Pending Transmissions");
__dump_mask(val, MCP251XFD_REG_CON, REQOP, "0x%02lx", "Request Operation Mode");
__dump_mask(val, MCP251XFD_REG_CON, OPMOD, "0x%02lx", "Operation Mode Status");
__dump_bit(val, MCP251XFD_REG_CON, TXQEN, "Enable Transmit Queue");
__dump_bit(val, MCP251XFD_REG_CON, STEF, "Store in Transmit Event FIFO");
__dump_bit(val, MCP251XFD_REG_CON, SERR2LOM, "Transition to Listen Only Mode on System Error");
__dump_bit(val, MCP251XFD_REG_CON, ESIGM, "Transmit ESI in Gateway Mode");
__dump_bit(val, MCP251XFD_REG_CON, RTXAT, "Restrict Retransmission Attempts");
__dump_bit(val, MCP251XFD_REG_CON, BRSDIS, "Bit Rate Switching Disable");
__dump_bit(val, MCP251XFD_REG_CON, BUSY, "CAN Module is Busy");
__dump_mask(val, MCP251XFD_REG_CON, WFT, "0x%02lx", "Selectable Wake-up Filter Time");
__dump_bit(val, MCP251XFD_REG_CON, WAKFIL, "Enable CAN Bus Line Wake-up Filter");
__dump_bit(val, MCP251XFD_REG_CON, PXEDIS, "Protocol Exception Event Detection Disabled");
__dump_bit(val, MCP251XFD_REG_CON, ISOCRCEN, "Enable ISO CRC in CAN FD Frames");
__dump_mask(val, MCP251XFD_REG_CON, DNCNT, "0x%02lx", "Device Net Filter Bit Number");
}
static void mcp251xfd_dump_reg_nbtcfg(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("NBTCFG: nbtcfg(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_NBTCFG, BRP, "%3lu", "Baud Rate Prescaler");
__dump_mask(val, MCP251XFD_REG_NBTCFG, TSEG1, "%3lu", "Time Segment 1 (Propagation Segment + Phase Segment 1)");
__dump_mask(val, MCP251XFD_REG_NBTCFG, TSEG2, "%3lu", "Time Segment 2 (Phase Segment 2)");
__dump_mask(val, MCP251XFD_REG_NBTCFG, SJW, "%3lu", "Synchronization Jump Width");
}
static void mcp251xfd_dump_reg_dbtcfg(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("DBTCFG: dbtcfg(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_DBTCFG, BRP, "%3lu", "Baud Rate Prescaler");
__dump_mask(val, MCP251XFD_REG_DBTCFG, TSEG1, "%3lu", "Time Segment 1 (Propagation Segment + Phase Segment 1)");
__dump_mask(val, MCP251XFD_REG_DBTCFG, TSEG2, "%3lu", "Time Segment 2 (Phase Segment 2)");
__dump_mask(val, MCP251XFD_REG_DBTCFG, SJW, "%3lu", "Synchronization Jump Width");
}
static void mcp251xfd_dump_reg_tdc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("TDC: tdc(0x%03x)=0x%08x\n", addr, val);
__dump_bit(val, MCP251XFD_REG_TDC, EDGFLTEN, "Enable Edge Filtering during Bus Integration state");
__dump_bit(val, MCP251XFD_REG_TDC, SID11EN, "Enable 12-Bit SID in CAN FD Base Format Messages");
__dump_mask(val, MCP251XFD_REG_TDC, TDCMOD, "0x%02lx", "Transmitter Delay Compensation Mode");
__dump_mask(val, MCP251XFD_REG_TDC, TDCO, "0x%02lx", "Transmitter Delay Compensation Offset");
__dump_mask(val, MCP251XFD_REG_TDC, TDCV, "0x%02lx", "Transmitter Delay Compensation Value");
}
static void mcp251xfd_dump_reg_tbc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("TBC: tbc(0x%03x)=0x%08x\n", addr, val);
}
static void mcp251xfd_dump_reg_vec(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
u8 rx_code, tx_code, i_code;
pr_info("VEC: vec(0x%03x)=0x%08x\n", addr, val);
rx_code = FIELD_GET(MCP251XFD_REG_VEC_RXCODE_MASK, val);
tx_code = FIELD_GET(MCP251XFD_REG_VEC_TXCODE_MASK, val);
i_code = FIELD_GET(MCP251XFD_REG_VEC_ICODE_MASK, val);
pr_info("\trxcode: ");
if (rx_code == 0x40)
pr_cont("No Interrupt");
else if (rx_code < 0x20)
pr_cont("FIFO %u", rx_code);
else
pr_cont("Reserved");
pr_cont(" (0x%02x)\n", rx_code);
pr_info("\ttxcode: ");
if (tx_code == 0x40)
pr_cont("No Interrupt");
else if (tx_code < 0x20)
pr_cont("FIFO %u", tx_code);
else
pr_cont("Reserved");
pr_cont(" (0x%02x)\n", tx_code);
pr_info("\ticode: ");
if (i_code == 0x4a)
pr_cont("Transmit Attempt Interrupt");
else if (i_code == 0x49)
pr_cont("Transmit Event FIFO Interrupt");
else if (i_code == 0x48)
pr_cont("Invalid Message Occurred");
else if (i_code == 0x47)
pr_cont("Operation Mode Changed");
else if (i_code == 0x46)
pr_cont("TBC Overflow");
else if (i_code == 0x45)
pr_cont("RX/TX MAB Overflow/Underflow");
else if (i_code == 0x44)
pr_cont("Address Error Interrupt");
else if (i_code == 0x43)
pr_cont("Receive FIFO Overflow Interrupt");
else if (i_code == 0x42)
pr_cont("Wake-up Interrupt");
else if (i_code == 0x41)
pr_cont("Error Interrupt");
else if (i_code == 0x40)
pr_cont("No Interrupt");
else if (i_code < 0x20)
pr_cont("FIFO %u", i_code);
else
pr_cont("Reserved");
pr_cont(" (0x%02x)\n", i_code);
}
#define __dump_int(val, bit, desc) \
pr_info("\t" __stringify(bit) "\t%s\t%s\t%s\t%s\n", \
(val) & MCP251XFD_REG_INT_##bit##E ? "x" : "", \
(val) & MCP251XFD_REG_INT_##bit##F ? "x" : "", \
FIELD_GET(MCP251XFD_REG_INT_IF_MASK, val) & \
FIELD_GET(MCP251XFD_REG_INT_IE_MASK, val) & \
MCP251XFD_REG_INT_##bit##F ? "x" : "", \
desc)
static void mcp251xfd_dump_reg_intf(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("INT: intf(0x%03x)=0x%08x\n", addr, val);
pr_info("\t\tIE\tIF\tIE & IF\n");
__dump_int(val, IVMI, "Invalid Message Interrupt");
__dump_int(val, WAKI, "Bus Wake Up Interrupt");
__dump_int(val, CERRI, "CAN Bus Error Interrupt");
__dump_int(val, SERRI, "System Error Interrupt");
__dump_int(val, RXOVI, "Receive FIFO Overflow Interrupt");
__dump_int(val, TXATI, "Transmit Attempt Interrupt");
__dump_int(val, SPICRCI, "SPI CRC Error Interrupt");
__dump_int(val, ECCI, "ECC Error Interrupt");
__dump_int(val, TEFI, "Transmit Event FIFO Interrupt");
__dump_int(val, MODI, "Mode Change Interrupt");
__dump_int(val, TBCI, "Time Base Counter Interrupt");
__dump_int(val, RXI, "Receive FIFO Interrupt");
__dump_int(val, TXI, "Transmit FIFO Interrupt");
}
#undef __dump_int
#define __create_dump_fifo_bitmask(fifo, name, description) \
static void mcp251xfd_dump_reg_##fifo(const struct mcp251xfd_priv *priv, u32 val, u16 addr) \
{ \
int i; \
\
pr_info(__stringify(name) ": " __stringify(fifo) "(0x%03x)=0x%08x\n", addr, val); \
pr_info(description ":\n"); \
if (!val) { \
pr_info("\t\t-none-\n"); \
return; \
} \
\
pr_info("\t\t"); \
for (i = 0; i < sizeof(val); i++) { \
if (val & BIT(i)) \
pr_cont("%d ", i); \
} \
\
pr_cont("\n"); \
}
__create_dump_fifo_bitmask(rxif, RXIF, "Receive FIFO Interrupt Pending");
__create_dump_fifo_bitmask(rxovif, RXOVIF, "Receive FIFO Overflow Interrupt Pending");
__create_dump_fifo_bitmask(txif, TXIF, "Transmit FIFO Interrupt Pending");
__create_dump_fifo_bitmask(txatif, TXATIF, "Transmit FIFO Attempt Interrupt Pending");
__create_dump_fifo_bitmask(txreq, TXREQ, "Message Send Request");
#undef __create_dump_fifo_bitmask
static void mcp251xfd_dump_reg_trec(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("TREC: trec(0x%03x)=0x%08x\n", addr, val);
__dump_bit(val, MCP251XFD_REG_TREC, TXBO, "Transmitter in Bus Off State");
__dump_bit(val, MCP251XFD_REG_TREC, TXBP, "Transmitter in Error Passive State");
__dump_bit(val, MCP251XFD_REG_TREC, RXBP, "Receiver in Error Passive State");
__dump_bit(val, MCP251XFD_REG_TREC, TXWARN, "Transmitter in Error Warning State");
__dump_bit(val, MCP251XFD_REG_TREC, RXWARN, "Receiver in Error Warning State");
__dump_bit(val, MCP251XFD_REG_TREC, EWARN, "Transmitter or Receiver is in Error Warning State");
__dump_mask(val, MCP251XFD_REG_TREC, TEC, "%3lu", "Transmit Error Counter");
__dump_mask(val, MCP251XFD_REG_TREC, REC, "%3lu", "Receive Error Counter");
}
static void mcp251xfd_dump_reg_bdiag0(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("BDIAG0: bdiag0(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_BDIAG0, DTERRCNT, "%3lu", "Data Bit Rate Transmit Error Counter");
__dump_mask(val, MCP251XFD_REG_BDIAG0, DRERRCNT, "%3lu", "Data Bit Rate Receive Error Counter");
__dump_mask(val, MCP251XFD_REG_BDIAG0, NTERRCNT, "%3lu", "Nominal Bit Rate Transmit Error Counter");
__dump_mask(val, MCP251XFD_REG_BDIAG0, NRERRCNT, "%3lu", "Nominal Bit Rate Receive Error Counter");
}
static void mcp251xfd_dump_reg_bdiag1(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("BDIAG1: bdiag1(0x%03x)=0x%08x\n", addr, val);
__dump_bit(val, MCP251XFD_REG_BDIAG1, DLCMM, "DLC Mismatch");
__dump_bit(val, MCP251XFD_REG_BDIAG1, ESI, "ESI flag of a received CAN FD message was set");
__dump_bit(val, MCP251XFD_REG_BDIAG1, DCRCERR, "Data CRC Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, DSTUFERR, "Data Bit Stuffing Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, DFORMERR, "Data Format Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, DBIT1ERR, "Data BIT1 Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, DBIT0ERR, "Data BIT0 Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, TXBOERR, "Device went to bus-off (and auto-recovered)");
__dump_bit(val, MCP251XFD_REG_BDIAG1, NCRCERR, "CRC Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, NSTUFERR, "Bit Stuffing Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, NFORMERR, "Format Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, NACKERR, "Transmitted message was not acknowledged");
__dump_bit(val, MCP251XFD_REG_BDIAG1, NBIT1ERR, "Bit1 Error");
__dump_bit(val, MCP251XFD_REG_BDIAG1, NBIT0ERR, "Bit0 Error");
__dump_mask(val, MCP251XFD_REG_BDIAG1, EFMSGCNT, "%3lu", "Error Free Message Counter");
}
static void mcp251xfd_dump_reg_osc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("OSC: osc(0x%03x)=0x%08x\n", addr, val);
__dump_bit(val, MCP251XFD_REG_OSC, SCLKRDY, "Synchronized SCLKDIV");
__dump_bit(val, MCP251XFD_REG_OSC, OSCRDY, "Clock Ready");
__dump_bit(val, MCP251XFD_REG_OSC, PLLRDY, "PLL Ready");
__dump_mask(val, MCP251XFD_REG_OSC, CLKODIV, "0x%02lu", "Clock Output Divisor");
__dump_bit(val, MCP251XFD_REG_OSC, SCLKDIV, "System Clock Divisor");
__dump_bit(val, MCP251XFD_REG_OSC, LPMEN, "Low Power Mode (LPM) Enable (MCP2518FD only)");
__dump_bit(val, MCP251XFD_REG_OSC, OSCDIS, "Clock (Oscillator) Disable");
__dump_bit(val, MCP251XFD_REG_OSC, PLLEN, "PLL Enable");
}
static void mcp251xfd_dump_reg_tefcon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("TEFCON: tefcon(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_TEFCON, FSIZE, "%3lu", "FIFO Size");
__dump_bit(val, MCP251XFD_REG_TEFCON, FRESET, "FIFO Reset");
__dump_bit(val, MCP251XFD_REG_TEFCON, UINC, "Increment Tail");
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFTSEN, "Transmit Event FIFO Time Stamp Enable");
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFOVIE, "Transmit Event FIFO Overflow Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFFIE, "Transmit Event FIFO Full Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFHIE, "Transmit Event FIFO Half Full Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFNEIE, "Transmit Event FIFO Not Empty Interrupt Enable");
}
static void mcp251xfd_dump_reg_tefsta(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("TEFSTA: tefsta(0x%03x)=0x%08x\n", addr, val);
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFOVIF, "Transmit Event FIFO Overflow Interrupt Flag");
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFFIF, "Transmit Event FIFO Full Interrupt Flag (0: not full)");
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFHIF, "Transmit Event FIFO Half Full Interrupt Flag (0: < half full)");
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFNEIF, "Transmit Event FIFO Not Empty Interrupt Flag (0: empty)");
}
static void mcp251xfd_dump_reg_tefua(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("TEFUA: tefua(0x%03x)=0x%08x\n", addr, val);
}
static void mcp251xfd_dump_reg_fifocon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("FIFOCON: fifocon(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_FIFOCON, PLSIZE, "%3lu", "Payload Size");
__dump_mask(val, MCP251XFD_REG_FIFOCON, FSIZE, "%3lu", "FIFO Size");
__dump_mask(val, MCP251XFD_REG_FIFOCON, TXAT, "%3lu", "Retransmission Attempts");
__dump_mask(val, MCP251XFD_REG_FIFOCON, TXPRI, "%3lu", "Message Transmit Priority");
__dump_bit(val, MCP251XFD_REG_FIFOCON, FRESET, "FIFO Reset");
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXREQ, "Message Send Request");
__dump_bit(val, MCP251XFD_REG_FIFOCON, UINC, "Increment Head/Tail");
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXEN, "TX/RX FIFO Selection (0: RX, 1: TX)");
__dump_bit(val, MCP251XFD_REG_FIFOCON, RTREN, "Auto RTR Enable");
__dump_bit(val, MCP251XFD_REG_FIFOCON, RXTSEN, "Received Message Time Stamp Enable");
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXATIE, "Transmit Attempts Exhausted Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_FIFOCON, RXOVIE, "Overflow Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFERFFIE, "Transmit/Receive FIFO Empty/Full Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFHRFHIE, "Transmit/Receive FIFO Half Empty/Half Full Interrupt Enable");
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFNRFNIE, "Transmit/Receive FIFO Not Full/Not Empty Interrupt Enable");
}
static void mcp251xfd_dump_reg_fifosta(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("FIFOSTA: fifosta(0x%03x)=0x%08x\n", addr, val);
__dump_mask(val, MCP251XFD_REG_FIFOSTA, FIFOCI, "%3lu", "FIFO Message Index");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXABT, "Message Aborted Status (0: completed successfully, 1: aborted)");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXLARB, "Message Lost Arbitration Status");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXERR, "Error Detected During Transmission");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXATIF, "Transmit Attempts Exhausted Interrupt Pending");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, RXOVIF, "Receive FIFO Overflow Interrupt Flag");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFERFFIF, "Transmit/Receive FIFO Empty/Full Interrupt Flag");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFHRFHIF, "Transmit/Receive FIFO Half Empty/Half Full Interrupt Flag");
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFNRFNIF, "Transmit/Receive FIFO Not Full/Not Empty Interrupt Flag");
}
static void mcp251xfd_dump_reg_fifoua(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
{
pr_info("FIFOUA: fifoua(0x%03x)=0x%08x\n", addr, val);
}
#define __dump_call(regs, val) \
do { \
mcp251xfd_dump_reg_##val(priv, (regs)->val, \
(u16)(offsetof(typeof(*(regs)), val) + \
(sizeof(*(regs)) == sizeof(struct mcp251xfd_dump_regs) ? \
0 : MCP251XFD_REG_OSC))); \
pr_info("\n"); \
} while (0)
#define __dump_call_fifo(reg, val) \
do { \
mcp251xfd_dump_reg_##reg(priv, regs->val, (u16)offsetof(typeof(*regs), val)); \
pr_info("\n"); \
} while (0)
static void
mcp251xfd_dump_regs(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_dump_regs_mcp251xfd *regs_mcp251xfd)
{
netdev_info(priv->ndev, "-------------------- register dump --------------------\n");
__dump_call(regs, con);
__dump_call(regs, nbtcfg);
__dump_call(regs, dbtcfg);
__dump_call(regs, tdc);
__dump_call(regs, tbc);
__dump_call(regs, vec);
__dump_call(regs, intf);
__dump_call(regs, rxif);
__dump_call(regs, rxovif);
__dump_call(regs, txif);
__dump_call(regs, txatif);
__dump_call(regs, txreq);
__dump_call(regs, trec);
__dump_call(regs, bdiag0);
__dump_call(regs, bdiag1);
__dump_call(regs_mcp251xfd, osc);
pr_info("-------------------- TEF --------------------\n");
__dump_call(regs, tefcon);
__dump_call(regs, tefsta);
__dump_call(regs, tefua);
pr_info("-------------------- TX_FIFO --------------------\n");
__dump_call_fifo(fifocon, fifo[MCP251XFD_TX_FIFO].con);
__dump_call_fifo(fifosta, fifo[MCP251XFD_TX_FIFO].sta);
__dump_call_fifo(fifoua, fifo[MCP251XFD_TX_FIFO].ua);
pr_info(" -------------------- RX_FIFO --------------------\n");
__dump_call_fifo(fifocon, fifo[MCP251XFD_RX_FIFO(0)].con);
__dump_call_fifo(fifosta, fifo[MCP251XFD_RX_FIFO(0)].sta);
__dump_call_fifo(fifoua, fifo[MCP251XFD_RX_FIFO(0)].ua);
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
}
#undef __dump_call
#undef __dump_call_fifo
static u8 mcp251xfd_dump_get_fifo_size(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
{
u8 obj_size;
obj_size = FIELD_GET(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, fifo_con);
switch (obj_size) {
case MCP251XFD_REG_FIFOCON_PLSIZE_8:
return 8;
case MCP251XFD_REG_FIFOCON_PLSIZE_12:
return 12;
case MCP251XFD_REG_FIFOCON_PLSIZE_16:
return 16;
case MCP251XFD_REG_FIFOCON_PLSIZE_20:
return 20;
case MCP251XFD_REG_FIFOCON_PLSIZE_24:
return 24;
case MCP251XFD_REG_FIFOCON_PLSIZE_32:
return 32;
case MCP251XFD_REG_FIFOCON_PLSIZE_48:
return 48;
case MCP251XFD_REG_FIFOCON_PLSIZE_64:
return 64;
}
return 0;
}
static u8 mcp251xfd_dump_get_fifo_obj_num(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
{
u8 obj_num;
obj_num = FIELD_GET(MCP251XFD_REG_FIFOCON_FSIZE_MASK, fifo_con);
return obj_num + 1;
}
static void mcp251xfd_dump_ram_fifo_obj_data(const struct mcp251xfd_priv *priv, const u8 *data, u8 dlc)
{
int i;
u8 len;
len = can_dlc2len(get_canfd_dlc(dlc));
if (!len) {
pr_info("%16s = -none-\n", "data");
return;
}
for (i = 0; i < len; i++) {
if ((i % 8) == 0) {
if (i == 0)
pr_info("%16s = %02x", "data", data[i]);
else
pr_info(" %02x", data[i]);
} else if ((i % 4) == 0) {
pr_cont(" %02x", data[i]);
} else if ((i % 8) == 7) {
pr_cont(" %02x\n", data[i]);
} else {
pr_cont(" %02x", data[i]);
}
}
if (i % 8)
pr_cont("\n");
}
/* TEF */
static u8
mcp251xfd_dump_get_tef_obj_num(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tef.con);
}
static u8
mcp251xfd_dump_get_tef_tail(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return regs->tefua / sizeof(struct mcp251xfd_hw_tef_obj);
}
static u16
mcp251xfd_dump_get_tef_obj_rel_addr(const struct mcp251xfd_priv *priv,
u8 n)
{
return sizeof(struct mcp251xfd_hw_tef_obj) * n;
}
static u16
mcp251xfd_dump_get_tef_obj_addr(const struct mcp251xfd_priv *priv,
u8 n)
{
return mcp251xfd_dump_get_tef_obj_rel_addr(priv, n) +
MCP251XFD_RAM_START;
}
/* TX */
static u8
mcp251xfd_dump_get_tx_obj_size(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return sizeof(struct mcp251xfd_hw_tx_obj_can) -
sizeof_field(struct mcp251xfd_hw_tx_obj_can, data) +
mcp251xfd_dump_get_fifo_size(priv, regs, regs->tx_fifo.con);
}
static u8
mcp251xfd_dump_get_tx_obj_num(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tx_fifo.con);
}
static u16
mcp251xfd_dump_get_tx_obj_rel_addr(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
u8 n)
{
return mcp251xfd_dump_get_tef_obj_rel_addr(priv, mcp251xfd_dump_get_tef_obj_num(priv, regs)) +
mcp251xfd_dump_get_tx_obj_size(priv, regs) * n;
}
static u16
mcp251xfd_dump_get_tx_obj_addr(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs, u8 n)
{
return mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, n) +
MCP251XFD_RAM_START;
}
static u8
mcp251xfd_dump_get_tx_tail(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return (regs->fifo[MCP251XFD_TX_FIFO].ua -
mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, 0)) /
mcp251xfd_dump_get_tx_obj_size(priv, regs);
}
static u8
mcp251xfd_dump_get_tx_head(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK,
regs->fifo[MCP251XFD_TX_FIFO].sta);
}
/* RX */
static u8
mcp251xfd_dump_get_rx_obj_size(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return sizeof(struct mcp251xfd_hw_rx_obj_can) -
sizeof_field(struct mcp251xfd_hw_rx_obj_can, data) +
mcp251xfd_dump_get_fifo_size(priv, regs, regs->rx_fifo.con);
}
static u8
mcp251xfd_dump_get_rx_obj_num(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->rx_fifo.con);
}
static u16
mcp251xfd_dump_get_rx_obj_rel_addr(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs, u8 n)
{
return mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, mcp251xfd_dump_get_tx_obj_num(priv, regs)) +
mcp251xfd_dump_get_rx_obj_size(priv, regs) * n;
}
static u16
mcp251xfd_dump_get_rx_obj_addr(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs, u8 n)
{
return mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, n) + MCP251XFD_RAM_START;
}
static u8
mcp251xfd_dump_get_rx_tail(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return (regs->fifo[MCP251XFD_RX_FIFO(0)].ua -
mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, 0)) /
mcp251xfd_dump_get_rx_obj_size(priv, regs);
}
static u8
mcp251xfd_dump_get_rx_head(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs)
{
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, regs->fifo[MCP251XFD_RX_FIFO(0)].sta);
}
/* dump TEF */
static void
mcp251xfd_dump_ram_tef_obj_one(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_ring *tef,
const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
u8 n)
{
pr_info("TEF Object: 0x%02x (0x%03x)%s%s%s%s%s\n",
n, mcp251xfd_dump_get_tef_obj_addr(priv, n),
mcp251xfd_get_ring_head(tef) == n ? " priv-HEAD" : "",
mcp251xfd_dump_get_tef_tail(priv, regs) == n ? " chip-TAIL" : "",
mcp251xfd_get_ring_tail(tef) == n ? " priv-TAIL" : "",
(mcp251xfd_dump_get_tef_tail(priv, regs) == n ?
((regs->tef.sta & MCP251XFD_REG_TEFSTA_TEFFIF) ? " chip-FIFO-full" :
!(regs->tef.sta & MCP251XFD_REG_TEFSTA_TEFNEIF) ? " chip-FIFO-empty" : "") :
("")),
(mcp251xfd_get_ring_head(tef) == mcp251xfd_get_ring_tail(tef) &&
mcp251xfd_get_ring_tail(tef) == n ?
(priv->tef->head == priv->tef->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
("")));
pr_info("%16s = 0x%08x\n", "id", hw_tef_obj->id);
pr_info("%16s = 0x%08x\n", "flags", hw_tef_obj->flags);
pr_info("%16s = 0x%08x\n", "ts", hw_tef_obj->ts);
__dump_mask(hw_tef_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ, "0x%06lx", "Sequence");
pr_info("\n");
}
static void
mcp251xfd_dump_ram_tef_obj(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_dump_ram *ram,
const struct mcp251xfd_ring *tef)
{
int i;
pr_info("\nTEF Overview:\n");
pr_info("%16s = 0x%02x 0x%08x\n", "head (p)",
mcp251xfd_get_ring_head(tef),
tef->head);
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
mcp251xfd_dump_get_tef_tail(priv, regs),
mcp251xfd_get_ring_tail(tef),
tef->tail);
pr_info("\n");
for (i = 0; i < mcp251xfd_dump_get_tef_obj_num(priv, regs); i++) {
const struct mcp251xfd_hw_tef_obj *hw_tef_obj;
u16 hw_tef_obj_rel_addr;
hw_tef_obj_rel_addr = mcp251xfd_dump_get_tef_obj_rel_addr(priv, i);
hw_tef_obj = (const struct mcp251xfd_hw_tef_obj *)&ram->ram[hw_tef_obj_rel_addr];
mcp251xfd_dump_ram_tef_obj_one(priv, regs, tef, hw_tef_obj, i);
}
}
/* dump TX */
static void
mcp251xfd_dump_ram_tx_obj_one(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_ring *tx,
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj,
u8 n)
{
pr_info("TX Object: 0x%02x (0x%03x)%s%s%s%s%s%s\n",
n, mcp251xfd_dump_get_tx_obj_addr(priv, regs, n),
mcp251xfd_dump_get_tx_head(priv, regs) == n ? " chip-HEAD" : "",
mcp251xfd_get_ring_head(tx) == n ? " priv-HEAD" : "",
mcp251xfd_dump_get_tx_tail(priv, regs) == n ? " chip-TAIL" : "",
mcp251xfd_get_ring_tail(tx) == n ? " priv-TAIL" : "",
mcp251xfd_dump_get_tx_tail(priv, regs) == n ?
(!(regs->tx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF) ? " chip-FIFO-full" :
(regs->tx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFERFFIF) ? " chip-FIFO-empty" : "") :
(""),
(mcp251xfd_get_ring_head(tx) == mcp251xfd_get_ring_tail(tx) &&
mcp251xfd_get_ring_tail(tx) == n ?
(tx->head == tx->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
("")));
pr_info("%16s = 0x%08x\n", "id", hw_tx_obj->id);
pr_info("%16s = 0x%08x\n", "flags", hw_tx_obj->flags);
__dump_mask(hw_tx_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ_MCP2517FD, "0x%06lx", "Sequence (MCP2517)");
__dump_mask(hw_tx_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ_MCP2518FD, "0x%06lx", "Sequence (MCP2518)");
mcp251xfd_dump_ram_fifo_obj_data(priv,
hw_tx_obj->data,
FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_tx_obj->flags));
pr_info("\n");
}
static void
mcp251xfd_dump_ram_tx_obj(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_dump_ram *ram,
const struct mcp251xfd_ring *tx)
{
int i;
pr_info("\nTX Overview:\n");
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/p)",
mcp251xfd_dump_get_tx_head(priv, regs),
mcp251xfd_get_ring_head(tx),
tx->head);
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
mcp251xfd_dump_get_tx_tail(priv, regs),
mcp251xfd_get_ring_tail(tx),
tx->tail);
pr_info("\n");
for (i = 0; i < mcp251xfd_dump_get_tx_obj_num(priv, regs); i++) {
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj;
u16 hw_tx_obj_rel_addr;
hw_tx_obj_rel_addr = mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, i);
hw_tx_obj = (const struct mcp251xfd_hw_tx_obj_canfd *)&ram->ram[hw_tx_obj_rel_addr];
mcp251xfd_dump_ram_tx_obj_one(priv, regs, tx, hw_tx_obj, i);
}
}
/* dump RX */
static void
mcp251xfd_dump_ram_rx_obj_one(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_ring *rx,
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
u8 n)
{
pr_info("RX Object: 0x%02x (0x%03x)%s%s%s%s%s%s\n",
n, mcp251xfd_dump_get_rx_obj_addr(priv, regs, n),
mcp251xfd_dump_get_rx_head(priv, regs) == n ? " chip-HEAD" : "",
mcp251xfd_get_ring_head(rx) == n ? " priv-HEAD" : "",
mcp251xfd_dump_get_rx_tail(priv, regs) == n ? " chip-TAIL" : "",
mcp251xfd_get_ring_tail(rx) == n ? " priv-TAIL" : "",
mcp251xfd_dump_get_rx_tail(priv, regs) == n ?
((regs->rx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFERFFIF) ? " chip-FIFO-full" :
!(regs->rx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF) ? " chip-FIFO-empty" : "") :
(""),
(mcp251xfd_get_ring_head(rx) == mcp251xfd_get_ring_tail(rx) &&
mcp251xfd_get_ring_tail(rx) == n ?
(priv->rx->head == priv->rx->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
("")));
pr_info("%16s = 0x%08x\n", "id", hw_rx_obj->id);
pr_info("%16s = 0x%08x\n", "flags", hw_rx_obj->flags);
pr_info("%16s = 0x%08x\n", "ts", hw_rx_obj->ts);
mcp251xfd_dump_ram_fifo_obj_data(priv, hw_rx_obj->data, FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags));
pr_info("\n");
}
static void
mcp251xfd_dump_ram_rx_obj(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_dump_regs *regs,
const struct mcp251xfd_dump_ram *ram,
const struct mcp251xfd_ring *rx)
{
int i;
pr_info("\nRX Overview:\n");
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/p)",
mcp251xfd_dump_get_rx_head(priv, regs),
mcp251xfd_get_ring_head(rx), rx->head);
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
mcp251xfd_dump_get_rx_tail(priv, regs),
mcp251xfd_get_ring_tail(rx), rx->tail);
pr_info("\n");
for (i = 0; i < mcp251xfd_dump_get_rx_obj_num(priv, regs); i++) {
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj;
u16 hw_rx_obj_rel_addr;
hw_rx_obj_rel_addr = mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, i);
hw_rx_obj = (const struct mcp251xfd_hw_rx_obj_canfd *)&ram->ram[hw_rx_obj_rel_addr];
mcp251xfd_dump_ram_rx_obj_one(priv, regs, rx, hw_rx_obj, i);
}
}
#undef __dump_mask
#undef __dump_bit
static void mcp251xfd_dump_ram(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, const struct mcp251xfd_dump_ram *ram)
{
netdev_info(priv->ndev, "----------------------- RAM dump ----------------------\n");
mcp251xfd_dump_ram_tef_obj(priv, regs, ram, priv->tef);
mcp251xfd_dump_ram_tx_obj(priv, regs, ram, priv->tx);
mcp251xfd_dump_ram_rx_obj(priv, regs, ram, priv->rx);
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
}
void mcp251xfd_dump(struct mcp251xfd_priv *priv)
{
struct mcp251xfd_dump_regs regs;
struct mcp251xfd_dump_ram ram;
struct mcp251xfd_dump_regs_mcp251xfd regs_mcp251xfd;
int err;
BUILD_BUG_ON(sizeof(struct mcp251xfd_dump_regs) !=
MCP251XFD_REG_FIFOUA(31) - MCP251XFD_REG_CON + 4);
err = regmap_bulk_read(priv->map, MCP251XFD_REG_CON,
&regs, sizeof(regs) / sizeof(u32));
if (err)
return;
err = regmap_bulk_read(priv->map, MCP251XFD_RAM_START,
&ram, sizeof(ram) / sizeof(u32));
if (err)
return;
err = regmap_bulk_read(priv->map, MCP251XFD_REG_OSC,
&regs_mcp251xfd, sizeof(regs_mcp251xfd) / sizeof(u32));
if (err)
return;
mcp251xfd_dump_regs(priv, &regs, &regs_mcp251xfd);
mcp251xfd_dump_ram(priv, &regs, &ram);
}
+45
View File
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
*
* Copyright (c) 2019, 2020, 2021 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
*/
#ifndef _MCP251XFD_DUMP_H
#define _MCP251XFD_DUMP_H
#define MCP251XFD_DUMP_MAGIC 0x1825434d
enum mcp251xfd_dump_object_type {
MCP251XFD_DUMP_OBJECT_TYPE_REG,
MCP251XFD_DUMP_OBJECT_TYPE_TEF,
MCP251XFD_DUMP_OBJECT_TYPE_RX,
MCP251XFD_DUMP_OBJECT_TYPE_TX,
MCP251XFD_DUMP_OBJECT_TYPE_END = -1,
};
enum mcp251xfd_dump_object_ring_key {
MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
__MCP251XFD_DUMP_OBJECT_RING_KEY_MAX,
};
struct mcp251xfd_dump_object_header {
__le32 magic;
__le32 type;
__le32 offset;
__le32 len;
};
struct mcp251xfd_dump_object_reg {
__le32 reg;
__le32 val;
};
#endif
+96
View File
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0
//
// Microchip MCP251xFD Family CAN controller debug tool
//
// Copyright (c) 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <linux/kernel.h>
#include "mcp251xfd-dump-userspace.h"
static void print_usage(char *prg)
{
fprintf(stderr,
"%s - decode chip and driver state of mcp251xfd.\n"
"\n"
"Usage: %s [options] <file>\n"
"\n"
" <file> path to dev coredump file\n"
" ('/var/log/devcoredump-19700101-234200.dump')\n"
" path to regmap register file\n"
" ('/sys/kernel/debug/regmap/spi1.0-crc/registers')\n"
" shortcut to regmap register file\n"
" ('spi0.0')\n"
"\n"
"Options:\n"
" -h, --help this help\n"
"\n",
prg, prg);
}
int regmap_bulk_read(struct regmap *map, unsigned int reg,
void *val, size_t val_count)
{
memcpy(val, map->mem->buf + reg,
val_count * sizeof(uint32_t));
return 0;
}
int main(int argc, char *argv[])
{
struct mcp251xfd_mem mem = { };
struct regmap map = {
.mem = &mem,
};
struct mcp251xfd_priv priv = {
.map = &map,
};
const char *file_path;
int opt, err;
struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 },
};
while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) {
switch (opt) {
case 'h':
print_usage(basename(argv[0]));
exit(EXIT_SUCCESS);
break;
default:
print_usage(basename(argv[0]));
exit(EXIT_FAILURE);
break;
}
}
file_path = argv[optind];
if (!file_path) {
print_usage(basename(argv[0]));
exit(EXIT_FAILURE);
}
err = mcp251xfd_dev_coredump_read(&priv, &mem, file_path);
if (err)
err = mcp251xfd_regmap_read(&priv, &mem, file_path);
if (err) {
fprintf(stderr, "Unable to read file: '%s'\n", file_path);
exit(EXIT_FAILURE);
}
mcp251xfd_dump(&priv);
exit(EXIT_SUCCESS);
}
+81
View File
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0
//
// Microchip MCP251xFD Family CAN controller debug tool
//
// Copyright (c) 2020 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <linux/kernel.h>
#include "mcp251xfd.h"
#include "mcp251xfd-dump-userspace.h"
static int
do_mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
struct mcp251xfd_mem *mem,
const char *file_path)
{
FILE *reg_file;
uint16_t reg;
uint32_t val;
reg_file = fopen(file_path, "r");
if (!reg_file)
return -errno;
while (fscanf(reg_file, "%hx: %x\n", &reg, &val) == 2) {
if (reg >= ARRAY_SIZE(mem->buf))
return -EINVAL;
*(uint32_t *)(mem->buf + reg) = val;
}
fclose(reg_file);
return 0;
}
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
struct mcp251xfd_mem *mem,
const char *file_path)
{
char *tmp;
int err;
err = do_mcp251xfd_regmap_read(priv, mem, file_path);
if (!err)
return 0;
/* maybe it's something like "spi0.0" */
tmp = strchr(file_path, '/');
if (tmp)
return -ENOENT;
/* first try literally */
err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s/registers", file_path);
if (err == -1)
return -errno;
err = do_mcp251xfd_regmap_read(priv, mem, tmp);
free (tmp);
if (!err)
return 0;
/* then add "-crc" */
err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s-crc/registers", file_path);
if (err == -1)
return -errno;
err = do_mcp251xfd_regmap_read(priv, mem, tmp);
free (tmp);
return err;
}
+389
View File
@@ -0,0 +1,389 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
*
* Copyright (c) 2019, 2020 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
* Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
*/
#ifndef _MCP251XFD_H
#define _MCP251XFD_H
/* MPC251x registers */
/* CAN FD Controller Module SFR */
#define MCP251XFD_REG_CON 0x00
#define MCP251XFD_REG_CON_TXBWS_MASK GENMASK(31, 28)
#define MCP251XFD_REG_CON_ABAT BIT(27)
#define MCP251XFD_REG_CON_REQOP_MASK GENMASK(26, 24)
#define MCP251XFD_REG_CON_MODE_MIXED 0
#define MCP251XFD_REG_CON_MODE_SLEEP 1
#define MCP251XFD_REG_CON_MODE_INT_LOOPBACK 2
#define MCP251XFD_REG_CON_MODE_LISTENONLY 3
#define MCP251XFD_REG_CON_MODE_CONFIG 4
#define MCP251XFD_REG_CON_MODE_EXT_LOOPBACK 5
#define MCP251XFD_REG_CON_MODE_CAN2_0 6
#define MCP251XFD_REG_CON_MODE_RESTRICTED 7
#define MCP251XFD_REG_CON_OPMOD_MASK GENMASK(23, 21)
#define MCP251XFD_REG_CON_TXQEN BIT(20)
#define MCP251XFD_REG_CON_STEF BIT(19)
#define MCP251XFD_REG_CON_SERR2LOM BIT(18)
#define MCP251XFD_REG_CON_ESIGM BIT(17)
#define MCP251XFD_REG_CON_RTXAT BIT(16)
#define MCP251XFD_REG_CON_BRSDIS BIT(12)
#define MCP251XFD_REG_CON_BUSY BIT(11)
#define MCP251XFD_REG_CON_WFT_MASK GENMASK(10, 9)
#define MCP251XFD_REG_CON_WFT_T00FILTER 0x0
#define MCP251XFD_REG_CON_WFT_T01FILTER 0x1
#define MCP251XFD_REG_CON_WFT_T10FILTER 0x2
#define MCP251XFD_REG_CON_WFT_T11FILTER 0x3
#define MCP251XFD_REG_CON_WAKFIL BIT(8)
#define MCP251XFD_REG_CON_PXEDIS BIT(6)
#define MCP251XFD_REG_CON_ISOCRCEN BIT(5)
#define MCP251XFD_REG_CON_DNCNT_MASK GENMASK(4, 0)
#define MCP251XFD_REG_NBTCFG 0x04
#define MCP251XFD_REG_NBTCFG_BRP_MASK GENMASK(31, 24)
#define MCP251XFD_REG_NBTCFG_TSEG1_MASK GENMASK(23, 16)
#define MCP251XFD_REG_NBTCFG_TSEG2_MASK GENMASK(14, 8)
#define MCP251XFD_REG_NBTCFG_SJW_MASK GENMASK(6, 0)
#define MCP251XFD_REG_DBTCFG 0x08
#define MCP251XFD_REG_DBTCFG_BRP_MASK GENMASK(31, 24)
#define MCP251XFD_REG_DBTCFG_TSEG1_MASK GENMASK(20, 16)
#define MCP251XFD_REG_DBTCFG_TSEG2_MASK GENMASK(11, 8)
#define MCP251XFD_REG_DBTCFG_SJW_MASK GENMASK(3, 0)
#define MCP251XFD_REG_TDC 0x0c
#define MCP251XFD_REG_TDC_EDGFLTEN BIT(25)
#define MCP251XFD_REG_TDC_SID11EN BIT(24)
#define MCP251XFD_REG_TDC_TDCMOD_MASK GENMASK(17, 16)
#define MCP251XFD_REG_TDC_TDCMOD_AUTO 2
#define MCP251XFD_REG_TDC_TDCMOD_MANUAL 1
#define MCP251XFD_REG_TDC_TDCMOD_DISABLED 0
#define MCP251XFD_REG_TDC_TDCO_MASK GENMASK(14, 8)
#define MCP251XFD_REG_TDC_TDCV_MASK GENMASK(5, 0)
#define MCP251XFD_REG_TBC 0x10
#define MCP251XFD_REG_TSCON 0x14
#define MCP251XFD_REG_TSCON_TSRES BIT(18)
#define MCP251XFD_REG_TSCON_TSEOF BIT(17)
#define MCP251XFD_REG_TSCON_TBCEN BIT(16)
#define MCP251XFD_REG_TSCON_TBCPRE_MASK GENMASK(9, 0)
#define MCP251XFD_REG_VEC 0x18
#define MCP251XFD_REG_VEC_RXCODE_MASK GENMASK(30, 24)
#define MCP251XFD_REG_VEC_TXCODE_MASK GENMASK(22, 16)
#define MCP251XFD_REG_VEC_FILHIT_MASK GENMASK(12, 8)
#define MCP251XFD_REG_VEC_ICODE_MASK GENMASK(6, 0)
#define MCP251XFD_REG_INT 0x1c
#define MCP251XFD_REG_INT_IF_MASK GENMASK(15, 0)
#define MCP251XFD_REG_INT_IE_MASK GENMASK(31, 16)
#define MCP251XFD_REG_INT_IVMIE BIT(31)
#define MCP251XFD_REG_INT_WAKIE BIT(30)
#define MCP251XFD_REG_INT_CERRIE BIT(29)
#define MCP251XFD_REG_INT_SERRIE BIT(28)
#define MCP251XFD_REG_INT_RXOVIE BIT(27)
#define MCP251XFD_REG_INT_TXATIE BIT(26)
#define MCP251XFD_REG_INT_SPICRCIE BIT(25)
#define MCP251XFD_REG_INT_ECCIE BIT(24)
#define MCP251XFD_REG_INT_TEFIE BIT(20)
#define MCP251XFD_REG_INT_MODIE BIT(19)
#define MCP251XFD_REG_INT_TBCIE BIT(18)
#define MCP251XFD_REG_INT_RXIE BIT(17)
#define MCP251XFD_REG_INT_TXIE BIT(16)
#define MCP251XFD_REG_INT_IVMIF BIT(15)
#define MCP251XFD_REG_INT_WAKIF BIT(14)
#define MCP251XFD_REG_INT_CERRIF BIT(13)
#define MCP251XFD_REG_INT_SERRIF BIT(12)
#define MCP251XFD_REG_INT_RXOVIF BIT(11)
#define MCP251XFD_REG_INT_TXATIF BIT(10)
#define MCP251XFD_REG_INT_SPICRCIF BIT(9)
#define MCP251XFD_REG_INT_ECCIF BIT(8)
#define MCP251XFD_REG_INT_TEFIF BIT(4)
#define MCP251XFD_REG_INT_MODIF BIT(3)
#define MCP251XFD_REG_INT_TBCIF BIT(2)
#define MCP251XFD_REG_INT_RXIF BIT(1)
#define MCP251XFD_REG_INT_TXIF BIT(0)
/* These IRQ flags must be cleared by SW in the CAN_INT register */
#define MCP251XFD_REG_INT_IF_CLEARABLE_MASK \
(MCP251XFD_REG_INT_IVMIF | MCP251XFD_REG_INT_WAKIF | \
MCP251XFD_REG_INT_CERRIF | MCP251XFD_REG_INT_SERRIF | \
MCP251XFD_REG_INT_MODIF)
#define MCP251XFD_REG_RXIF 0x20
#define MCP251XFD_REG_TXIF 0x24
#define MCP251XFD_REG_RXOVIF 0x28
#define MCP251XFD_REG_TXATIF 0x2c
#define MCP251XFD_REG_TXREQ 0x30
#define MCP251XFD_REG_TREC 0x34
#define MCP251XFD_REG_TREC_TXBO BIT(21)
#define MCP251XFD_REG_TREC_TXBP BIT(20)
#define MCP251XFD_REG_TREC_RXBP BIT(19)
#define MCP251XFD_REG_TREC_TXWARN BIT(18)
#define MCP251XFD_REG_TREC_RXWARN BIT(17)
#define MCP251XFD_REG_TREC_EWARN BIT(16)
#define MCP251XFD_REG_TREC_TEC_MASK GENMASK(15, 8)
#define MCP251XFD_REG_TREC_REC_MASK GENMASK(7, 0)
#define MCP251XFD_REG_BDIAG0 0x38
#define MCP251XFD_REG_BDIAG0_DTERRCNT_MASK GENMASK(31, 24)
#define MCP251XFD_REG_BDIAG0_DRERRCNT_MASK GENMASK(23, 16)
#define MCP251XFD_REG_BDIAG0_NTERRCNT_MASK GENMASK(15, 8)
#define MCP251XFD_REG_BDIAG0_NRERRCNT_MASK GENMASK(7, 0)
#define MCP251XFD_REG_BDIAG1 0x3c
#define MCP251XFD_REG_BDIAG1_DLCMM BIT(31)
#define MCP251XFD_REG_BDIAG1_ESI BIT(30)
#define MCP251XFD_REG_BDIAG1_DCRCERR BIT(29)
#define MCP251XFD_REG_BDIAG1_DSTUFERR BIT(28)
#define MCP251XFD_REG_BDIAG1_DFORMERR BIT(27)
#define MCP251XFD_REG_BDIAG1_DBIT1ERR BIT(25)
#define MCP251XFD_REG_BDIAG1_DBIT0ERR BIT(24)
#define MCP251XFD_REG_BDIAG1_TXBOERR BIT(23)
#define MCP251XFD_REG_BDIAG1_NCRCERR BIT(21)
#define MCP251XFD_REG_BDIAG1_NSTUFERR BIT(20)
#define MCP251XFD_REG_BDIAG1_NFORMERR BIT(19)
#define MCP251XFD_REG_BDIAG1_NACKERR BIT(18)
#define MCP251XFD_REG_BDIAG1_NBIT1ERR BIT(17)
#define MCP251XFD_REG_BDIAG1_NBIT0ERR BIT(16)
#define MCP251XFD_REG_BDIAG1_BERR_MASK \
(MCP251XFD_REG_BDIAG1_DLCMM | MCP251XFD_REG_BDIAG1_ESI | \
MCP251XFD_REG_BDIAG1_DCRCERR | MCP251XFD_REG_BDIAG1_DSTUFERR | \
MCP251XFD_REG_BDIAG1_DFORMERR | MCP251XFD_REG_BDIAG1_DBIT1ERR | \
MCP251XFD_REG_BDIAG1_DBIT0ERR | MCP251XFD_REG_BDIAG1_TXBOERR | \
MCP251XFD_REG_BDIAG1_NCRCERR | MCP251XFD_REG_BDIAG1_NSTUFERR | \
MCP251XFD_REG_BDIAG1_NFORMERR | MCP251XFD_REG_BDIAG1_NACKERR | \
MCP251XFD_REG_BDIAG1_NBIT1ERR | MCP251XFD_REG_BDIAG1_NBIT0ERR)
#define MCP251XFD_REG_BDIAG1_EFMSGCNT_MASK GENMASK(15, 0)
#define MCP251XFD_REG_TEFCON 0x40
#define MCP251XFD_REG_TEFCON_FSIZE_MASK GENMASK(28, 24)
#define MCP251XFD_REG_TEFCON_FRESET BIT(10)
#define MCP251XFD_REG_TEFCON_UINC BIT(8)
#define MCP251XFD_REG_TEFCON_TEFTSEN BIT(5)
#define MCP251XFD_REG_TEFCON_TEFOVIE BIT(3)
#define MCP251XFD_REG_TEFCON_TEFFIE BIT(2)
#define MCP251XFD_REG_TEFCON_TEFHIE BIT(1)
#define MCP251XFD_REG_TEFCON_TEFNEIE BIT(0)
#define MCP251XFD_REG_TEFSTA 0x44
#define MCP251XFD_REG_TEFSTA_TEFOVIF BIT(3)
#define MCP251XFD_REG_TEFSTA_TEFFIF BIT(2)
#define MCP251XFD_REG_TEFSTA_TEFHIF BIT(1)
#define MCP251XFD_REG_TEFSTA_TEFNEIF BIT(0)
#define MCP251XFD_REG_TEFUA 0x48
#define MCP251XFD_REG_TXQCON 0x50
#define MCP251XFD_REG_TXQCON_PLSIZE_MASK GENMASK(31, 29)
#define MCP251XFD_REG_TXQCON_PLSIZE_8 0
#define MCP251XFD_REG_TXQCON_PLSIZE_12 1
#define MCP251XFD_REG_TXQCON_PLSIZE_16 2
#define MCP251XFD_REG_TXQCON_PLSIZE_20 3
#define MCP251XFD_REG_TXQCON_PLSIZE_24 4
#define MCP251XFD_REG_TXQCON_PLSIZE_32 5
#define MCP251XFD_REG_TXQCON_PLSIZE_48 6
#define MCP251XFD_REG_TXQCON_PLSIZE_64 7
#define MCP251XFD_REG_TXQCON_FSIZE_MASK GENMASK(28, 24)
#define MCP251XFD_REG_TXQCON_TXAT_UNLIMITED 3
#define MCP251XFD_REG_TXQCON_TXAT_THREE_SHOT 1
#define MCP251XFD_REG_TXQCON_TXAT_ONE_SHOT 0
#define MCP251XFD_REG_TXQCON_TXAT_MASK GENMASK(22, 21)
#define MCP251XFD_REG_TXQCON_TXPRI_MASK GENMASK(20, 16)
#define MCP251XFD_REG_TXQCON_FRESET BIT(10)
#define MCP251XFD_REG_TXQCON_TXREQ BIT(9)
#define MCP251XFD_REG_TXQCON_UINC BIT(8)
#define MCP251XFD_REG_TXQCON_TXEN BIT(7)
#define MCP251XFD_REG_TXQCON_TXATIE BIT(4)
#define MCP251XFD_REG_TXQCON_TXQEIE BIT(2)
#define MCP251XFD_REG_TXQCON_TXQNIE BIT(0)
#define MCP251XFD_REG_TXQSTA 0x54
#define MCP251XFD_REG_TXQSTA_TXQCI_MASK GENMASK(12, 8)
#define MCP251XFD_REG_TXQSTA_TXABT BIT(7)
#define MCP251XFD_REG_TXQSTA_TXLARB BIT(6)
#define MCP251XFD_REG_TXQSTA_TXERR BIT(5)
#define MCP251XFD_REG_TXQSTA_TXATIF BIT(4)
#define MCP251XFD_REG_TXQSTA_TXQEIF BIT(2)
#define MCP251XFD_REG_TXQSTA_TXQNIF BIT(0)
#define MCP251XFD_REG_TXQUA 0x58
#define MCP251XFD_REG_FIFOCON(x) (0x50 + 0xc * (x))
#define MCP251XFD_REG_FIFOCON_PLSIZE_MASK GENMASK(31, 29)
#define MCP251XFD_REG_FIFOCON_PLSIZE_8 0
#define MCP251XFD_REG_FIFOCON_PLSIZE_12 1
#define MCP251XFD_REG_FIFOCON_PLSIZE_16 2
#define MCP251XFD_REG_FIFOCON_PLSIZE_20 3
#define MCP251XFD_REG_FIFOCON_PLSIZE_24 4
#define MCP251XFD_REG_FIFOCON_PLSIZE_32 5
#define MCP251XFD_REG_FIFOCON_PLSIZE_48 6
#define MCP251XFD_REG_FIFOCON_PLSIZE_64 7
#define MCP251XFD_REG_FIFOCON_FSIZE_MASK GENMASK(28, 24)
#define MCP251XFD_REG_FIFOCON_TXAT_MASK GENMASK(22, 21)
#define MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT 0
#define MCP251XFD_REG_FIFOCON_TXAT_THREE_SHOT 1
#define MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED 3
#define MCP251XFD_REG_FIFOCON_TXPRI_MASK GENMASK(20, 16)
#define MCP251XFD_REG_FIFOCON_FRESET BIT(10)
#define MCP251XFD_REG_FIFOCON_TXREQ BIT(9)
#define MCP251XFD_REG_FIFOCON_UINC BIT(8)
#define MCP251XFD_REG_FIFOCON_TXEN BIT(7)
#define MCP251XFD_REG_FIFOCON_RTREN BIT(6)
#define MCP251XFD_REG_FIFOCON_RXTSEN BIT(5)
#define MCP251XFD_REG_FIFOCON_TXATIE BIT(4)
#define MCP251XFD_REG_FIFOCON_RXOVIE BIT(3)
#define MCP251XFD_REG_FIFOCON_TFERFFIE BIT(2)
#define MCP251XFD_REG_FIFOCON_TFHRFHIE BIT(1)
#define MCP251XFD_REG_FIFOCON_TFNRFNIE BIT(0)
#define MCP251XFD_REG_FIFOSTA(x) (0x54 + 0xc * (x))
#define MCP251XFD_REG_FIFOSTA_FIFOCI_MASK GENMASK(12, 8)
#define MCP251XFD_REG_FIFOSTA_TXABT BIT(7)
#define MCP251XFD_REG_FIFOSTA_TXLARB BIT(6)
#define MCP251XFD_REG_FIFOSTA_TXERR BIT(5)
#define MCP251XFD_REG_FIFOSTA_TXATIF BIT(4)
#define MCP251XFD_REG_FIFOSTA_RXOVIF BIT(3)
#define MCP251XFD_REG_FIFOSTA_TFERFFIF BIT(2)
#define MCP251XFD_REG_FIFOSTA_TFHRFHIF BIT(1)
#define MCP251XFD_REG_FIFOSTA_TFNRFNIF BIT(0)
#define MCP251XFD_REG_FIFOUA(x) (0x58 + 0xc * (x))
#define MCP251XFD_REG_FLTCON(x) (0x1d0 + 0x4 * (x))
#define MCP251XFD_REG_FLTCON_FLTEN3 BIT(31)
#define MCP251XFD_REG_FLTCON_F3BP_MASK GENMASK(28, 24)
#define MCP251XFD_REG_FLTCON_FLTEN2 BIT(23)
#define MCP251XFD_REG_FLTCON_F2BP_MASK GENMASK(20, 16)
#define MCP251XFD_REG_FLTCON_FLTEN1 BIT(15)
#define MCP251XFD_REG_FLTCON_F1BP_MASK GENMASK(12, 8)
#define MCP251XFD_REG_FLTCON_FLTEN0 BIT(7)
#define MCP251XFD_REG_FLTCON_F0BP_MASK GENMASK(4, 0)
#define MCP251XFD_REG_FLTCON_FLTEN(x) (BIT(7) << 8 * ((x) & 0x3))
#define MCP251XFD_REG_FLTCON_FLT_MASK(x) (GENMASK(7, 0) << (8 * ((x) & 0x3)))
#define MCP251XFD_REG_FLTCON_FBP(x, fifo) ((fifo) << 8 * ((x) & 0x3))
#define MCP251XFD_REG_FLTOBJ(x) (0x1f0 + 0x8 * (x))
#define MCP251XFD_REG_FLTOBJ_EXIDE BIT(30)
#define MCP251XFD_REG_FLTOBJ_SID11 BIT(29)
#define MCP251XFD_REG_FLTOBJ_EID_MASK GENMASK(28, 11)
#define MCP251XFD_REG_FLTOBJ_SID_MASK GENMASK(10, 0)
#define MCP251XFD_REG_FLTMASK(x) (0x1f4 + 0x8 * (x))
#define MCP251XFD_REG_MASK_MIDE BIT(30)
#define MCP251XFD_REG_MASK_MSID11 BIT(29)
#define MCP251XFD_REG_MASK_MEID_MASK GENMASK(28, 11)
#define MCP251XFD_REG_MASK_MSID_MASK GENMASK(10, 0)
/* RAM */
#define MCP251XFD_RAM_START 0x400
#define MCP251XFD_RAM_SIZE SZ_2K
/* Message Object */
#define MCP251XFD_OBJ_ID_SID11 BIT(29)
#define MCP251XFD_OBJ_ID_EID_MASK GENMASK(28, 11)
#define MCP251XFD_OBJ_ID_SID_MASK GENMASK(10, 0)
#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK GENMASK(31, 9)
#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK GENMASK(15, 9)
#define MCP251XFD_OBJ_FLAGS_SEQ_MASK MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK
#define MCP251XFD_OBJ_FLAGS_ESI BIT(8)
#define MCP251XFD_OBJ_FLAGS_FDF BIT(7)
#define MCP251XFD_OBJ_FLAGS_BRS BIT(6)
#define MCP251XFD_OBJ_FLAGS_RTR BIT(5)
#define MCP251XFD_OBJ_FLAGS_IDE BIT(4)
#define MCP251XFD_OBJ_FLAGS_DLC GENMASK(3, 0)
#define MCP251XFD_REG_FRAME_EFF_SID_MASK GENMASK(28, 18)
#define MCP251XFD_REG_FRAME_EFF_EID_MASK GENMASK(17, 0)
/* MCP2517/18FD SFR */
#define MCP251XFD_REG_OSC 0xe00
#define MCP251XFD_REG_OSC_SCLKRDY BIT(12)
#define MCP251XFD_REG_OSC_OSCRDY BIT(10)
#define MCP251XFD_REG_OSC_PLLRDY BIT(8)
#define MCP251XFD_REG_OSC_CLKODIV_10 3
#define MCP251XFD_REG_OSC_CLKODIV_4 2
#define MCP251XFD_REG_OSC_CLKODIV_2 1
#define MCP251XFD_REG_OSC_CLKODIV_1 0
#define MCP251XFD_REG_OSC_CLKODIV_MASK GENMASK(6, 5)
#define MCP251XFD_REG_OSC_SCLKDIV BIT(4)
#define MCP251XFD_REG_OSC_LPMEN BIT(3) /* MCP2518FD only */
#define MCP251XFD_REG_OSC_OSCDIS BIT(2)
#define MCP251XFD_REG_OSC_PLLEN BIT(0)
#define MCP251XFD_REG_IOCON 0xe04
#define MCP251XFD_REG_IOCON_INTOD BIT(30)
#define MCP251XFD_REG_IOCON_SOF BIT(29)
#define MCP251XFD_REG_IOCON_TXCANOD BIT(28)
#define MCP251XFD_REG_IOCON_PM1 BIT(25)
#define MCP251XFD_REG_IOCON_PM0 BIT(24)
#define MCP251XFD_REG_IOCON_GPIO1 BIT(17)
#define MCP251XFD_REG_IOCON_GPIO0 BIT(16)
#define MCP251XFD_REG_IOCON_LAT1 BIT(9)
#define MCP251XFD_REG_IOCON_LAT0 BIT(8)
#define MCP251XFD_REG_IOCON_XSTBYEN BIT(6)
#define MCP251XFD_REG_IOCON_TRIS1 BIT(1)
#define MCP251XFD_REG_IOCON_TRIS0 BIT(0)
#define MCP251XFD_REG_CRC 0xe08
#define MCP251XFD_REG_CRC_FERRIE BIT(25)
#define MCP251XFD_REG_CRC_CRCERRIE BIT(24)
#define MCP251XFD_REG_CRC_FERRIF BIT(17)
#define MCP251XFD_REG_CRC_CRCERRIF BIT(16)
#define MCP251XFD_REG_CRC_IF_MASK GENMASK(17, 16)
#define MCP251XFD_REG_CRC_MASK GENMASK(15, 0)
#define MCP251XFD_REG_ECCCON 0xe0c
#define MCP251XFD_REG_ECCCON_PARITY_MASK GENMASK(14, 8)
#define MCP251XFD_REG_ECCCON_DEDIE BIT(2)
#define MCP251XFD_REG_ECCCON_SECIE BIT(1)
#define MCP251XFD_REG_ECCCON_ECCEN BIT(0)
#define MCP251XFD_REG_ECCSTAT 0xe10
#define MCP251XFD_REG_ECCSTAT_ERRADDR_MASK GENMASK(27, 16)
#define MCP251XFD_REG_ECCSTAT_IF_MASK GENMASK(2, 1)
#define MCP251XFD_REG_ECCSTAT_DEDIF BIT(2)
#define MCP251XFD_REG_ECCSTAT_SECIF BIT(1)
#define MCP251XFD_REG_DEVID 0xe14 /* MCP2518FD only */
#define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4)
#define MCP251XFD_REG_DEVID_REV_MASK GENMASK(3, 0)
struct mcp251xfd_hw_tef_obj {
u32 id;
u32 flags;
u32 ts;
};
struct mcp251xfd_hw_tx_obj_can {
u32 id;
u32 flags;
u8 data[sizeof_field(struct can_frame, data)];
};
struct mcp251xfd_hw_tx_obj_canfd {
u32 id;
u32 flags;
u8 data[sizeof_field(struct canfd_frame, data)];
};
struct mcp251xfd_hw_rx_obj_can {
u32 id;
u32 flags;
u32 ts;
u8 data[sizeof_field(struct can_frame, data)];
};
struct mcp251xfd_hw_rx_obj_canfd {
u32 id;
u32 flags;
u32 ts;
u8 data[sizeof_field(struct canfd_frame, data)];
};
#endif
+37 -24
View File
@@ -42,37 +42,50 @@
*
*/
#include <fcntl.h>
#include <getopt.h>
#include <linux/sockios.h>
#include <linux/tty.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <termios.h>
#include <linux/tty.h>
#include <linux/sockios.h>
#include <unistd.h>
void print_usage(char *prg)
{
fprintf(stderr, "%s - userspace tool for serial line CAN interface driver SLCAN.\n", prg);
fprintf(stderr, "\nUsage: %s [options] tty\n\n", prg);
fprintf(stderr, "Options: -o (send open command 'O\\r')\n");
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
fprintf(stderr, " -c (send close command 'C\\r')\n");
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
fprintf(stderr, " -b <btr> (set bit time register value)\n");
fprintf(stderr, " -d (only detach line discipline)\n");
fprintf(stderr, " -w (attach - wait for keypess - detach)\n");
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -o (send open command 'O\\r')\n");
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
fprintf(stderr, " -c (send close command 'C\\r')\n");
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
fprintf(stderr, " -b <btr> (set bit time register value)\n");
fprintf(stderr, " -d (only detach line discipline)\n");
fprintf(stderr, " -w (attach - wait for keypess - detach)\n");
fprintf(stderr, " -n <name> (assign created netdevice name)\n");
fprintf(stderr, "\n"
" <speed> Bitrate\n"
" 0 10 Kbit/s\n"
" 1 20 Kbit/s\n"
" 2 50 Kbit/s\n"
" 3 100 Kbit/s\n"
" 4 125 Kbit/s\n"
" 5 250 Kbit/s\n"
" 6 500 Kbit/s\n"
" 7 800 Kbit/s\n"
" 8 1000 Kbit/s\n"
"\n");
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "slcan_attach -w -o -f -s6 -c /dev/ttyS1\n");
fprintf(stderr, "slcan_attach /dev/ttyS1\n");
fprintf(stderr, "slcan_attach -d /dev/ttyS1\n");
fprintf(stderr, "slcan_attach -w -n can15 /dev/ttyS1\n");
fprintf(stderr, "\n");
fprintf(stderr, "slcan_attach -w -o -f -s6 -c /dev/ttyS1\n\n");
fprintf(stderr, "slcan_attach /dev/ttyS1\n\n");
fprintf(stderr, "slcan_attach -d /dev/ttyS1\n\n");
fprintf(stderr, "slcan_attach -w -n can15 /dev/ttyS1\n\n");
exit(1);
}
@@ -212,7 +225,7 @@ int main(int argc, char **argv)
/* try to rename the created device if requested */
if (name) {
int s = socket(PF_INET, SOCK_DGRAM, 0);
printf("rename netdevice %s to %s ... ", buf, name);
if (s < 0)
@@ -221,12 +234,12 @@ int main(int argc, char **argv)
/* current slcan%d name is still in ifr.ifr_name */
memset (ifr.ifr_newname, 0, sizeof(ifr.ifr_newname));
strncpy (ifr.ifr_newname, name, sizeof(ifr.ifr_newname) - 1);
if (ioctl(s, SIOCSIFNAME, &ifr) < 0)
printf("failed!\n");
else
printf("ok.\n");
close(s);
}
}
+29 -28
View File
@@ -22,25 +22,25 @@
*
*/
#include <errno.h>
#include <fcntl.h>
#include <linux/serial.h>
#include <linux/sockios.h>
#include <linux/tty.h>
#include <net/if.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <syslog.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <termios.h>
#include <linux/tty.h>
#include <linux/sockios.h>
#include <linux/serial.h>
#include <stdarg.h>
#include <unistd.h>
/* Change this to whatever your daemon is called */
#define DAEMON_NAME "slcand"
@@ -72,22 +72,23 @@ static syslog_t syslogger = syslog;
void print_usage(char *prg)
{
fprintf(stderr, "%s - userspace daemon for serial line CAN interface driver SLCAN.\n", prg);
fprintf(stderr, "\nUsage: %s [options] <tty> [canif-name]\n\n", prg);
fprintf(stderr, "Options: -o (send open command 'O\\r')\n");
fprintf(stderr, " -c (send close command 'C\\r')\n");
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
fprintf(stderr, " -S <speed> (set UART speed in baud)\n");
fprintf(stderr, " -t <type> (set UART flow control type 'hw' or 'sw')\n");
fprintf(stderr, " -b <btr> (set bit time register value)\n");
fprintf(stderr, " -F (stay in foreground; no daemonize)\n");
fprintf(stderr, " -h (show this help page)\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -o (send open command 'O\\r')\n");
fprintf(stderr, " -c (send close command 'C\\r')\n");
fprintf(stderr, " -f (read status flags with 'F\\r' to reset error states)\n");
fprintf(stderr, " -l (send listen only command 'L\\r', overrides -o)\n");
fprintf(stderr, " -s <speed> (set CAN speed 0..8)\n");
fprintf(stderr, " -S <speed> (set UART speed in baud)\n");
fprintf(stderr, " -t <type> (set UART flow control type 'hw' or 'sw')\n");
fprintf(stderr, " -b <btr> (set bit time register value)\n");
fprintf(stderr, " -F (stay in foreground; no daemonize)\n");
fprintf(stderr, " -h (show this help page)\n");
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0\n");
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0 can0\n");
fprintf(stderr, "slcand -o -c -f -s6 /dev/ttyUSB0\n");
fprintf(stderr, "\n");
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0\n\n");
fprintf(stderr, "slcand -o -c -f -s6 ttyUSB0 can0\n\n");
fprintf(stderr, "slcand -o -c -f -s6 /dev/ttyUSB0\n\n");
exit(EXIT_FAILURE);
}
+17 -11
View File
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* slcanpty.c - creates a pty for applications using the slcan ASCII protocol
* slcanpty: adapter for applications using the slcan ASCII protocol
*
* slcanpty.c - creates a pty for applications using the slcan ASCII protocol
* and converts the ASCII data to a CAN network interface (and vice versa)
*
* Copyright (c)2009 Oliver Hartkopp
@@ -22,16 +24,18 @@
*
*/
#include <fcntl.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -428,16 +432,18 @@ int main(int argc, char **argv)
/* check command line options */
if (argc != 3) {
fprintf(stderr, "\n");
fprintf(stderr, "%s creates a pty for applications using"
" the slcan ASCII protocol and\n", argv[0]);
fprintf(stderr, "%s: adapter for applications using"
" the slcan ASCII protocol.\n", basename(argv[0]));
fprintf(stderr, "\n%s creates a pty for applications using"
" the slcan ASCII protocol and\n", basename(argv[0]));
fprintf(stderr, "converts the ASCII data to a CAN network"
" interface (and vice versa)\n\n");
fprintf(stderr, "Usage: %s <pty> <can interface>\n", argv[0]);
fprintf(stderr, "e.g. '%s /dev/ptyc0 can0' creates"
" /dev/ttyc0 for the slcan application\n", argv[0]);
fprintf(stderr, "Usage: %s <pty> <can interface>\n", basename(argv[0]));
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, "%s /dev/ptyc0 can0 - creates /dev/ttyc0 for the slcan application\n\n",
basename(argv[0]));
fprintf(stderr, "e.g. for pseudo-terminal '%s %s can0' creates"
" /dev/pts/N\n", argv[0], DEVICE_NAME_PTMX);
" /dev/pts/N\n", basename(argv[0]), DEVICE_NAME_PTMX);
fprintf(stderr, "\n");
return 1;
}
+71 -68
View File
@@ -10,26 +10,26 @@
* as published by the Free Software Foundation
*/
#include <signal.h>
#include <time.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <getopt.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include "libj1939.h"
static const char help_msg[] =
"testj1939: demonstrate j1939 use\n"
"Usage: testj1939 FROM TO\n"
"Usage: testj1939 [OPTIONS] FROM TO\n"
" FROM / TO - or [IFACE][:[SA][,[PGN][,NAME]]]\n"
"Options:\n"
" -v Print relevant API calls\n"
@@ -46,7 +46,7 @@ static const char help_msg[] =
" -n Emit 64bit NAMEs in output\n"
" -w[TIME] Return after TIME (default 1) seconds\n"
"\n"
"Example:\n"
"Examples:\n"
"testj1939 can1 20\n"
"\n"
;
@@ -61,7 +61,7 @@ static void onsigalrm(int sig)
static void schedule_oneshot_itimer(double delay)
{
struct itimerval it = {};
struct itimerval it = { 0 };
it.it_value.tv_sec = delay;
it.it_value.tv_usec = (long)(delay * 1e6) % 1000000;
@@ -72,7 +72,8 @@ static void schedule_oneshot_itimer(double delay)
/* main */
int main(int argc, char *argv[])
{
int ret, sock, opt, j;
int ret, sock, opt;
unsigned int j;
int verbose = 0;
socklen_t peernamelen;
struct sockaddr_can sockname = {
@@ -92,62 +93,64 @@ int main(int argc, char *argv[])
};
uint8_t dat[128];
int valid_peername = 0;
int todo_send = 0, todo_recv = 0, todo_echo = 0, todo_prio = -1;
unsigned int todo_send = 0;
int todo_recv = 0, todo_echo = 0, todo_prio = -1;
int todo_connect = 0, todo_names = 0, todo_wait = 0, todo_rebind = 0;
int todo_broadcast = 0, todo_promisc = 0;
int no_bind = 0;
/* argument parsing */
while ((opt = getopt(argc, argv, optstring)) != -1)
switch (opt) {
case 'v':
verbose = 1;
break;
case 's':
todo_send = strtoul(optarg ?: "8", NULL, 0);
if (todo_send > sizeof(dat))
err(1, "Unsupported size. max: %zu", sizeof(dat));
break;
case 'r':
todo_recv = 1;
break;
case 'e':
todo_echo = 1;
break;
case 'p':
todo_prio = strtoul(optarg, NULL, 0);
break;
case 'P':
todo_promisc = 1;
break;
case 'c':
todo_connect = 1;
break;
case 'n':
todo_names = 1;
break;
case 'b':
todo_rebind = 1;
break;
case 'B':
todo_broadcast = 1;
break;
case 'o':
no_bind = 1;
break;
case 'w':
schedule_oneshot_itimer(strtod(optarg ?: "1", NULL));
signal(SIGALRM, onsigalrm);
todo_wait = 1;
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
switch (opt) {
case 'v':
verbose = 1;
break;
case 's':
todo_send = strtoul(optarg ?: "8", NULL, 0);
if (todo_send > sizeof(dat))
err(1, "Unsupported size. max: %zu",
sizeof(dat));
break;
case 'r':
todo_recv = 1;
break;
case 'e':
todo_echo = 1;
break;
case 'p':
todo_prio = strtoul(optarg, NULL, 0);
break;
case 'P':
todo_promisc = 1;
break;
case 'c':
todo_connect = 1;
break;
case 'n':
todo_names = 1;
break;
case 'b':
todo_rebind = 1;
break;
case 'B':
todo_broadcast = 1;
break;
case 'o':
no_bind = 1;
break;
case 'w':
schedule_oneshot_itimer(strtod(optarg ?: "1", NULL));
signal(SIGALRM, onsigalrm);
todo_wait = 1;
break;
default:
fputs(help_msg, stderr);
exit(1);
break;
}
if (argv[optind]) {
if (strcmp("-", argv[optind]))
if (strcmp("-", argv[optind]) != 0)
libj1939_parse_canaddr(argv[optind], &sockname);
++optind;
}
@@ -156,7 +159,7 @@ int main(int argc, char *argv[])
sockname.can_addr.j1939.addr++;
if (argv[optind]) {
if (strcmp("-", argv[optind])) {
if (strcmp("-", argv[optind]) != 0) {
libj1939_parse_canaddr(argv[optind], &peername);
valid_peername = 1;
}
@@ -289,18 +292,18 @@ int main(int argc, char *argv[])
err(1, "sendto");
}
if (todo_recv) {
int i = 0;
int i;
if (todo_names && peername.can_addr.j1939.name)
printf("%016llx ", peername.can_addr.j1939.name);
printf("%02x %05x:", peername.can_addr.j1939.addr,
peername.can_addr.j1939.pgn);
for (j = 0; j < ret; ++j, i++) {
if (i == 8) {
printf("\n%05x ", j);
i = 0;
for (i = 0, j = 0; i < ret; ++i, j++) {
if (j == 8) {
printf("\n%05x ", i);
j = 0;
}
printf(" %02x", dat[j]);
printf(" %02x", dat[i]);
}
printf("\n");
}