77 Commits
Author SHA1 Message Date
Marc Kleine-BuddeandGitHub 01083a64eb Merge pull request #573 from hartkopp/canxl-asc-conversion
CANXL support for ASC conversion tools
2025-01-24 15:39:01 +01:00
Oliver Hartkopp 008f9f8e22 asc2log: add option to disable direction info
The ASC file provides an information whether the CAN frame is sent (Tx)
or received (Rx) on the local CAN node.

With the new '-d' option the generation of this information is disabled
for the log file generation to simplify the comparision of log files.

E.g. log1 -> asc -> log2 always created the T/R information in the log2
file which is then hard to compare to the log1 file which might not
have the T/R information at all.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 15:08:46 +01:00
Oliver Hartkopp 66e7c08beb log2asc: add CAN XL support
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 15:04:43 +01:00
Oliver Hartkopp 4b66e8c56f asc2log: shrink string buffer for header analysis
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:59:57 +01:00
Oliver Hartkopp e6e3253972 asc2log: shrink string buffer for CAN identifier
Since using the %n feature the tmp1 buffer is only used for the handling
of the CAN identifier. So this buffer can be shrinked for that use case.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:56:16 +01:00
Oliver Hartkopp 6d69bef837 asc2log: add CAN CC and CAN FD support for CAN XL message events
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:51:52 +01:00
Oliver Hartkopp 4d8b247258 asc2log: make use of sscanf consumed characters feature
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:48:32 +01:00
Oliver Hartkopp 0e9c53f6d3 asc2log: add CAN XL support for CAN XL message events
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:33:59 +01:00
Oliver Hartkopp 99c5c14790 can.h: canxl: support Remote Request Substitution bit access
The Remote Request Substitution bit is a dominant bit ("0") in the CAN XL
frame. As some CAN XL controllers support to access this bit a new
CANXL_RRS value has been defined for the canxl_frame.flags element.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:22:21 +01:00
Oliver Hartkopp df8e08fa70 asc2log: prepare helper functions for CAN XL frame handling
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:22:21 +01:00
Oliver Hartkopp cb5ab07f34 asc2log: handle and skip TxRq messages
TxRq messages are internal measurement messages that document the time of
a transmission request (to the CAN driver) to be checked against the real
transmission time, when the CAN message has been sent.

There is no such feature in the SocketCAN log format, so we detect this
tag but skip TxRq messages in the ASC log files.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:22:21 +01:00
Oliver Hartkopp 0e692bf42e asc2log: unify multi-line comments
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2025-01-24 14:21:59 +01:00
Marc Kleine-BuddeandGitHub 0984817438 Merge pull request #571 from marckleinebudde/cangen-canbusload
cangen, canbusload: new features
2025-01-22 15:54:06 +01:00
Zhu YiandMarc Kleine-Budde b3da2f62b9 canbusload: support busload visualization
Add '-v' option for visualize busload, the output shows a moving
histogram of the past 90 seconds.

canbusload 2024-09-23 17:19:33 (exact bitstuffing)
 can0@500k   487   55558   31048       0  99% |XXXXXXXXXXXXXXXXXXX.|
100%|..........................................................................................
 95%|..............................................................................XXXXXXXXXXXX
 90%|.............................................................................XXXXXXXXXXXXX
 85%|.............................................................................XXXXXXXXXXXXX
 80%|.............................................................................XXXXXXXXXXXXX
 75%|.............................................................................XXXXXXXXXXXXX
 70%|.............................................................................XXXXXXXXXXXXX
 65%|.............................................................................XXXXXXXXXXXXX
 60%|............................................................................XXXXXXXXXXXXXX
 55%|............................................................................XXXXXXXXXXXXXX
 50%|............................................................................XXXXXXXXXXXXXX
 45%|............................................................................XXXXXXXXXXXXXX
 40%|............................................................................XXXXXXXXXXXXXX
 35%|.........................................XXX................................XXXXXXXXXXXXXX
 30%|.........................................XXXX...............................XXXXXXXXXXXXXX
 25%|........................................XXXXXX.............................XXXXXXXXXXXXXXX
 20%|XXXXXXXX...............................XXXXXXXXXXXXXXXXX....XXXXXXXXXXX...XXXXXXXXXXXXXXXX
 15%|XXXXXXXXX.............................XXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 10%|XXXXXXXXX.XXXXXXXXXXXXXXXXXXX..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  5%|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Signed-off-by: Zhu Yi <yi.zhu5@cn.bosch.com>
Signed-off-by: Hubert Streidl <hubert.streidl@de.bosch.com>
Signed-off-by: Mark Jonas <mark.jonas@de.bosch.com>
Link: https://lore.kernel.org/r/20250120162332.19157-3-mark.jonas@de.bosch.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2025-01-20 18:07:16 +01:00
Zhu YiandMarc Kleine-Budde b85418d75c canbusload: support busload statistic
Add '-s' option for display busload statistic, the output contains
minimal, maximum and exponentially-damped moving sums of one second
average (borrowed from Linux load average algorithm) since start or
reset (press 'r' while running).

canbusload 2024-09-23 17:15:18 (exact bitstuffing)
 can0@500k   942  107535   60168       0  18% min:  0%, max: 21%, load: 16%   6%   2% |XXX.................|

Signed-off-by: Zhu Yi <yi.zhu5@cn.bosch.com>
Signed-off-by: Hubert Streidl <hubert.streidl@de.bosch.com>
Signed-off-by: Mark Jonas <mark.jonas@de.bosch.com>
Link: https://lore.kernel.org/r/20250120162332.19157-2-mark.jonas@de.bosch.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2025-01-20 18:01:10 +01:00
Zhu YiandMarc Kleine-Budde 6eb97b57c5 cangen: support socket priority
Add '-P' option for allow user to set the socket priority. This can be
useful in conjuction with queuing discipline.

Signed-off-by: Zhu Yi <yi.zhu5@cn.bosch.com>
Signed-off-by: Hubert Streidl <hubert.streidl@de.bosch.com>
Signed-off-by: Mark Jonas <mark.jonas@de.bosch.com>
Link: https://lore.kernel.org/r/20250120162332.19157-1-mark.jonas@de.bosch.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
2025-01-20 18:01:10 +01:00
Marc Kleine-BuddeandGitHub fc1f6979c0 Merge pull request #568 from marckleinebudde/j1939
can-j1939-install-kernel-module: convert to Unix line endings and remove trailing whitespace
2024-12-11 15:02:35 +01:00
Marc Kleine-Budde 24e0c520b6 can-j1939-install-kernel-module: convert to Unix line endings and remove trailing whitespace 2024-12-11 15:01:58 +01:00
Marc Kleine-BuddeandGitHub 06561ac3dc Merge pull request #566 from marckleinebudde/canfdtest
canfdtest: compare_frame: add 0x prefix to indicate hex value
2024-12-11 11:03:12 +01:00
Marc Kleine-Budde 7093a73185 canfdtest: compare_frame: add 0x prefix to indicate hex value 2024-12-11 10:24:33 +01:00
Marc Kleine-BuddeandGitHub 72f236e3ac Merge pull request #565 from yegorich/fix-code-analysis-workflow
CI: fix codeql-analysis
2024-12-09 11:17:38 +01:00
Yegor Yefremov 3bbc8075eb CI: fix codeql-analysis
v1 is deprecated. Thus, use the latest version v3 instead.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-12-09 11:05:40 +01:00
Oliver HartkoppandGitHub 6526683a10 Merge pull request #556 from hartkopp/master
Fix and rework canbusload
2024-08-09 15:02:26 +02:00
Oliver Hartkopp dced0a6ec7 canbusload: fix and improve the bitrate output
With the introduction of CAN FD the bitrate has not been printed
correcty. Fix the CAN FD bitrate output and try to shrink the
bitrates by using kilo or Mega suffixes: 500000 -> 500k

Fixes: 6382765bf6 ("canbusload: count databitrate seperately")
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-08 17:36:49 +02:00
Marc Kleine-BuddeandGitHub 6c36d44c83 Merge pull request #555 from marckleinebudde/readme-update-link
README: update link to kernel documentation
2024-08-08 14:14:10 +02:00
Marc Kleine-Budde 7260844b73 README: update link to kernel documentation
The can.txt is obsolete, move to rendered html instead.
2024-08-08 14:06:59 +02:00
Oliver Hartkopp be1fc77311 gitignore: add j1939-timedate-cli and j1939-timedate-srv
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-08 11:03:15 +02:00
Oliver Hartkopp fc2473424e canbusload: show RX/TX direction in bargraph
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-08 10:04:55 +02:00
Oliver Hartkopp 724e6f7c11 canbusload: use recvmsg() instead of recvfrom()
To access msg_flags for RX/TX direction detection.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-07 21:29:49 +02:00
Oliver Hartkopp 7665e1e236 canbusload: add auto detection of CAN interfaces
Rework to use a single CAN socket for the received CAN traffic.
This allows to shutdown and restart various CAN interfaces without
terminating the application.
Additionally an auto detection has been implemented with the 'any' CAN
interface. E.g. with any@500000,2000000 CAN interfaces that have not
been defined before are assigned with the given 'any' bitrates when a
CAN frame from this CAN interface has been received.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-07 19:57:08 +02:00
Oliver Hartkopp b592ec5b1f canbusload: fix string length check for CAN FD
The CAN interface description can now have two bitrates.
Extend the length check to handle the CAN FD data bitrate correctly.

Fixes: 6382765bf6 ("canbusload: count databitrate seperately")
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-07 13:02:05 +02:00
Oliver Hartkopp 30b6b04053 isotpdump: add color support for functional addressing traffic
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-08-06 16:26:14 +02:00
chrisandOliver Hartkopp 367e0df4aa isotpdump: option to capture functional addressing traffic
add option '-b' to capture functional broadcast data eg: -b 98DAFFF1 or -b 18DAFFF1
2024-08-06 16:12:18 +02:00
Oleksij RempelandGitHub 8a156fee19 Merge pull request #552 from pseiderer/ps-devel-fix-uclibc-compile-002
j1939acd: remove legacy '-p' option (prefix to use when logging)
2024-07-24 09:36:00 +02:00
Peter Seiderer a63bf468c2 j1939sr: remove legacy program_invocation_name/program_invocation_short_name code
- remove legacy program_invocation_name/program_invocation_short_name code

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
2024-07-22 16:18:21 +02:00
Peter Seiderer d337863d91 j1939acd: remove legacy '-p' option (prefix to use when logging)
- remove legacy '-p' option (prefix to use when logging), fixes uclibc
  compile

Fixes:

  j1939acd.c: In function 'main':
  j1939acd.c:489:38: error: passing argument 1 of 'asprintf' from incompatible pointer type [-Wincompatible-pointer-types]
    489 |                         if (asprintf(&program_invocation_name, "%s.%s",
        |                                      ^~~~~~~~~~~~~~~~~~~~~~~~
        |                                      |
        |                                      const char **

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
2024-07-22 16:14:48 +02:00
Marc Kleine-BuddeandGitHub 95fe6522c6 Merge pull request #548 from marckleinebudde/workflow-debian-experimental
github-actions: add debian:experimental
2024-06-20 09:05:12 +02:00
Marc Kleine-Budde fe514eedf8 github-actions: add debian:experimental 2024-06-20 08:41:48 +02:00
Marc Kleine-BuddeandGitHub 4eb72fd39a Merge pull request #547 from vuquangtrong/master
asc2log::get_date check for AM in en_US time format
2024-06-12 08:58:32 +02:00
vuquangtrongandGitHub 51b1f67851 asc2log::get_date check for AM in en_US time format 2024-06-12 13:48:53 +07:00
Marc Kleine-BuddeandGitHub 847486083a Merge pull request #546 from marckleinebudde/activate-Wsign-compare
cmake: add -Wsign-compare
2024-06-07 13:22:32 +02:00
Marc Kleine-Budde f6db81da68 cmake: add -Wsign-compare 2024-06-07 09:58:13 +02:00
Oliver Hartkopp 15dbb474c7 j1939_timedate_cli: fix sign-compare warning
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-06-07 09:09:26 +02:00
Oliver Hartkopp 4b86049167 Makefile: add j1939 datetime tools
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
2024-06-07 09:09:26 +02:00
Marc Kleine-BuddeandGitHub cf0091c90c Merge pull request #524 from olerem/j1939-datetime-2024.05.15
Add support for the J1939 TimeDate services
2024-06-06 21:29:13 +02:00
Oleksij Rempel d0b04bd456 add j1939 datetime
Implement client and server side for SAE J1939-71:2002 - 5.3 pgn65254 -
Time/Date - TD.

Testing:
./j1939-timedate-srv -i vcan0 -a 0x70 &
./j1939-timedate-cli -i vcan0 -a 0x80 -r 0xff

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-06-06 13:54:26 +02:00
Oleksij Rempel af95ee0c6d move part of isobusfs code to the libj1939
Move part of isobusfs which can be reused by other applications to the
libj1939. By the way, reuse some of new libj1939 code in the j1939cat.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-06-06 13:53:19 +02:00
Oleksij Rempel 69c1e8289d add pr_err and pr_warn macros
This variant will be used in the j19393-timeday code.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-05-30 09:40:23 +02:00
Marc Kleine-BuddeandGitHub 72d097b2f9 Merge pull request #527 from marckleinebudde/buildsystems-cleanup
build-systems: remove autotools and Android.mk
2024-05-29 21:10:26 +02:00
Marc Kleine-Budde 97bfb2960a build-systems: remove autotools and Android.mk
Remove autotools and Android.mk support. This clauses less friction
when adding new tools.

Link: https://github.com/linux-can/can-utils/issues/526
2024-05-29 21:03:17 +02:00
Yegor YefremovandMarc Kleine-Budde 8fdd8f9a5a github-actions: add workflow for NDK build
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-29 21:03:17 +02:00
Marc Kleine-Budde 4597b054e2 github-actions: add cross-compiling 2024-05-29 21:03:16 +02:00
Marc Kleine-Budde bc88e89caf github-actions: replace autotools by cmake 2024-05-29 21:02:59 +02:00
Marc Kleine-Budde db2fe6a605 travis.yml: remove
Travis is not used anymore.
2024-05-29 14:38:19 +02:00
Marc Kleine-BuddeandGitHub bfcf548f97 Merge pull request #542 from marckleinebudde/fix-compiler-errors
Fix compiler errors
2024-05-29 14:37:21 +02:00
Marc Kleine-Budde 1405a90e8b j1939spy: main(): fix shift-count-overflow error
Fix the following error, by converting recvflags into a 64 bit type.

| /home/j1939spy.c: In function 'main':
| /home/j1939spy.c:248:36: error: left shift count >= width of type [-Werror=shift-count-overflow]
|   248 |                 if (recvflags & (1 << SCM_TIMESTAMP)) {
|       |                                    ^~
2024-05-29 14:30:05 +02:00
Marc Kleine-Budde e0bb44c908 isobusfs_cmn: isobusfs_print_timestamp(): always use 64-bit for time stamp formatting
Using C99 `unsigned long long` to format `struct timeval`'s `tv_sec`
and `tv_usec`, fix incorrect print under some 32bit platform which
using time64.
2024-05-29 14:27:34 +02:00
Marc Kleine-BuddeandGitHub c468568f1e Merge pull request #540 from olerem/isobusfs_cmn_warning
isobusfs: address snprintf truncation warning with explicit limits
2024-05-29 11:17:57 +02:00
Oleksij Rempel 8012b3b23d isobusfs: address snprintf truncation warning with explicit limits
Modify the isobusfs_log function in isobusfs_cmn.c to explicitly limit
the lengths of the time_buffer, level_str, and log_entry strings in
the snprintf format string to 40, 10, and 150 characters respectively.
This change acknowledges that truncation may still occur, but it is now
explicit and controlled.

This change silences the following warning:
cmake -DCMAKE_BUILD_TYPE=Debug -D CMAKE_C_COMPILER=gcc -B build
cmake --build build

/home/isobusfs/isobusfs_cmn.c: In function 'isobusfs_log':
/home/isobusfs/isobusfs_cmn.c:104:30: warning: '%s' directive output
may be truncated writing up to 191 bytes into a region of size between
182 and 245 [-Wformat-truncation=]
  104 |                  "[%s] [%s]: %s", time_buffer, level_str, log_entry);
      |                              ^~                           ~~~~~~~~~
/home/isobusfs/isobusfs_cmn.c:103:9: note: 'snprintf' output 12 or more
bytes (assuming 266) into a destination of size 256
  103 |         snprintf(complete_log_entry, sizeof(complete_log_entry),
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  104 |                  "[%s] [%s]: %s", time_buffer, level_str, log_entry);
      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-05-29 10:54:18 +02:00
Marc Kleine-BuddeandGitHub a7ff280c62 Merge pull request #537 from marckleinebudde/bcmserver-fix-warning-better
bcmserver: use pragma to silence unknown pragma option
2024-05-28 12:12:17 +02:00
Marc Kleine-Budde c98e25334b bcmserver: use pragma to silence unknown pragma option
Silence the following warning by switching it of via a pragma.

| bcmserver.c: In function 'main':
| bcmserver.c:159:32: warning: unknown option after '#pragma GCC diagnostic' kind [-Wpragmas]
|   159 | #pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
|       |                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2024-05-28 12:03:15 +02:00
Marc Kleine-BuddeandGitHub c2e40edd24 Merge pull request #517 from marckleinebudde/bcmserver-fix-warning
bcmserver: use pragma to silence gnu-variable-sized-type-not-at-end warning
2024-05-28 11:39:43 +02:00
Marc Kleine-BuddeandGitHub f12a59d780 Merge pull request #534 from yegorich/cmake-format
CMake: resolve linting issues
2024-05-27 12:26:59 +02:00
Yegor Yefremov fbd097edf6 CMake: resolve linting issues
Improve indentation according to the .editorconfig style.

Write commands in lowercase letters.

Break long lines.

Remove double keywords (PRIVATE).

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-27 11:48:25 +02:00
Marc Kleine-BuddeandGitHub 465ee7c203 Merge pull request #533 from yegorich/editorconfig
Add configuration file for EditorConfig
2024-05-26 22:29:27 +02:00
Yegor Yefremov 800c48fb1e Add configuration file for EditorConfig
Handles source and CMake files.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-26 17:42:43 +02:00
Marc Kleine-Budde e865e54490 bcmserver: use pragma to silence gnu-variable-sized-type-not-at-end warning
Silence the following warning by switching it of via a pragma.

| bcmserver.c:159:23: warning: field 'msg_head' with variable sized
| type 'struct bcm_msg_head' not at the end of a struct or class is a
| GNU extension [-Wgnu-variable-sized-type-not-at-end]
|            struct bcm_msg_head msg_head;
|                                ^
2024-05-26 16:57:25 +02:00
Marc Kleine-Budde 4d16dc867d bcmserver: remove trailing whitespace 2024-05-26 16:57:25 +02:00
Marc Kleine-BuddeandGitHub 6c893e5c4f Merge pull request #531 from yegorich/ignore-tags
Ignore ctags generated tags file
2024-05-26 16:26:08 +02:00
Marc Kleine-BuddeandGitHub 7b6daa3aca Merge pull request #532 from yegorich/cmake-fixes
Cmake fixes
2024-05-26 16:23:31 +02:00
Yegor Yefremov 0e4c2d35f2 CMakeLists.txt: print the detected CMake version
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-26 15:22:37 +02:00
Yegor Yefremov 3b5593f499 CMakeLists.txt: bump the minimum required version to 3.5
CMake versions prior to 3.5 are regarded as deprecated and will cause
an error on recent CMake versions.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-26 15:20:45 +02:00
Yegor Yefremov 2a93b10057 Ignore ctags generated tags file
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-26 12:51:33 +02:00
Marc Kleine-BuddeandGitHub b76bb3f66c Merge pull request #530 from olerem/isobusfs-fixes
Isobusfs fixes
2024-05-25 19:23:53 +02:00
Oleksij Rempel 06ab86226a isobusfs_srv_cm: do not try to add padding beyond the buffer
The memset in isobusfs_srv_volume_status_resp() was attempting to make a
padding beyond the buffer. Fix it.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-05-25 07:57:16 +02:00
Oleksij Rempel fc742c574e isobusfs_srv_cm: make sure we do le16toh/htole16 conversation for name_len
name_len is __le16. We need always convert it to host byte order.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-05-25 07:57:16 +02:00
Oleksij Rempel 1e8bc8fd34 isobusfs: do not kill application on error_queue error
Kernel may notify us about some error, which may happens if the bus was
in the error state. But this is not a good reason to kill application,
especially the server side.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
2024-05-25 07:57:16 +02:00
47 changed files with 2879 additions and 1840 deletions
+16
View File
@@ -0,0 +1,16 @@
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[{CMakeLists.txt,*.cmake}]
indent_style = space
indent_size = 2
tab_width = 2
[{*.c,*.h}]
indent_style = tab
indent_size = 8
tab_width = 8
-19
View File
@@ -1,19 +0,0 @@
name: C with autotools
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: autogen
run: ./autogen.sh
- name: configure
run: ./configure
- name: make
run: make
- name: make distcheck
run: make distcheck
+3 -3
View File
@@ -42,7 +42,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -67,4 +67,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
+104
View File
@@ -0,0 +1,104 @@
name: native and cross
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
release:
- "ubuntu:20.04"
- "ubuntu:22.04"
- "ubuntu:24.04"
- "ubuntu:rolling"
- "debian:oldstable-slim"
- "debian:stable-slim"
- "debian:testing-slim"
- "debian:unstable-slim"
- "debian:experimental"
steps:
- uses: actions/checkout@v4
- name: Prepare ${{ matrix.release }} container
env:
release: ${{ matrix.release == 'debian:experimental' && '-t experimental' || '' }}
run: |
podman version
podman run --name stable -di --userns=keep-id:uid=1000,gid=1000 -v "$PWD":/home -w /home ${{ matrix.release }} bash
podman exec -i stable uname -a
podman exec -i stable id
podman exec -i -u root stable apt update
podman exec -e DEBIAN_FRONTEND='noninteractive' -i -u root stable apt install -o APT::Install-Suggests=false -qy ${release} \
clang \
cmake \
gcc \
gcc-aarch64-linux-gnu \
gcc-arm-linux-gnueabihf \
gcc-mips-linux-gnu \
make
- name: Configure & Build with gcc
env:
cc: gcc
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -B build-${cc}
podman exec -i stable cmake --build build-${cc}
- name: Configure & Build with clang
env:
cc: clang
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=${cc} -DENABLE_WERROR=ON -B build-${cc}
podman exec -i stable cmake --build build-${cc}
- name: Configure & Build with arm-linux-gnueabihf-gcc
env:
toolchain: arm-linux-gnueabihf-gcc
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain}
podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with arm-linux-gnueabihf-clang
if:
${{ matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim' }}
env:
toolchain: arm-linux-gnueabihf-clang
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain}
podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with aarch64-linux-gnu-gcc
env:
toolchain: aarch64-linux-gnu-gcc
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain}
podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with aarch64-linux-gnu-clang
if:
${{ matrix.release != 'ubuntu:20.04' && matrix.release != 'debian:oldstable-slim' }}
env:
toolchain: aarch64-linux-gnu-clang
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain}
podman exec -i stable cmake --build build-${toolchain}
- name: Configure & Build with mips-linux-gnu-gcc
env:
toolchain: mips-linux-gnu-gcc
run: |
podman exec -i stable cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/${toolchain}.cmake -DENABLE_WERROR=ON -B build-${toolchain}
podman exec -i stable cmake --build build-${toolchain}
- name: Show logs
if: ${{ failure() }}
run: |
for log in build-*/CMakeFiles/{CMakeOutput.log,CMakeConfigureLog.yaml}; do \
if [ -e ${log} ]; then \
echo "---------------- ${log} ----------------"; \
cat ${log}; \
fi; \
done
+15
View File
@@ -0,0 +1,15 @@
name: NDK
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: CMake and NDK
run: |
cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_WERROR=ON -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -B build
cmake --build build
+4 -26
View File
@@ -1,30 +1,9 @@
*~
*.o
*.lo
*.la
.deps
.libs
.ccls-cache
compile_commands.json
configure
libtool
GNUmakefile
GNUmakefile.in
/aclocal.m4
/autom4te.cache/
/calc-bit-timing/.dirstamp
/config.log
/config.status
/config/autoconf/
/config/m4/libtool.m4
/config/m4/ltoptions.m4
/config/m4/ltsugar.m4
/config/m4/ltversion.m4
/config/m4/lt~obsolete.m4
/isobusfs/.dirstamp
/mcp251xfd/.dirstamp
tags
/build
/asc2log
/bcmserver
@@ -52,6 +31,8 @@ GNUmakefile.in
/j1939cat
/j1939spy
/j1939sr
/j1939-timedate-cli
/j1939-timedate-srv
/log2asc
/log2long
/mcp251xfd-dump
@@ -59,6 +40,3 @@ GNUmakefile.in
/slcand
/slcanpty
/testj1939
/can-utils-*.tar.bz2
/can-utils-*.tar.gz
-164
View File
@@ -1,164 +0,0 @@
language: c
matrix:
include:
# native
- env: test="x64 4.8.4 (make)"
os: linux
dist: trusty
compiler: gcc
script: make
- env: test="x64 4.8.4 (autotools)"
os: linux
dist: trusty
compiler: gcc
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
- env: test="x64 5.0 (autotools)"
os: linux
dist: trusty
compiler: clang
script: ./autogen.sh && ./configure CFLAGS="-Werror -Wno-unused-result" && make distcheck
- env: test="x64 4.8.4 (CMake gcc)"
os: linux
dist: trusty
compiler: gcc
before_script:
- mkdir gcc_rel && cd gcc_rel
- cmake ..
script: make
- env: test="x64 5.0 (CMake clang)"
os: linux
dist: trusty
compiler: clang
before_script:
- mkdir clang_rel && cd clang_rel
- cmake ..
script: make
- env: test="x64 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
# 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:
- echo y | sdkmanager "ndk-bundle"
- echo y | sdkmanager "cmake;3.6.4111459"
before_script:
- export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
- export ANDROID_CMAKE=$ANDROID_HOME/cmake/3.6.4111459/bin/cmake
- export ANDROID_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake
script:
- pushd . && mkdir android15_armeabiv7a_rel && cd android15_armeabiv7a_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android15_x86_rel && cd android15_x86_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_arm64-v8a_rel && cd android21_arm64-v8a_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_x86_64_rel && cd android21_x86_64_rel
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android15_armeabiv7a_dbg && cd android15_armeabiv7a_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=armeabi-v7a -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android15_x86_dbg && cd android15_x86_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-15 -DANDROID_ABI=x86 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_arm64-v8a_dbg && cd android21_arm64-v8a_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
- pushd . && mkdir android21_x86_64_dbg && cd android21_x86_64_dbg
- $ANDROID_CMAKE -DANDROID_PLATFORM=android-21 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN_FILE ..
- make && popd
addons:
apt:
packages:
- autoconf
- automake
- libtool
- m4
- cmake
- ninja-build
sources:
- ubuntu-toolchain-r-test
-498
View File
@@ -1,498 +0,0 @@
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
#
# canlib
#
include $(CLEAR_VARS)
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
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := candump.c
LOCAL_MODULE := candump
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)
#
# cansend
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cansend.c
LOCAL_MODULE := cansend
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)
#
# bcmserver
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bcmserver.c
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
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := calc-bit-timing/can-calc-bit-timing.c
LOCAL_MODULE := can-calc-bit-timing
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
LOCAL_CFLAGS := $(PRIVATE_LOCAL_CFLAGS)
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)
#
# canbusload
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := canbusload.c
LOCAL_MODULE := canbusload
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)
#
# canfdtest
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := canfdtest.c
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)
#
# cangen
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cangen.c
LOCAL_MODULE := cangen
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)
#
# cangw
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cangw.c
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)
#
# canlogserver
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := canlogserver.c
LOCAL_MODULE := canlogserver
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)
#
# canplayer
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := canplayer.c
LOCAL_MODULE := canplayer
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)
#
# cansniffer
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cansniffer.c
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)
#
# isotpdump
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotpdump.c
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)
#
# isotprecv
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotprecv.c
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)
#
# isotpsend
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotpsend.c
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)
#
# isotpserver
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotpserver.c
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)
#
# isotpsniffer
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := 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)
#
# isotptun
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotptun.c
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)
#
# isotpperf
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := isotpperf.c
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)
#
# log2asc
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := log2asc.c
LOCAL_MODULE := log2asc
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)
#
# log2long
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := log2long.c
LOCAL_MODULE := log2long
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)
#
# slcan_attach
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := slcan_attach.c
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)
#
# slcand
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := slcand.c
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)
#
# slcanpty
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := lib.c slcanpty.c
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)
+99 -50
View File
@@ -1,7 +1,9 @@
cmake_minimum_required(VERSION 3.3)
cmake_minimum_required(VERSION 3.5)
project(can-utils LANGUAGES C)
message(STATUS "CMake version: ${CMAKE_VERSION}")
include (CheckFunctionExists)
include (CheckSymbolExists)
include (GNUInstallDirs)
@@ -10,9 +12,16 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
# Add an option to enable treating warnings as errors
option(ENABLE_WERROR "Treat all compiler warnings as errors" OFF)
if(ENABLE_WERROR)
add_compile_options(-Werror)
endif()
add_definitions(-D_GNU_SOURCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-parentheses -Wsign-compare")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSO_RXQ_OVFL=40")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPF_CAN=29")
@@ -29,71 +38,80 @@ include_directories (./include)
check_function_exists(fork HAVE_FORK)
set(PROGRAMS_CANLIB
asc2log
canbusload
candump
cangen
canplayer
cansend
cansequence
log2asc
log2long
slcanpty
asc2log
canbusload
candump
cangen
canplayer
cansend
cansequence
log2asc
log2long
slcanpty
)
if(HAVE_FORK)
list(APPEND PROGRAMS_CANLIB canlogserver)
list(APPEND PROGRAMS_CANLIB canlogserver)
endif()
set(PROGRAMS_J1939
j1939acd
j1939cat
j1939spy
j1939sr
testj1939
j1939acd
j1939cat
j1939spy
j1939sr
testj1939
)
set(PROGRAMS_J1939_TIMEDATE
j1939-timedate-srv
j1939-timedate-cli
)
set(PROGRAMS_ISOBUSFS
isobusfs-srv
isobusfs-cli
isobusfs-srv
isobusfs-cli
)
set(PROGRAMS
${PROGRAMS_CANLIB}
canfdtest
cangw
cansniffer
isotpdump
isotpperf
isotprecv
isotpsend
isotpsniffer
isotptun
slcan_attach
slcand
${PROGRAMS_CANLIB}
canfdtest
cangw
cansniffer
isotpdump
isotpperf
isotprecv
isotpsend
isotpsniffer
isotptun
slcan_attach
slcand
)
if(HAVE_FORK)
list(APPEND PROGRAMS bcmserver)
list(APPEND PROGRAMS isotpserver)
list(APPEND PROGRAMS bcmserver)
list(APPEND PROGRAMS isotpserver)
endif()
add_executable(can-calc-bit-timing
calc-bit-timing/can-calc-bit-timing.c
calc-bit-timing/can-calc-bit-timing.c
)
add_executable(mcp251xfd-dump
mcp251xfd/mcp251xfd-dev-coredump.c
mcp251xfd/mcp251xfd-dump.c
mcp251xfd/mcp251xfd-main.c
mcp251xfd/mcp251xfd-regmap.c
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})
add_library(j1939 STATIC
libj1939.c
libj1939.c
)
target_link_libraries(j1939
PRIVATE can
)
add_library(isobusfs SHARED
@@ -125,8 +143,7 @@ if(NOT ANDROID)
)
target_link_libraries(isobusfs-cli
PRIVATE isobusfs
PRIVATE can
PRIVATE isobusfs can j1939
)
add_executable(isobusfs-srv
@@ -140,19 +157,44 @@ if(NOT ANDROID)
)
target_link_libraries(isobusfs-srv
PRIVATE isobusfs
PRIVATE can
PRIVATE isobusfs can j1939
)
install(TARGETS
isobusfs-cli
isobusfs-srv
DESTINATION ${CMAKE_INSTALL_BINDIR})
set(PUBLIC_HEADER_j1939_TIMEDATE
j1939_timedate/j1939_timedate_cmn.h
)
add_executable(j1939-timedate-cli
j1939_timedate/j1939_timedate_cli.c
)
target_link_libraries(j1939-timedate-cli
PRIVATE can j1939
)
add_executable(j1939-timedate-srv
j1939_timedate/j1939_timedate_srv.c
)
target_link_libraries(j1939-timedate-srv
PRIVATE can j1939
)
install(TARGETS
j1939-timedate-cli
j1939-timedate-srv
DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
add_library(can STATIC
lib.c
canframelen.c
lib.c
canframelen.c
)
foreach(name ${PROGRAMS})
@@ -160,17 +202,24 @@ foreach(name ${PROGRAMS})
if("${name}" IN_LIST PROGRAMS_J1939)
target_link_libraries(${name}
PRIVATE j1939
PRIVATE j1939 can
)
elseif("${name}" IN_LIST PROGRAMS_CANLIB)
target_link_libraries(${name}
PRIVATE can
PRIVATE can
)
endif()
install(TARGETS ${name} DESTINATION ${CMAKE_INSTALL_BINDIR})
endforeach()
install(TARGETS can-calc-bit-timing mcp251xfd-dump DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS
can-calc-bit-timing
mcp251xfd-dump
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake")
add_custom_target(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake"
COMMENT "Add uninstall target"
)
-198
View File
@@ -1,198 +0,0 @@
ACLOCAL_AMFLAGS = -I config/m4
AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_builddir)/include \
$(linux_CFLAGS)
EXTRA_DIST =
# link every app against libcan, it's static so it wouldn't hurt
LDADD = \
libcan.la
noinst_HEADERS = \
canframelen.h \
isobusfs/isobusfs_cli.h \
isobusfs/isobusfs_cmn.h \
isobusfs/isobusfs_cmn_cm.h \
isobusfs/isobusfs_cmn_dh.h \
isobusfs/isobusfs_cmn_fa.h \
isobusfs/isobusfs_cmn_fh.h \
isobusfs/isobusfs_cmn_va.h \
isobusfs/isobusfs_srv.h \
lib.h \
libj1939.h \
terminal.h \
include/linux/can.h \
include/linux/can/bcm.h \
include/linux/can/error.h \
include/linux/can/gw.h \
include/linux/can/isotp.h \
include/linux/can/j1939.h \
include/linux/can/netlink.h \
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
noinst_LTLIBRARIES = \
libcan.la \
libj1939.la
libcan_la_SOURCES = \
lib.c \
canframelen.c
libj1939_la_SOURCES = \
libj1939.c
can_calc_bit_timing_SOURCES = \
calc-bit-timing/can-calc-bit-timing.c \
calc-bit-timing/compat.h
EXTRA_DIST += \
calc-bit-timing/can-calc-bit-timing-v2_6_31.c \
calc-bit-timing/can-calc-bit-timing-v3_18.c \
calc-bit-timing/can-calc-bit-timing-v4_8.c \
calc-bit-timing/can-calc-bit-timing-v5_16.c \
calc-bit-timing/can-calc-bit-timing-v5_19.c \
calc-bit-timing/can-calc-bit-timing-v6_3.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
EXTRA_DIST += \
mcp251xfd/99-devcoredump.rules \
mcp251xfd/data/devcoredump-canfd-v5.15.dump \
mcp251xfd/data/devcoredump-canfd.dump \
mcp251xfd/data/devcoredump-classic-can-v5.15.dump \
mcp251xfd/data/devcoredump-classic-can.dump \
mcp251xfd/data/registers-canfd-v5.15.dump \
mcp251xfd/data/registers-canfd.dump \
mcp251xfd/data/registers-classic-can-v5.15.dump \
mcp251xfd/data/registers-classic-can.dump \
mcp251xfd/devcoredump \
mcp251xfd/mcp251xfd-gen-testdata.sh
lib_LTLIBRARIES = \
libisobusfs.la
libisobusfs_la_SOURCES = \
isobusfs/isobusfs_cmn.c \
isobusfs/isobusfs_cmn_dh.c
bin_PROGRAMS = \
asc2log \
can-calc-bit-timing \
canbusload \
candump \
canfdtest \
cangen \
cangw \
canplayer \
cansend \
cansequence \
cansniffer \
isobusfs-cli \
isobusfs-srv \
isotpdump \
isotpperf \
isotprecv \
isotpsend \
isotpsniffer \
isotptun \
j1939acd \
j1939cat \
j1939spy \
j1939sr \
log2asc \
log2long \
mcp251xfd-dump \
slcan_attach \
slcand \
slcanpty \
testj1939
if HAVE_FORK
bin_PROGRAMS += \
bcmserver \
canlogserver \
isotpserver
endif
isobusfs_cli_SOURCES = \
isobusfs/isobusfs_cli.c \
isobusfs/isobusfs_cli_cm.c \
isobusfs/isobusfs_cli_dh.c \
isobusfs/isobusfs_cli_fa.c \
isobusfs/isobusfs_cli_selftests.c \
isobusfs/isobusfs_cli_int.c
isobusfs_cli_LDADD = \
libisobusfs.la \
libcan.la
isobusfs_srv_SOURCES = \
isobusfs/isobusfs_srv.c \
isobusfs/isobusfs_srv_cm.c \
isobusfs/isobusfs_srv_cm_fss.c \
isobusfs/isobusfs_srv_dh.c \
isobusfs/isobusfs_srv_fa.c \
isobusfs/isobusfs_srv_fh.c \
isobusfs/isobusfs_srv_vh.c
isobusfs_srv_LDADD = \
libisobusfs.la \
libcan.la
EXTRA_DIST += \
isobusfs/isobusfs_create_test_dirs.sh \
isobusfs/isobusfs_create_test_file.sh
j1939acd_LDADD = libj1939.la
j1939cat_LDADD = libj1939.la
j1939spy_LDADD = libj1939.la
j1939sr_LDADD = libj1939.la
testj1939_LDADD = libj1939.la
EXTRA_DIST += \
.travis.yml \
Android.mk \
README.md \
autogen.sh \
can-j1939-kickstart.md \
can-j1939.md \
can-tc-init-etf.sh
MAINTAINERCLEANFILES = \
configure \
GNUmakefile.in \
aclocal.m4 \
config/autoconf/compile \
config/autoconf/config.guess \
config/autoconf/config.sub \
config/autoconf/depcomp \
config/autoconf/install-sh \
config/autoconf/ltmain.sh \
config/autoconf/mdate-sh \
config/autoconf/missing \
config/autoconf/texinfo.tex \
config/m4/libtool.m4 \
config/m4/ltoptions.m4 \
config/m4/ltsugar.m4 \
config/m4/ltversion.m4 \
config/m4/lt~obsolete.m4 \
$(DIST_ARCHIVES)
maintainer-clean-local:
-chmod -R a+rw $(distdir)
-rm -fr $(distdir)
+32 -13
View File
@@ -63,6 +63,10 @@ CPPFLAGS += \
PROGRAMS_CANGW := \
cangw
PROGRAMS_J1939_TIMEDATE := \
j1939-timedate-srv \
j1939-timedate-cli
PROGRAMS_ISOBUSFS := \
isobusfs-srv \
isobusfs-cli
@@ -93,6 +97,7 @@ PROGRAMS_SLCAN := \
PROGRAMS := \
$(PROGRAMS_CANGW) \
$(PROGRAMS_J1939_TIMEDATE) \
$(PROGRAMS_ISOBUSFS) \
$(PROGRAMS_ISOTP) \
$(PROGRAMS_J1939) \
@@ -121,7 +126,7 @@ endif
all: $(PROGRAMS)
clean:
rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o
rm -f $(PROGRAMS) *.o mcp251xfd/*.o isobusfs/*.o j1939_timedate/*.o
install:
mkdir -p $(DESTDIR)$(PREFIX)/bin
@@ -139,13 +144,15 @@ cansend.o: lib.h
log2asc.o: lib.h
log2long.o: lib.h
slcanpty.o: lib.h
j1939acd.o: libj1939.h
j1939cat.o: libj1939.h
j1939spy.o: libj1939.h
j1939sr.o: libj1939.h
testj1939.o: libj1939.h
isobusfs_srv.o: lib.h
isobusfs_c.o: lib.h
j1939acd.o: lib.h libj1939.h
j1939cat.o: lib.h libj1939.h
j1939spy.o: lib.h libj1939.h
j1939sr.o: lib.h libj1939.h
testj1939.o: lib.h libj1939.h
isobusfs_srv.o: lib.h libj1939.h
isobusfs_c.o: lib.h libj1939.h
j1939_timedate_srv.o: lib.h libj1939.h
j1939_timedate_cli.o: lib.h libj1939.h
canframelen.o: canframelen.h
asc2log: asc2log.o lib.o
@@ -159,13 +166,24 @@ cansequence: cansequence.o lib.o
log2asc: log2asc.o lib.o
log2long: log2long.o lib.o
slcanpty: slcanpty.o lib.o
j1939acd: j1939acd.o libj1939.o
j1939cat: j1939cat.o libj1939.o
j1939spy: j1939spy.o libj1939.o
j1939sr: j1939sr.o libj1939.o
testj1939: testj1939.o libj1939.o
j1939acd: j1939acd.o lib.o libj1939.o
j1939cat: j1939cat.o lib.o libj1939.o
j1939spy: j1939spy.o lib.o libj1939.o
j1939sr: j1939sr.o lib.o libj1939.o
testj1939: testj1939.o lib.o libj1939.o
j1939-timedate-srv: lib.o \
libj1939.o \
j1939_timedate/j1939_timedate_srv.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
j1939-timedate-cli: lib.o \
libj1939.o \
j1939_timedate/j1939_timedate_cli.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
isobusfs-srv: lib.o \
libj1939.o \
isobusfs/isobusfs_cmn.o \
isobusfs/isobusfs_srv.o \
isobusfs/isobusfs_srv_cm.o \
@@ -178,6 +196,7 @@ isobusfs-srv: lib.o \
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
isobusfs-cli: lib.o \
libj1939.o \
isobusfs/isobusfs_cmn.o \
isobusfs/isobusfs_cli.o \
isobusfs/isobusfs_cli_cm.o \
+1 -1
View File
@@ -72,7 +72,7 @@ Follow the link to see examples on how this tools can be used:
### Additional Information:
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/Documentation/networking/can.txt)
* [SocketCAN Documentation (Linux Kernel)](https://www.kernel.org/doc/html/latest/networking/can.html)
* [Elinux.org CAN Bus Page](http://elinux.org/CAN_Bus)
* [Debian Package Description](https://packages.debian.org/sid/can-utils)
+491 -82
View File
@@ -58,7 +58,17 @@
#include "lib.h"
#define BUFLEN 400 /* CAN FD mode lines can be pretty long */
#define BUFLEN 6500 /* CAN XL mode lines can be pretty long */
#define NO_DIR '.'
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
#define ASC_F_XLF 0x00400000
#define ASC_F_RES 0x00800000
#define ASC_F_SEC 0x01000000
extern int optind, opterr, optopt;
@@ -69,10 +79,12 @@ static void print_usage(char *prg)
fprintf(stderr, "Options:\n");
fprintf(stderr, "\t-I <infile>\t(default stdin)\n");
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
fprintf(stderr, "\t-d (disable direction information R/T)\n");
fprintf(stderr, "\t-v (verbose)\n");
}
static void prframe(FILE *file, struct timeval *tv, int dev,
struct canfd_frame *cf, char *extra_info)
cu_t *cf, char dir)
{
static char abuf[BUFLEN];
@@ -83,19 +95,23 @@ static void prframe(FILE *file, struct timeval *tv, int dev,
else
fprintf(file, "canX ");
snprintf_canframe(abuf, sizeof(abuf), (cu_t *)cf, 0);
fprintf(file, "%s%s", abuf, extra_info);
snprintf_canframe(abuf, sizeof(abuf), cf, 0);
if (dir == NO_DIR)
fprintf(file, "%s\n", abuf);
else
fprintf(file, "%s %c\n", abuf, dir);
}
static void get_can_id(struct canfd_frame *cf, char *idstring, int base)
static void get_can_id(canid_t *can_id, char *idstring, int base)
{
if (idstring[strlen(idstring)-1] == 'x') {
cf->can_id = CAN_EFF_FLAG;
*can_id = CAN_EFF_FLAG;
idstring[strlen(idstring)-1] = 0;
} else
cf->can_id = 0;
*can_id = 0;
cf->can_id |= strtoul(idstring, NULL, base);
*can_id |= strtoul(idstring, NULL, base);
}
static void calc_tv(struct timeval *tv, struct timeval *read_tv,
@@ -131,7 +147,7 @@ static void calc_tv(struct timeval *tv, struct timeval *read_tv,
}
static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
char base, int dplace, FILE *outfile)
char base, int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
@@ -142,27 +158,26 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
int dlc = 0;
int len = 0;
int data[8];
char tmp1[BUFLEN];
char dir[3]; /* 'Rx' or 'Tx' plus terminating zero */
char *extra_info;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
int i, items;
unsigned long long sec, usec;
/* check for ErrorFrames */
if (sscanf(buf, "%llu.%llu %d %s",
if (sscanf(buf, "%llu.%llu %d %20s",
&sec, &usec,
&interface, tmp1) == 4) {
&interface, idstr) == 4) {
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
if (!strncmp(idstr, "ErrorFrame", strlen("ErrorFrame"))) {
/* 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, "\n");
prframe(outfile, &tv, interface, (cu_t *)&cf, NO_DIR);
fflush(outfile);
return;
}
@@ -172,15 +187,15 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
/* check for CAN frames with (hexa)decimal values */
if (base == 'h')
items = sscanf(buf, "%llu.%llu %d %s %2s %c %x %x %x %x %x %x %x %x %x",
items = sscanf(buf, "%llu.%llu %d %20s %4s %c %x %x %x %x %x %x %x %x %x",
&sec, &usec, &interface,
tmp1, dir, &rtr, &dlc,
idstr, dir, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]);
else
items = sscanf(buf, "%llu.%llu %d %s %2s %c %x %d %d %d %d %d %d %d %d",
items = sscanf(buf, "%llu.%llu %d %20s %4s %c %x %d %d %d %d %d %d %d %d",
&sec, &usec, &interface,
tmp1, dir, &rtr, &dlc,
idstr, dir, &rtr, &dlc,
&data[0], &data[1], &data[2], &data[3],
&data[4], &data[5], &data[6], &data[7]);
@@ -205,9 +220,9 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
/* check for CAN ID with (hexa)decimal value */
if (base == 'h')
get_can_id(&cf, tmp1, 16);
get_can_id(&cf.can_id, idstr, 16);
else
get_can_id(&cf, tmp1, 10);
get_can_id(&cf.can_id, idstr, 10);
/* dlc > 8 => len == CAN_MAX_DLEN => fill len8_dlc value */
if (dlc > CAN_MAX_DLC)
@@ -216,6 +231,9 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
@@ -223,11 +241,6 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
if (dir[0] == 'R')
extra_info = " R\n";
else
extra_info = " T\n";
cf.len = len;
if (rtr == 'r')
cf.can_id |= CAN_RTR_FLAG;
@@ -236,13 +249,13 @@ static void eval_can(char* buf, struct timeval *date_tvp, char timestamps,
cf.data[i] = data[i] & 0xFFU;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf, extra_info);
prframe(outfile, &tv, interface, (cu_t *)&cf, dir[0]);
fflush(outfile);
}
}
static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, FILE *outfile)
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
@@ -251,29 +264,33 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
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 idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/* The CANFD format is mainly in hex representation but <DataLength>
and probably some content we skip anyway. Don't trust the docs! */
/*
* 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 */
/*
* 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, "%llu.%llu %*s %d %2s %s %hhx %hhx %x %d ",
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %hhx %hhx %x %d %n",
&sec, &usec, &interface,
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) {
/* check for valid line with a symbolic name */
if (sscanf(buf, "%llu.%llu %*s %d %2s %s %*s %hhx %hhx %x %d ",
if (sscanf(buf, "%llu.%llu %*s %d %4s %20s %*s %hhx %hhx %x %d %n",
&sec, &usec, &interface,
dir, tmp1, &brs, &esi, &dlc, &dlen) != 9) {
dir, idstr, &brs, &esi, &dlc, &dlen, &n) != 9) {
/* no valid CANFD format pattern */
return;
@@ -290,6 +307,9 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
@@ -298,26 +318,13 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
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);
get_can_id(&cf.can_id, idstr, 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 */
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
@@ -341,12 +348,6 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
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) {
cf.flags = CANFD_FDF;
if (flags & ASC_F_BRS)
@@ -373,18 +374,414 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps,
}
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf, extra_info);
prframe(outfile, &tv, interface, (cu_t *)&cf, dir[0]);
fflush(outfile);
/* No support for really strange CANFD ErrorFrames format m( */
}
static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct can_frame cf = { 0 };
unsigned char ctmp;
unsigned int flags;
int dlc, dlen = 0;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/*
* 59.171614 CANXL 2 Rx CBFF 243215 176 432 msgCanCCTest1 \
* f 8 e1 89 e8 c2 b9 6d 5a f1 174 00000000 00000000 \
* 000000050005000e 0000000000a00010 0000000a000a001d \
* 0000000000a00002 000000100010000f 000000000a00001
*/
/* check for valid line without symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%x %d %n", /* DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* check for valid line with a symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %x %d %n", /* sym name, DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* no valid CAN CC format pattern */
return;
}
}
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
/* check for allowed (unsigned) value ranges */
if ((dlen > CAN_MAX_DLEN) || (dlc > CAN_MAX_RAW_DLC))
return;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
/* check for signed integer overflow */
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
get_can_id(&cf.can_id, idstr, 16);
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip FCRC to get Flags value */
if (sscanf(ptr, "%*x %x ", &flags) != 1)
return;
if (flags & ASC_F_RTR) {
cf.can_id |= CAN_RTR_FLAG;
/* dlen is always 0 for classic CAN RTR frames
but the DLC value is valid in RTR cases */
cf.len = dlc;
/* sanitize payload length value */
if (dlc > CAN_MAX_DLEN)
cf.len = CAN_MAX_DLEN;
}
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((cf.len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC))
cf.len8_dlc = dlc;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (cu_t *)&cf, dir[0]);
fflush(outfile);
}
static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct canfd_frame cf = { 0 };
unsigned char ctmp;
unsigned int flags;
int dlc, dlen = 0;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/*
* 59.171614 CANXL 2 Rx FBFF 243215 176 432 msgCanFDTest2 \
* 9 12 e1 89 e8 c2 b9 6d 5a f1 11 22 33 44 a 12345 00001240 00000000 \
* 000000050005000e 0000000000a00010 0000000a000a001d \
* 0000000000a00002 000000100010000f 000000000a00001
*/
/* check for valid line without symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%x %d %n", /* DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* check for valid line with a symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %x %d %n", /* sym name, DLC, Datalen */
&sec, &usec, &interface, dir,
idstr,
&dlc, &dlen, &n) != 7) {
/* no valid CAN CC format pattern */
return;
}
}
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
/* check for allowed (unsigned) value ranges */
if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC))
return;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
/* check for signed integer overflow */
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
get_can_id(&cf.can_id, idstr, 16);
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip stuff field and FCRC to get Flags value */
if (sscanf(ptr, "%*s %*s %x ", &flags) != 1)
return;
if (!(flags & ASC_F_FDF))
return;
cf.flags = CANFD_FDF;
if (flags & ASC_F_BRS)
cf.flags |= CANFD_BRS;
if (flags & ASC_F_ESI)
cf.flags |= CANFD_ESI;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (cu_t *)&cf, dir[0]);
fflush(outfile);
}
static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
static struct timeval tv; /* current frame timestamp */
static struct timeval read_tv; /* frame timestamp from ASC file */
struct canxl_frame cf = { 0 };
unsigned char sdt, vcid, secbit, ctmp;
unsigned int af, flags;
int dlc, dlen = 0;
char idstr[21];
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char *ptr;
int i;
int n = 0; /* sscanf consumed characters */
unsigned long long sec, usec;
/*
* 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \
* e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \
* ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \
* 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \
* 000000000a00001
*/
/* check for valid line without symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%hhx %hhx %x %d " /* SDT, SEC, DLC, Datalen */
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
&sec, &usec, &interface, dir,
idstr,
&sdt, &secbit, &dlc, &dlen,
&vcid, &af, &n) != 11) {
/* check for valid line with a symbolic name */
if (sscanf(buf,
"%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */
"%*s %*s %*s %20s " /* frame format, msg dur, bit count, ID */
"%*s %hhx %hhx %x %d " /* sym name, SDT, SEC, DLC, Datalen */
"%*s %*s %hhx %x %n", /* stuff bit count, crc, VCID, AF */
&sec, &usec, &interface, dir,
idstr,
&sdt, &secbit, &dlc, &dlen,
&vcid, &af, &n) != 11) {
/* no valid CANXL format pattern */
return;
}
}
read_tv.tv_sec = sec;
read_tv.tv_usec = usec;
/* check for allowed (unsigned) value ranges */
if ((dlen > CANXL_MAX_DLEN) || (dlc > CANXL_MAX_DLC) || (secbit > 1))
return;
cf.sdt = sdt;
cf.af = af;
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (disable_dir)
dir[0] = NO_DIR;
/* check for signed integer overflow */
if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100)
return;
/* check for signed integer overflow */
if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10)
return;
/* don't trust ASCII content - sanitize data length */
if (dlen != dlc + 1)
return;
get_can_id(&cf.prio, idstr, 16);
if ((cf.prio & CANXL_PRIO_MASK) != cf.prio)
return;
if (vcid)
cf.prio |= (vcid << CANXL_VCID_OFFSET);
ptr = buf + n; /* start of ASCII hex frame data */
cf.len = dlen;
for (i = 0; i < dlen; i++) {
ctmp = asc2nibble(ptr[0]);
if (ctmp > 0x0F)
return;
cf.data[i] = (ctmp << 4);
ctmp = asc2nibble(ptr[1]);
if (ctmp > 0x0F)
return;
cf.data[i] |= ctmp;
ptr += 3; /* start of next ASCII hex byte */
}
/* skip FCRC to get Flags value */
if (sscanf(ptr, "%*x %x ", &flags) != 1)
return;
/* mandatory for CAN XL frames */
if (!(flags & ASC_F_XLF))
return;
/* mark as CAN XL */
cf.flags = CANXL_XLF;
if (flags & ASC_F_SEC)
cf.flags |= CANXL_SEC;
if (flags & ASC_F_RES)
cf.flags |= CANXL_RRS;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, (cu_t *)&cf, dir[0]);
fflush(outfile);
/* No support for CAN XL ErrorFrames */
}
static void eval_canxl(char* buf, struct timeval *date_tvp, char timestamps,
int dplace, int disable_dir, FILE *outfile)
{
int interface;
char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */
char frfo[5]; /* frame format 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' plus terminating zero */
unsigned long long sec, usec;
/*
* The CANXL format is mainly in hex representation but <DataLength>
* and probably some content we skip anyway. Check out the new spec:
* CAN, Log & Trigger ASC Logging Format Spec V 1.4.17 of 2024-05-21
*/
/*
* This is a CAN XL ("XLFF") example for the CANXL Message Event:
*
* 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \
* e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \
* ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \
* 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \
* 000000000a00001
*/
/* check for valid line until frame format tag */
if (sscanf(buf, "%llu.%llu %*s %d %4s %4s ",
&sec, &usec, &interface, dir, frfo) != 5)
return; /* no valid CANXL format pattern */
if (strlen(dir) != 2) /* "Rx" or "Tx" */
return;
if (strlen(frfo) != 4) /* 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' */
return;
if (!strncmp(frfo, "XLFF", 4))
eval_canxl_xl(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "FBFF", 4))
eval_canxl_fd(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "FEFF", 4))
eval_canxl_fd(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "CBFF", 4))
eval_canxl_cc(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(frfo, "CEFF", 4))
eval_canxl_cc(buf, date_tvp, timestamps, dplace, disable_dir, outfile);
}
static int get_date(struct timeval *tv, char *date)
{
struct tm tms;
unsigned int msecs = 0;
if (strcasestr(date, " pm ") != NULL) {
if ((strcasestr(date, " am ") != NULL) || (strcasestr(date, " pm ") != NULL)) {
/* assume EN/US date due to existing am/pm field */
if (!setlocale(LC_TIME, "en_US")) {
@@ -393,9 +790,11 @@ static int get_date(struct timeval *tv, char *date)
}
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) */
/*
* 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);
@@ -410,9 +809,11 @@ static int get_date(struct timeval *tv, char *date)
}
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) */
/*
* 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);
@@ -434,11 +835,11 @@ static int get_date(struct timeval *tv, char *date)
int main(int argc, char **argv)
{
char buf[BUFLEN], tmp1[BUFLEN], tmp2[BUFLEN];
char buf[BUFLEN], tmp1[10], tmp2[10];
FILE *infile = stdin;
FILE *outfile = stdout;
static int verbose;
static int verbose, disable_dir;
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 */
@@ -446,7 +847,7 @@ int main(int argc, char **argv)
int opt;
unsigned long long sec, usec;
while ((opt = getopt(argc, argv, "I:O:v?")) != -1) {
while ((opt = getopt(argc, argv, "I:O:dv?")) != -1) {
switch (opt) {
case 'I':
infile = fopen(optarg, "r");
@@ -464,6 +865,10 @@ int main(int argc, char **argv)
}
break;
case 'd':
disable_dir = 1;
break;
case 'v':
verbose = 1;
break;
@@ -488,7 +893,7 @@ int main(int argc, char **argv)
/* check for base and timestamp entries in the header */
if ((!base) &&
(sscanf(buf, "base %s timestamps %s", tmp1, tmp2) == 2)) {
(sscanf(buf, "base %9s timestamps %9s", tmp1, tmp2) == 2)) {
base = tmp1[0];
timestamps = tmp2[0];
if (verbose)
@@ -522,7 +927,7 @@ int main(int argc, char **argv)
}
/* check for decimal places length in valid CAN frames */
if (sscanf(buf, "%llu.%s %s ", &sec, tmp2,
if (sscanf(buf, "%llu.%9s %9s ", &sec, tmp2,
tmp1) != 3)
continue; /* dplace remains zero until first found CAN frame */
@@ -537,15 +942,19 @@ int main(int argc, char **argv)
}
}
/* the representation of a valid CAN frame is known here */
/* so try to get CAN frames and ErrorFrames and convert them */
/*
* The representation of a valid CAN frame is known here.
* So try to get CAN frames and ErrorFrames and convert them.
*/
/* check classic CAN format or the CANFD tag which can take both types */
if (sscanf(buf, "%llu.%llu %s ", &sec, &usec, tmp1) == 3){
if (!strncmp(tmp1, "CANFD", 5))
eval_canfd(buf, &date_tv, timestamps, dplace, outfile);
/* check classic CAN format or the CANFD/CANXL tag which can take different types */
if (sscanf(buf, "%llu.%llu %9s ", &sec, &usec, tmp1) == 3) {
if (!strncmp(tmp1, "CANXL", 5))
eval_canxl(buf, &date_tv, timestamps, dplace, disable_dir, outfile);
else if (!strncmp(tmp1, "CANFD", 5))
eval_canfd(buf, &date_tv, timestamps, dplace, disable_dir, outfile);
else
eval_can(buf, &date_tv, timestamps, base, dplace, outfile);
eval_can(buf, &date_tv, timestamps, base, dplace, disable_dir, outfile);
}
}
fclose(outfile);
-22
View File
@@ -1,22 +0,0 @@
#!/bin/bash
#
# usage:
#
# banner <target name>
#
banner() {
echo
TG=`echo $1 | sed -e "s,/.*/,,g"`
LINE=`echo $TG |sed -e "s/./-/g"`
echo $LINE
echo $TG
echo $LINE
echo
}
banner "autoreconf"
autoreconf --force --install -Wall || exit $?
banner "Finished"
+6 -2
View File
@@ -155,10 +155,14 @@ int main(void)
char format[FORMATSZ];
char rxmsg[50];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
struct {
struct bcm_msg_head msg_head;
struct can_frame frame;
} msg;
#pragma GCC diagnostic pop
if (snprintf(format, FORMATSZ, "< %%%ds %%c %%lu %%lu %%x %%hhu "
"%%hhx %%hhx %%hhx %%hhx %%hhx %%hhx "
@@ -194,7 +198,7 @@ int main(void)
exit(1);
}
while (1) {
while (1) {
sa = accept(sl,(struct sockaddr *)&clientaddr, &sin_size);
if (sa > 0 ){
if (!fork())
@@ -295,7 +299,7 @@ int main(void)
items = sscanf(buf, format,
ifr.ifr_name,
&cmd,
&cmd,
&msg.msg_head.ival2.tv_sec,
&msg.msg_head.ival2.tv_usec,
&msg.msg_head.can_id,
+180 -180
View File
@@ -1,180 +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!
# 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!
+306 -81
View File
@@ -45,14 +45,17 @@
#include <ctype.h>
#include <libgen.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -65,34 +68,69 @@
#include "terminal.h"
#include "canframelen.h"
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
#define ANYDEV "any" /* name of interface to receive from any CAN interface */
#define MAXDEVS 20 /* max. number of CAN interfaces given on the cmdline */
#define PERCENTRES 5 /* resolution in percent for bargraph */
#define NUMBAR (100 / PERCENTRES) /* number of bargraph elements */
#define BRSTRLEN 20
#define VISUAL_WINDOW 90 /* window width for visualization */
/*
* Inspired from
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/
* include/linux/sched/loadavg.h
*
* Following are the fixed-point math constants and the exponential-damping
* factors for:
* - 1 samples/s in 1 minute
* - 1 samples/s in 5 minutes
* - 1 samples/s in 15 minutes
* in fixed-point representation.
*/
#define FP_SHIFT 12 /* bits of precision */
#define FP_ONE (1 << FP_SHIFT) /* 1.0 fixed-point representation */
#define EXP_1 4028 /* (1 / e ^ (1 / 60)) * FP_ONE */
#define EXP_5 4082 /* (1 / e ^ (1 / 300)) * FP_ONE */
#define EXP_15 4091 /* (1 / e ^ (1 / 900)) * FP_ONE */
extern int optind, opterr, optopt;
static struct {
char devname[IFNAMSIZ + 1];
char bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */
char recv_direction;
int ifindex;
unsigned int bitrate;
unsigned int dbitrate;
unsigned int recv_frames;
unsigned int recv_bits_total;
unsigned int recv_bits_payload;
unsigned int recv_bits_dbitrate;
} stat[MAXSOCK + 1];
unsigned int load_min;
unsigned int load_max;
unsigned int load_1m;
unsigned int load_5m;
unsigned int load_15m;
unsigned int loads[VISUAL_WINDOW];
unsigned int index;
} stat[MAXDEVS + 1];
static volatile int running = 1;
static volatile sig_atomic_t signal_num;
static int max_devname_len; /* to prevent frazzled device name output */
static int max_bitrate_len;
static int currmax;
static int max_bitratestr_len;
static unsigned int currmax;
static unsigned char redraw;
static unsigned char timestamp;
static unsigned char color;
static unsigned char bargraph;
static bool statistic;
static bool reset;
static bool visualize;
static enum cfl_mode mode = CFL_WORSTCASE;
static char *prg;
static struct termios old;
static void print_usage(char *prg)
{
@@ -106,21 +144,23 @@ static void print_usage(char *prg)
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, " -s (show statistics, press 'r' to reset)\n");
fprintf(stderr, " -v (show busload visualization)\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>[,<dbitrate>]\n\n");
fprintf(stderr, "Up to %d CAN interfaces with mandatory bitrate can be specified on the \n", MAXDEVS);
fprintf(stderr, "commandline in the form: <ifname>@<bitrate>[,<dbitrate>]\n");
fprintf(stderr, "The interface name 'any' enables an auto detection with the given bitrate[s]\n\n");
fprintf(stderr, "The bitrate is mandatory as it is needed to know the CAN bus bitrate to\n");
fprintf(stderr, "calculate the bus load percentage based on the received CAN frames.\n");
fprintf(stderr, "Due to the bitstuffing estimation the calculated busload may exceed 100%%.\n");
fprintf(stderr, "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, "(interface) (received CAN frames) (bits total) (bits payload) (bits payload brs)\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");
fprintf(stderr, " can1@500000 796 75140 37728 15%% |XXX.................|\n");
fprintf(stderr, " can2@500000 0 0 0 0%% |....................|\n");
fprintf(stderr, " can3@500000 47 4633 2424 0%% |....................|\n");
fprintf(stderr, "\nuser$> canbusload can0@100000 can1@500000,2000000 can2@500000 -r -t -b -c\n\n");
fprintf(stderr, "%s 2024-08-08 16:30:05 (worst case bitstuffing)\n", prg);
fprintf(stderr, " can0@100k 192 21980 9136 0 21%% |TTTT................|\n");
fprintf(stderr, " can1@500k/2M 2651 475500 234448 131825 74%% |XXXXXXXXXXXXXX......|\n");
fprintf(stderr, " can2@500k 855 136777 62968 35219 27%% |RRRRR...............|\n");
fprintf(stderr, "\n");
}
@@ -130,9 +170,45 @@ static void sigterm(int signo)
signal_num = signo;
}
static int add_bitrate(char *brstr, unsigned int bitrate)
{
if (bitrate % 1000000 == 0)
return sprintf(brstr, "%dM", bitrate / 1000000);
if (bitrate % 1000 == 0)
return sprintf(brstr, "%dk", bitrate / 1000);
return sprintf(brstr, "%d", bitrate);
}
static void create_bitrate_string(int stat_idx, int *max_bitratestr_len)
{
int ptr;
ptr = add_bitrate(&stat[stat_idx].bitratestr[0], stat[stat_idx].bitrate);
if (stat[stat_idx].bitrate != stat[stat_idx].dbitrate) {
ptr += sprintf(&stat[stat_idx].bitratestr[ptr], "/");
ptr += add_bitrate(&stat[stat_idx].bitratestr[ptr], stat[stat_idx].dbitrate);
}
if (ptr > *max_bitratestr_len)
*max_bitratestr_len = ptr;
}
static unsigned int calc_load(unsigned int load_fp,
unsigned int exp_fp,
unsigned int sample)
{
unsigned int sample_fp = sample << FP_SHIFT;
unsigned int damped_sum = (load_fp * exp_fp) +
(sample_fp * (FP_ONE - exp_fp));
return damped_sum >> FP_SHIFT;
}
static void printstats(int signo)
{
int i, j, percent;
unsigned int i, j, k, percent, index;
if (redraw)
printf("%s", CSR_HOME);
@@ -194,15 +270,39 @@ static void printstats(int signo)
else
percent = 0;
printf(" %*s@%-*d %5d %7d %6d %6d %3d%%",
printf(" %*s@%-*s %5d %7d %7d %7d %3d%%",
max_devname_len, stat[i].devname,
max_bitrate_len, stat[i].bitrate,
max_bitratestr_len, stat[i].bitratestr,
stat[i].recv_frames,
stat[i].recv_bits_total,
stat[i].recv_bits_payload,
stat[i].recv_bits_dbitrate,
percent);
if (statistic) {
if (reset) {
stat[i].load_min = UINT_MAX;
stat[i].load_max = 0;
stat[i].load_1m = 0;
stat[i].load_5m = 0;
stat[i].load_15m = 0;
}
stat[i].load_min = MIN(stat[i].load_min, percent);
stat[i].load_max = MAX(stat[i].load_max, percent);
stat[i].load_1m = calc_load(stat[i].load_1m, EXP_1, percent);
stat[i].load_5m = calc_load(stat[i].load_5m, EXP_5, percent);
stat[i].load_15m = calc_load(stat[i].load_15m, EXP_15, percent);
printf(" min:%3d%%, max:%3d%%, load:%3d%% %3d%% %3d%%",
stat[i].load_min,
stat[i].load_max,
(stat[i].load_1m + (FP_ONE >> 1)) >> FP_SHIFT,
(stat[i].load_5m + (FP_ONE >> 1)) >> FP_SHIFT,
(stat[i].load_15m + (FP_ONE >> 1)) >> FP_SHIFT);
}
if (bargraph) {
printf(" |");
@@ -212,7 +312,7 @@ static void printstats(int signo)
for (j = 0; j < NUMBAR; j++) {
if (j < percent / PERCENTRES)
printf("X");
printf("%c", stat[i].recv_direction);
else
printf(".");
}
@@ -220,6 +320,28 @@ static void printstats(int signo)
printf("|");
}
if (visualize) {
stat[i].loads[stat[i].index] = percent;
stat[i].index = (stat[i].index + 1) % VISUAL_WINDOW;
printf("\n");
for (j = 0; j < NUMBAR; j++) {
printf("%3d%%|", (NUMBAR - j) * PERCENTRES);
index = stat[i].index;
for (k = 0; k < VISUAL_WINDOW; k++) {
percent = stat[i].loads[index];
if ((percent / PERCENTRES) >= (NUMBAR - j))
printf("X");
else
printf(".");
index = (index + 1) % VISUAL_WINDOW;
}
printf("\n");
}
}
if (color)
printf("%s", ATTRESET);
@@ -230,8 +352,11 @@ static void printstats(int signo)
stat[i].recv_bits_total = 0;
stat[i].recv_bits_dbitrate = 0;
stat[i].recv_bits_payload = 0;
stat[i].recv_direction = '.';
}
reset = false;
if (!redraw)
printf("\n");
@@ -240,17 +365,35 @@ static void printstats(int signo)
alarm(1);
}
void cleanup()
{
tcsetattr(STDIN_FILENO, TCSANOW, &old);
}
int main(int argc, char **argv)
{
fd_set rdfs;
int s[MAXSOCK];
int s;
int opt;
char *ptr, *nptr;
struct sockaddr_can addr;
struct canfd_frame frame;
int nbytes, i;
struct ifreq ifr;
struct iovec iov;
struct msghdr msg;
unsigned int i;
int nbytes;
int have_anydev = 0;
unsigned int anydev_bitrate = 0;
unsigned int anydev_dbitrate = 0;
char anydev_bitratestr[BRSTRLEN]; /* 100000/2000000 => 100k/2M */
struct termios temp;
tcgetattr(STDIN_FILENO, &old);
atexit(cleanup);
temp = old;
temp.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &temp);
signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm);
@@ -260,7 +403,7 @@ int main(int argc, char **argv)
prg = basename(argv[0]);
while ((opt = getopt(argc, argv, "rtbcieh?")) != -1) {
while ((opt = getopt(argc, argv, "rtbciesvh?")) != -1) {
switch (opt) {
case 'r':
redraw = 1;
@@ -286,6 +429,15 @@ int main(int argc, char **argv)
mode = CFL_EXACT;
break;
case 's':
statistic = true;
reset = true;
break;
case 'v':
visualize = true;
break;
default:
print_usage(prg);
exit(1);
@@ -300,27 +452,22 @@ int main(int argc, char **argv)
currmax = argc - optind; /* find real number of CAN devices */
if (currmax > MAXSOCK) {
printf("More than %d CAN devices given on commandline!\n", MAXSOCK);
if (currmax > MAXDEVS) {
printf("More than %d CAN devices given on commandline!\n", MAXDEVS);
return 1;
}
/* prefill stat[] array with given interface assignments */
for (i = 0; i < currmax; i++) {
ptr = argv[optind + i];
ptr = argv[optind + i + have_anydev];
nbytes = strlen(ptr);
if (nbytes >= (int)(IFNAMSIZ + sizeof("@1000000") + 1)) {
if (nbytes >= (int)(IFNAMSIZ + sizeof("@1000000,2000000") + 1)) {
printf("name of CAN device '%s' is too long!\n", ptr);
return 1;
}
pr_debug("open %d '%s'.\n", i, ptr);
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s[i] < 0) {
perror("socket");
return 1;
}
pr_debug("handle %d '%s'.\n", i, ptr);
nptr = strchr(ptr, '@');
@@ -330,55 +477,76 @@ int main(int argc, char **argv)
return 1;
}
/* interface name length */
nbytes = nptr - ptr; /* interface name is up the first '@' */
if (nbytes >= (int)IFNAMSIZ) {
printf("name of CAN device '%s' is too long!\n", ptr);
return 1;
}
/* copy interface name to stat[] entry */
strncpy(stat[i].devname, ptr, nbytes);
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, ptr, nbytes);
if (nbytes > max_devname_len)
max_devname_len = nbytes; /* for nice printing */
char *endp;
stat[i].bitrate = strtol(nptr + 1, &endp, 0); /* bitrate is placed behind the '@' */
/* bitrate is placed behind the '@' */
stat[i].bitrate = strtol(nptr + 1, &endp, 0);
/* check for CAN FD additional data bitrate */
if (*endp == ',')
/* data bitrate is placed behind the ',' */
stat[i].dbitrate = strtol(endp + 1, &endp, 0);
else
stat[i].dbitrate = stat[i].bitrate;
if (!stat[i].bitrate || stat[i].bitrate > 1000000) {
if (!stat[i].bitrate || stat[i].bitrate > 1000000 ||
!stat[i].dbitrate || stat[i].dbitrate > 8000000) {
printf("invalid bitrate for CAN device '%s'!\n", ptr);
return 1;
}
nbytes = strlen(nptr + 1);
if (nbytes > max_bitrate_len)
max_bitrate_len = nbytes; /* for nice printing */
/* prepare bitrate string for hot path */
create_bitrate_string(i, &max_bitratestr_len);
pr_debug("using interface name '%s'.\n", ifr.ifr_name);
stat[i].recv_direction = '.';
/* try to switch the socket into CAN FD mode */
const int canfd_on = 1;
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
exit(1);
/* handling for 'any' device */
if (have_anydev == 0 && strcmp(ANYDEV, stat[i].devname) == 0) {
anydev_bitrate = stat[i].bitrate;
anydev_dbitrate = stat[i].dbitrate;
memcpy(anydev_bitratestr, stat[i].bitratestr, BRSTRLEN);
/* no real interface: remove this command line entry */
have_anydev = 1;
currmax--;
i--;
} else {
stat[i].ifindex = if_nametoindex(stat[i].devname);
if (!stat[i].ifindex) {
printf("invalid CAN device '%s'!\n", stat[i].devname);
return 1;
}
pr_debug("using interface name '%s'.\n", stat[i].devname);
}
}
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("socket");
return 1;
}
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
/* try to switch the socket into CAN FD mode */
const int canfd_on = 1;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
addr.can_family = AF_CAN;
addr.can_ifindex = 0; /* any CAN device */
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
alarm(1);
@@ -386,43 +554,100 @@ int main(int argc, char **argv)
if (redraw)
printf("%s", CLR_SCREEN);
/* these settings are static and can be held out of the hot path */
iov.iov_base = &frame;
msg.msg_name = &addr;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
while (running) {
FD_ZERO(&rdfs);
for (i = 0; i < currmax; i++)
FD_SET(s[i], &rdfs);
FD_SET(s, &rdfs);
FD_SET(STDIN_FILENO, &rdfs);
if (select(s[currmax - 1] + 1, &rdfs, NULL, NULL, NULL) < 0) {
if (select(s + 1, &rdfs, NULL, NULL, NULL) < 0) {
//perror("pselect");
continue;
}
for (i = 0; i < currmax; i++) { /* check all CAN RAW sockets */
if (FD_ISSET(s[i], &rdfs)) {
nbytes = read(s[i], &frame, sizeof(frame));
if (nbytes < 0) {
perror("read");
return 1;
}
if (nbytes < (int)sizeof(struct can_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
stat[i].recv_frames++;
stat[i].recv_bits_payload += frame.len * 8;
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
&frame, mode, sizeof(frame));
stat[i].recv_bits_total += can_frame_length(&frame,
mode, nbytes);
if (FD_ISSET(STDIN_FILENO, &rdfs)) {
if (getchar() == 'r') {
reset = true;
}
}
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = 0;
msg.msg_flags = 0;
nbytes = recvmsg(s, &msg, 0);
if (nbytes < 0) {
perror("read");
return 1;
}
if (nbytes != (int)sizeof(struct can_frame) &&
nbytes != (int)sizeof(struct canfd_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
/* find received ifindex in stat[] array */
for (i = 0; i < currmax; i++) {
if (stat[i].ifindex == addr.can_ifindex)
break;
}
/* not found? check for unknown interface */
if (i >= currmax) {
/* drop unwanted traffic */
if (have_anydev == 0)
continue;
/* can we add another interface? */
if (currmax >= MAXDEVS)
continue;
/* add an new entry */
stat[i].ifindex = addr.can_ifindex;
stat[i].bitrate = anydev_bitrate;
stat[i].dbitrate = anydev_dbitrate;
memcpy(stat[i].bitratestr, anydev_bitratestr, BRSTRLEN);
stat[i].recv_direction = '.';
if_indextoname(addr.can_ifindex, stat[i].devname);
nbytes = strlen(stat[i].devname);
if (nbytes > max_devname_len)
max_devname_len = nbytes; /* for nice printing */
currmax++;
}
if (msg.msg_flags & MSG_DONTROUTE) {
/* TX direction */
if (stat[i].recv_direction == '.')
stat[i].recv_direction = 'T';
else if (stat[i].recv_direction == 'R')
stat[i].recv_direction = 'X';
} else {
/* RX direction */
if (stat[i].recv_direction == '.')
stat[i].recv_direction = 'R';
else if (stat[i].recv_direction == 'T')
stat[i].recv_direction = 'X';
}
stat[i].recv_frames++;
stat[i].recv_bits_payload += frame.len * 8;
stat[i].recv_bits_dbitrate += can_frame_dbitrate_length(
&frame, mode, sizeof(frame));
stat[i].recv_bits_total += can_frame_length(&frame,
mode, nbytes);
}
for (i = 0; i < currmax; i++)
close(s[i]);
close(s);
if (signal_num)
return 128 + signal_num;
+1 -1
View File
@@ -157,7 +157,7 @@ static int compare_frame(const struct canfd_frame *exp, const struct canfd_frame
} else {
for (i = 0; i < rec->len; i++) {
if (rec->data[i] != (uint8_t)(exp->data[i] + inc)) {
printf("Databyte %x mismatch!\n", i);
printf("Databyte 0x%x mismatch!\n", i);
print_compare(expected_can_id, exp->data, exp->len,
rec->can_id, rec->data, rec->len, inc);
running = 0;
+21 -1
View File
@@ -189,6 +189,7 @@ static void print_usage(char *prg)
fprintf(stderr, " -A <mode> (CAN XL AF generation mode - see below, no e/o mode)\n");
fprintf(stderr, " -V <mode> (CAN XL VCID generation mode - see below, no e/o mode)\n");
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
fprintf(stderr, " -P <priority> (set socket priority using SO_PRIORITY)\n");
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n");
@@ -479,6 +480,7 @@ int main(int argc, char **argv)
uint64_t incdata = 0;
__u8 *data; /* base pointer for CC/FD or XL data */
int incdlc = 0;
int priority = -1;
unsigned long rnd;
unsigned char fixdata[CANFD_MAX_DLEN];
unsigned char rand_position[CANFD_MAX_DLEN] = { 0 };
@@ -512,7 +514,7 @@ int main(int argc, char **argv)
{ 0, 0, 0, 0 },
};
while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:n:ixc:vh?", long_options, NULL)) != -1) {
while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:P:n:ixc:vh?", long_options, NULL)) != -1) {
switch (opt) {
case 'g':
gap = strtod(optarg, NULL);
@@ -682,6 +684,14 @@ int main(int argc, char **argv)
}
break;
case 'P':
priority = atoi(optarg);
if (priority < 0) {
printf("socket priority has to be >= 0\n");
exit(1);
}
break;
case 'i':
ignore_enobufs = true;
break;
@@ -750,6 +760,16 @@ int main(int argc, char **argv)
*/
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/*
* user can use tc to configure the queuing discipline (e.g. mqprio),
* together with SO_PRIORITY option to specify the message send from
* this socket should go to which queue.
*/
if (priority >= 0 &&
setsockopt(s, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority))) {
printf("error setting SO_PRIORITY\n");
}
if (loopback_disable) {
const int loopback = 0;
+5
View File
@@ -0,0 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
+5
View File
@@ -0,0 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
+5
View File
@@ -0,0 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
+5
View File
@@ -0,0 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
+24 -19
View File
@@ -1,19 +1,24 @@
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
endif()
file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files)
string(REGEX REPLACE "[\r\n]" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling ${file}")
if(EXISTS "${file}")
file(REMOVE ${file})
if (EXISTS "${file}")
message(FATAL_ERROR "Problem when removing ${file}, please check your permissions")
endif()
else()
message(STATUS "File ${file} does not exist.")
endif()
endforeach()
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
message(FATAL_ERROR
"Cannot find install manifest: \
${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt"
)
endif()
file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files)
string(REGEX REPLACE "[\r\n]" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling ${file}")
if(EXISTS "${file}")
file(REMOVE ${file})
if (EXISTS "${file}")
message(
FATAL_ERROR "Problem when removing ${file}, \
please check your permissions"
)
endif()
else()
message(STATUS "File ${file} does not exist.")
endif()
endforeach()
+5
View File
@@ -0,0 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR mips)
set(CMAKE_C_COMPILER mips-linux-gnu-gcc)
set(CMAKE_C_COMPILER_TARGET mips-linux-gnu)
-141
View File
@@ -1,141 +0,0 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59])
AC_INIT([can-utils],[trunk],[linux-can@vger.kernel.org])
AC_CONFIG_SRCDIR([lib.c])
AC_CONFIG_MACRO_DIR([config/m4])
AC_CONFIG_AUX_DIR([config/autoconf])
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
# If possible, enable extensions to Posix
AC_USE_SYSTEM_EXTENSIONS
#AM_MAINTAINER_MODE
CFLAGS="${CFLAGS} -Wall"
#
# Checks for programs.
#
AC_PROG_CC
LT_INIT(win32-dll)
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2 subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
#
# Checks for header files.
#
AC_CHECK_HEADERS([ \
fcntl.h \
limits.h \
locale.h \
stdint.h \
stdlib.h \
string.h \
syslog.h \
termios.h \
unistd.h \
\
netinet/in.h \
\
sys/ioctl.h \
sys/socket.h \
sys/time.h \
])
#
# Checks for typedefs, structures, and compiler characteristics.
#
AC_C_INLINE
AC_SYS_LARGEFILE
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_UINT64_T
#
# Checks for library functions.
#
AC_FUNC_FORK
AC_FUNC_MKTIME
AC_CHECK_FUNCS([ \
alarm \
gettimeofday \
localtime_r \
memset \
select \
setlocale \
socket \
strchr \
strerror \
strstr \
strtoul \
])
AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork_works" = "yes")
# glibc versions before 2.17 needs to link with -lrt for clock_nanosleep
AC_SEARCH_LIBS([clock_nanosleep], [rt])
AC_CHECK_DECL(SO_RXQ_OVFL,,
[AC_DEFINE([SO_RXQ_OVFL], [40], [SO_RXQ_OVFL])],
[[#include <linux/net.h>]]
)
AC_CHECK_DECL(PF_CAN,,
[AC_DEFINE([PF_CAN], [29], [PF_CAN])],
[[#include <net/if.h>]]
)
AC_CHECK_DECL(AF_CAN,,
[AC_DEFINE([AF_CAN], [PF_CAN], [AF_CAN])],
[[#include <net/if.h>]]
)
AC_CHECK_DECL(N_SLCAN,,
[AC_DEFINE([N_SLCAN], [17], [N_SLCAN])],
[[#include <linux/tty.h>]]
)
AC_CHECK_DECL(SCM_TIMESTAMPING_OPT_STATS,,
[AC_DEFINE([SCM_TIMESTAMPING_OPT_STATS], [54], [SCM_TIMESTAMPING_OPT_STATS])],
[[#include <linux/net.h>]]
)
AC_CHECK_DECL(CLOCK_TAI,,
[AC_DEFINE([CLOCK_TAI], [11], [CLOCK_TAI])],
[[#include <time.h>]]
)
AC_CHECK_DECL(SO_TXTIME,,
[AC_DEFINE([SO_TXTIME], [61], [SO_TXTIME])],
[[#include <sys/socket.h>]]
)
AC_CHECK_DECL(SCM_TXTIME,,
[AC_DEFINE([SCM_TXTIME], [SO_TXTIME], [SCM_TXTIME])],
[[#include <sys/socket.h>]]
)
#
# Debugging
#
AC_MSG_CHECKING([whether to enable debugging])
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug], [enable debugging [[default=no]]]),
[case "$enableval" in
(y | yes) CONFIG_DEBUG=yes ;;
(*) CONFIG_DEBUG=no ;;
esac],
[CONFIG_DEBUG=no])
AC_MSG_RESULT([${CONFIG_DEBUG}])
if test "${CONFIG_DEBUG}" = "yes"; then
CFLAGS="${CFLAGS} -Wsign-compare -Wfloat-equal -Wformat-security -g -O1"
AC_DEFINE(DEBUG, 1, [debugging])
else
CFLAGS="${CFLAGS} -O2"
fi
AC_CONFIG_FILES([
GNUmakefile
])
AC_OUTPUT
+2 -1
View File
@@ -182,7 +182,7 @@ struct canfd_frame {
/*
* defined bits for canxl_frame.flags
*
* The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
* The canxl_frame.flags element contains three bits CANXL_[XLF|SEC|RRS]
* and shares the relative position of the struct can[fd]_frame.len element.
* The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
* As a side effect setting this bit intentionally breaks the length checks
@@ -192,6 +192,7 @@ struct canfd_frame {
*/
#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
#define CANXL_RRS 0x02 /* Remote Request Substitution */
/* the 8-bit VCID is optionally placed in the canxl_frame.prio element */
#define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */
+2
View File
@@ -22,6 +22,8 @@ struct regmap {
};
#define pr_info(...) fprintf(stdout, ## __VA_ARGS__)
#define pr_err(...) fprintf(stderr, ## __VA_ARGS__)
#define pr_warn(...) fprintf(stderr, ## __VA_ARGS__)
#define pr_cont(...) fprintf(stdout, ## __VA_ARGS__)
#define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__)
#define BUILD_BUG_ON(...)
+23 -23
View File
@@ -288,8 +288,8 @@ static int isobusfs_cli_handle_events(struct isobusfs_priv *priv, unsigned int n
};
ret = isobusfs_recv_err(priv->sock_ccm, &emsg);
if (ret && ret != -EINTR)
return ret;
if (ret)
pr_warn("error queue reported error: %i", ret);
}
} else if (ev->data.fd == STDIN_FILENO) {
if (!priv->interactive) {
@@ -336,7 +336,7 @@ int isobusfs_cli_process_events_and_tasks(struct isobusfs_priv *priv)
if (priv->state == ISOBUSFS_CLI_STATE_SELFTEST)
dont_wait = true;
ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, dont_wait);
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, dont_wait);
if (ret)
return ret;
@@ -354,7 +354,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
@@ -362,7 +362,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
/* TODO: this is TX only socket */
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL;
ret = isobusfs_cmn_bind_socket(priv->sock_main, &addr);
ret = libj1939_bind_socket(priv->sock_main, &addr);
if (ret < 0)
return ret;
@@ -370,7 +370,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
if (ret < 0)
return ret;
ret = isobusfs_cmn_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT);
ret = libj1939_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT);
if (ret < 0)
return ret;
@@ -378,7 +378,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv)
if (ret < 0)
return ret;
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_main, EPOLLIN);
}
@@ -398,7 +398,7 @@ static int isobusfs_cli_sock_int_prepare(struct isobusfs_priv *priv)
if (ret < 0)
return ret;
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
STDIN_FILENO, EPOLLIN);
}
@@ -407,7 +407,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
@@ -419,7 +419,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
/* TODO: this is TX only socket */
addr.can_addr.j1939.pgn = J1939_NO_PGN;
ret = isobusfs_cmn_bind_socket(priv->sock_ccm, &addr);
ret = libj1939_bind_socket(priv->sock_ccm, &addr);
if (ret < 0)
return ret;
@@ -427,7 +427,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
if (ret < 0)
return ret;
ret = isobusfs_cmn_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT);
ret = libj1939_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT);
if (ret < 0)
return ret;
@@ -436,7 +436,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv)
return ret;
/* poll for errors to get confirmation if our packets are send */
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm,
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm,
EPOLLERR);
}
@@ -445,23 +445,23 @@ static int isobusfs_cli_sock_nack_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_nack = ret;
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr);
ret = libj1939_bind_socket(priv->sock_nack, &addr);
if (ret < 0)
return ret;
ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
if (ret < 0)
return ret;
/* poll for errors to get confirmation if our packets are send */
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN);
}
@@ -471,7 +471,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
struct sockaddr_can addr = priv->sockname;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
@@ -481,11 +481,11 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
addr.can_addr.j1939.name = J1939_NO_NAME;
addr.can_addr.j1939.addr = J1939_NO_ADDR;
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL;
ret = isobusfs_cmn_bind_socket(priv->sock_bcast_rx, &addr);
ret = libj1939_bind_socket(priv->sock_bcast_rx, &addr);
if (ret < 0)
return ret;
ret = isobusfs_cmn_set_broadcast(priv->sock_bcast_rx);
ret = libj1939_set_broadcast(priv->sock_bcast_rx);
if (ret < 0)
return ret;
@@ -493,7 +493,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv)
if (ret < 0)
return ret;
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx,
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx,
EPOLLIN);
}
@@ -501,7 +501,7 @@ static int isobusfs_cli_sock_prepare(struct isobusfs_priv *priv)
{
int ret;
ret = isobusfs_cmn_create_epoll();
ret = libj1939_create_epoll();
if (ret < 0)
return ret;
@@ -647,8 +647,8 @@ int main(int argc, char *argv[])
bzero(priv, sizeof(*priv));
isobusfs_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
isobusfs_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS);
libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
libj1939_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS);
ret = isobusfs_cli_parse_args(priv, argc, argv);
if (ret)
+1 -1
View File
@@ -103,7 +103,7 @@ struct isobusfs_priv {
struct isobusfs_buf_log tx_buf_log;
enum isobusfs_cli_state state;
struct isobusfs_cmn cmn;
struct libj1939_cmn cmn;
uint8_t handle;
uint32_t read_offset;
+4 -189
View File
@@ -101,7 +101,7 @@ void isobusfs_log(log_level_t level, const char *fmt, ...)
va_end(args);
snprintf(complete_log_entry, sizeof(complete_log_entry),
"[%s] [%s]: %s", time_buffer, level_str, log_entry);
"[%.40s] [%.10s]: %.150s", time_buffer, level_str, log_entry);
if (interactive_mode) {
add_log_to_buffer(complete_log_entry);
@@ -125,29 +125,6 @@ void isobusfs_log_level_set(log_level_t level)
log_level = level;
}
int isobusfs_get_timeout_ms(struct timespec *ts)
{
struct timespec curr_time;
int64_t time_diff;
int timeout_ms;
clock_gettime(CLOCK_MONOTONIC, &curr_time);
time_diff = timespec_diff_ms(ts, &curr_time);
if (time_diff < 0) {
/* Too late to send next message. Send it now */
timeout_ms = 0;
} else {
if (time_diff > INT_MAX) {
warn("timeout too long: %" PRId64 " ms", time_diff);
time_diff = INT_MAX;
}
timeout_ms = time_diff;
}
return timeout_ms;
}
const char *isobusfs_error_to_str(enum isobusfs_error err)
{
switch (err) {
@@ -238,15 +215,6 @@ enum isobusfs_error linux_error_to_isobusfs_error(int linux_err)
}
}
void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = pgn;
}
static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg,
const char *name, struct timespec *cur)
{
@@ -258,9 +226,9 @@ static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg,
if (!(cur->tv_sec | cur->tv_nsec))
return;
fprintf(stderr, " %s: %lu s %lu us (seq=%u/%u, send=%u)",
name, cur->tv_sec, cur->tv_nsec / 1000,
stats->tskey_sch, stats->tskey_ack, stats->send);
fprintf(stderr, " %s: %llu s %llu us (seq=%u/%u, send=%u)",
name, (unsigned long long)cur->tv_sec, (unsigned long long)cur->tv_nsec / 1000,
stats->tskey_sch, stats->tskey_ack, stats->send);
fprintf(stderr, "\n");
}
@@ -520,28 +488,6 @@ int isobusfs_send(int sock, const void *data, size_t len,
return 0;
}
/**
* isobusfs_cmn_open_socket - Open a CAN J1939 socket
*
* This function opens a CAN J1939 socket and returns the file descriptor
* on success. In case of an error, the function returns the negative
* error code.
*/
int isobusfs_cmn_open_socket(void)
{
int ret;
/* Create a new CAN J1939 socket */
ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (ret < 0) {
/* Get the error code and print an error message */
ret = -errno;
pr_err("socket(j1939): %d (%s)", ret, strerror(ret));
return ret;
}
return ret;
}
/**
* isobusfs_cmn_configure_socket_filter - Configure a J1939 socket filter
* @sock: Socket file descriptor
@@ -650,47 +596,6 @@ int isobusfs_cmn_configure_error_queue(int sock)
return 0;
}
/**
* isobusfs_cmn_bind_socket - Bind a J1939 socket to a given address
* @sock: socket file descriptor
* @addr: pointer to a sockaddr_can structure containing the address
* information to bind the socket to
*
* This function binds a J1939 socket to the specified address. It returns
* 0 on successful binding or a negative error code on failure.
*
* Return: 0 on success, or a negative error code on failure.
*/
int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr)
{
int ret;
ret = bind(sock, (void *)addr, sizeof(*addr));
if (ret < 0) {
ret = -errno;
pr_err("failed to bind: %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
int isobusfs_cmn_socket_prio(int sock, int prio)
{
int ret;
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&prio, sizeof(prio));
if (ret < 0) {
ret = -errno;
pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret,
strerror(ret));
return ret;
}
return 0;
}
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
{
int ret;
@@ -705,32 +610,6 @@ int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr)
return 0;
}
/**
* isobusfs_cmn_set_broadcast - Enable broadcast option for a socket
* @sock: socket file descriptor
*
* This function enables the SO_BROADCAST option for the given socket,
* allowing it to send and receive broadcast messages. It returns 0 on success
* or a negative error code on failure.
*
* Return: 0 on success, or a negative error code on failure.
*/
int isobusfs_cmn_set_broadcast(int sock)
{
int broadcast = true;
int ret;
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast));
if (ret < 0) {
ret = -errno;
pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/* FIXME: linger is currently not supported by the kernel J1939 stack
* but it would be nice to have it. Especially if we wont to stop sending
* messages on a socket when the connection is lost.
@@ -753,70 +632,6 @@ int isobusfs_cmn_set_linger(int sock)
return 0;
}
int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events)
{
struct epoll_event ev = {0};
int ret;
ev.events = events;
ev.data.fd = sock;
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
if (ret < 0) {
ret = errno;
pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
int isobusfs_cmn_create_epoll(void)
{
int ret, epoll_fd;
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
ret = -errno;
pr_err("epoll_create1: %d (%s)", ret, strerror(ret));
return ret;
}
return epoll_fd;
}
int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds,
bool dont_wait)
{
int ret, timeout_ms;
if (dont_wait)
timeout_ms = 0;
else
timeout_ms = isobusfs_get_timeout_ms(&cmn->next_send_time);
ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events,
cmn->epoll_events_size, timeout_ms);
if (ret < 0) {
ret = -errno;
if (ret != -EINTR) {
*nfds = 0;
return ret;
}
}
*nfds = ret;
ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time);
if (ret < 0) {
ret = -errno;
pr_err("failed to get time: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
size_t x)
{
-19
View File
@@ -257,15 +257,6 @@ struct isobusfs_err_msg {
struct isobusfs_stats *stats;
};
struct isobusfs_cmn {
int epoll_fd;
struct epoll_event *epoll_events;
size_t epoll_events_size;
struct timespec next_send_time;
struct timespec last_time;
};
void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
int isobusfs_recv_err(int sock, struct isobusfs_err_msg *emsg);
/*
@@ -300,7 +291,6 @@ static inline uint8_t isobusfs_cg_function_to_buf(enum isobusfs_cg cg,
const char *isobusfs_error_to_str(enum isobusfs_error err);
enum isobusfs_error linux_error_to_isobusfs_error(int linux_err);
int isobusfs_get_timeout_ms(struct timespec *ts);
void isobusfs_send_nack(int sock, struct isobusfs_msg *msg);
void isobufs_store_tx_data(struct isobusfs_buf_log *buffer, uint8_t *data);
void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer);
@@ -313,20 +303,11 @@ int isobusfs_send(int sock, const void *data, size_t len,
void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size,
size_t x);
int isobusfs_cmn_open_socket(void);
int isobusfs_cmn_configure_socket_filter(int sock, pgn_t pgn);
int isobusfs_cmn_configure_error_queue(int sock);
int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr);
int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr);
int isobusfs_cmn_set_broadcast(int sock);
int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);
int isobusfs_cmn_create_epoll(void);
int isobusfs_cmn_socket_prio(int sock, int prio);
int isobusfs_cmn_set_linger(int sock);
int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds,
bool dont_wait);
/* ============ directory handling ============ */
int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable);
+19 -19
View File
@@ -221,8 +221,8 @@ static int isobusfs_srv_handle_events(struct isobusfs_srv_priv *priv, unsigned i
};
ret = isobusfs_recv_err(priv->sock_fss, &emsg);
if (ret && ret != -EINTR)
return ret;
if (ret)
pr_warn("error queue reported error: %i", ret);
}
}
@@ -250,7 +250,7 @@ static int isobusfs_srv_process_events_and_tasks(struct isobusfs_srv_priv *priv)
{
int ret, nfds;
ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, false);
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
if (ret)
return ret;
@@ -268,7 +268,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
struct sockaddr_can addr = priv->addr;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
@@ -283,11 +283,11 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
* PGN?
*/
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
ret = isobusfs_cmn_bind_socket(priv->sock_fss, &addr);
ret = libj1939_bind_socket(priv->sock_fss, &addr);
if (ret < 0)
return ret;
ret = isobusfs_cmn_set_broadcast(priv->sock_fss);
ret = libj1939_set_broadcast(priv->sock_fss);
if (ret < 0)
return ret;
@@ -295,7 +295,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
if (ret < 0)
return ret;
ret = isobusfs_cmn_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS);
ret = libj1939_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS);
if (ret < 0)
return ret;
@@ -308,7 +308,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv)
return ret;
/* poll for errors to get confirmation if our packets are send */
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss,
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss,
EPOLLERR);
}
@@ -317,7 +317,7 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv)
struct sockaddr_can addr = priv->addr;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
@@ -325,12 +325,12 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv)
/* keep address and name and overwrite PGN */
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
ret = isobusfs_cmn_bind_socket(priv->sock_in, &addr);
ret = libj1939_bind_socket(priv->sock_in, &addr);
if (ret < 0)
return ret;
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in,
EPOLLIN);
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in,
EPOLLIN);
}
static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv)
@@ -338,24 +338,24 @@ static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv)
struct sockaddr_can addr = priv->addr;
int ret;
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_nack = ret;
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr);
ret = libj1939_bind_socket(priv->sock_nack, &addr);
if (ret < 0)
return ret;
ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK);
if (ret < 0)
return ret;
/* poll for errors to get confirmation if our packets are send */
return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN);
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN);
}
/**
@@ -370,7 +370,7 @@ static int isobusfs_srv_sock_prepare(struct isobusfs_srv_priv *priv)
{
int ret;
ret = isobusfs_cmn_create_epoll();
ret = libj1939_create_epoll();
if (ret < 0)
return ret;
@@ -762,7 +762,7 @@ int main(int argc, char *argv[])
memset(priv, 0, sizeof(*priv));
/* Initialize sockaddr_can with a non-configurable PGN */
isobusfs_init_sockaddr_can(&priv->addr, J1939_NO_PGN);
libj1939_init_sockaddr_can(&priv->addr, J1939_NO_PGN);
priv->server_version = ISOBUSFS_SRV_VERSION;
/* Parse command line arguments */
+1 -1
View File
@@ -103,7 +103,7 @@ struct isobusfs_srv_priv {
int clients_count;
struct isobusfs_buf_log tx_buf_log;
struct isobusfs_cmn cmn;
struct libj1939_cmn cmn;
struct isobusfs_srv_volume volumes[ISOBUSFS_SRV_MAX_VOLUMES];
int volume_count;
+20 -12
View File
@@ -213,14 +213,14 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv,
return -EINVAL;
}
ret = isobusfs_cmn_open_socket();
ret = libj1939_open_socket();
if (ret < 0)
return ret;
client->sock = ret;
addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS;
ret = isobusfs_cmn_bind_socket(client->sock, &addr);
ret = libj1939_bind_socket(client->sock, &addr);
if (ret < 0)
return ret;
@@ -243,7 +243,7 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv,
goto close_socket;
}
ret = isobusfs_cmn_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT);
ret = libj1939_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT);
if (ret < 0)
return ret;
@@ -464,15 +464,17 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
struct isobusfs_cm_vol_stat_req *req =
(struct isobusfs_cm_vol_stat_req *)msg->buf;
char isobusfs_volume_path[ISOBUSFS_MAX_VOLUME_NAME_LENGTH];
size_t path_len, req_name_len, resp_name_len;
char linux_path[ISOBUSFS_SRV_MAX_PATH_LEN];
struct isobusfs_srv_volume *volume = NULL;
struct isobusfs_srv_client *client;
const char *path;
size_t path_len;
int ret, i;
req_name_len = le16toh(req->name_len);
pr_debug("< rx volume status request. mode: %x, length: %d, name: %s",
req->volume_mode, req->name_len, req->name);
req->volume_mode, req_name_len, req->name);
client = isobusfs_srv_get_client_by_msg(priv, msg);
if (!client) {
@@ -480,12 +482,12 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
return ISOBUSFS_ERR_OTHER;
}
if (req->name_len == 0) {
if (req_name_len == 0) {
path = client->current_dir;
path_len = sizeof(client->current_dir);
} else {
path = req->name;
path_len = req->name_len;
path_len = req_name_len;
}
ret = isobusfs_extract_volume_name(path, path_len, isobusfs_volume_path,
@@ -495,11 +497,12 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
return ISOBUSFS_ERR_OTHER;
}
resp->name_len = strlen(isobusfs_volume_path);
resp_name_len = strlen(isobusfs_volume_path);
resp->name_len = htole16(resp_name_len);
/* the isobusfs_volume_path is already null terminated
* by isobusfs_extract_volume_name()
*/
memcpy(resp->name, isobusfs_volume_path, resp->name_len + 1);
memcpy(resp->name, isobusfs_volume_path, resp_name_len + 1);
ret = isobusfs_path_to_linux_path(priv, isobusfs_volume_path,
sizeof(isobusfs_volume_path),
@@ -530,7 +533,7 @@ static int isobusfs_srv_process_volume_status_request(struct isobusfs_srv_priv *
if (req->volume_mode & ISOBUSFS_VOL_MODE_PREP_TO_REMOVE) {
if (!volume->removable ||
(req->name_len == 0 &&
(req_name_len == 0 &&
0 /* Current directory is not set condition */)) {
/* Volume is not removable, or the Path Name Length of
* request is zero and the current directory is not set
@@ -571,10 +574,15 @@ static int isobusfs_srv_volume_status_resp(struct isobusfs_srv_priv *priv,
ret = isobusfs_srv_process_volume_status_request(priv, msg, &resp);
resp.error_code = ret;
buf_size = sizeof(resp);
buf_size = sizeof(resp) - sizeof(resp.name) + le16toh(resp.name_len);
if (buf_size < ISOBUSFS_MIN_TRANSFER_LENGH) {
/* Fill the rest of the buffer with 0xFF. We need to fill
* only buffers under 8 bytes. Padding for ETP/TP is done
* by the kernel.
*/
memset(((uint8_t *) &resp) + buf_size, 0xFF,
ISOBUSFS_MIN_TRANSFER_LENGH - buf_size);
buf_size = ISOBUSFS_MIN_TRANSFER_LENGH;
memset(((uint8_t *) &resp) + sizeof(resp), 0xFF, buf_size - sizeof(resp));
} else if (buf_size > ISOBUSFS_MAX_TRANSFER_LENGH) {
pr_warn("volume status response too long");
resp.error_code = ISOBUSFS_ERR_OUT_OF_MEM;
+30 -5
View File
@@ -72,6 +72,7 @@ void print_usage(char *prg)
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, " -b <can_id> (broadcast can_id, Use 8 digits for extended IDs)\n");
fprintf(stderr, " -x <addr> (extended addressing mode. Use 'any' for all addresses)\n");
fprintf(stderr, " -X <addr> (extended addressing mode (rx addr). Use 'any' for all)\n");
fprintf(stderr, " -c (color mode)\n");
@@ -197,11 +198,12 @@ int main(int argc, char **argv)
{
int s;
struct sockaddr_can addr;
struct can_filter rfilter[2];
struct can_filter rfilter[3];
struct canfd_frame frame;
int nbytes, i;
canid_t src = NO_CAN_ID;
canid_t dst = NO_CAN_ID;
canid_t bst = NO_CAN_ID;
int ext = 0;
int extaddr = 0;
int extany = 0;
@@ -222,7 +224,7 @@ int main(int argc, char **argv)
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "s:d:ax:X:ct:u?")) != -1) {
while ((opt = getopt(argc, argv, "s:d:b:ax:X:ct:u?")) != -1) {
switch (opt) {
case 's':
src = strtoul(optarg, NULL, 16);
@@ -236,6 +238,12 @@ int main(int argc, char **argv)
dst |= CAN_EFF_FLAG;
break;
case 'b':
bst = strtoul(optarg, NULL, 16);
if (strlen(optarg) > 7)
bst |= CAN_EFF_FLAG;
break;
case 'c':
color = 1;
break;
@@ -321,7 +329,18 @@ int main(int argc, char **argv)
rfilter[1].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
}
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
if (bst & CAN_EFF_FLAG) {
rfilter[2].can_id = bst & (CAN_EFF_MASK | CAN_EFF_FLAG);
rfilter[2].can_mask = (CAN_EFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
} else {
rfilter[2].can_id = bst & CAN_SFF_MASK;
rfilter[2].can_mask = (CAN_SFF_MASK|CAN_EFF_FLAG|CAN_RTR_FLAG);
}
if (bst != NO_CAN_ID)
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
else
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter) - sizeof(rfilter[0]));
addr.can_family = AF_CAN;
addr.can_ifindex = if_nametoindex(argv[optind]);
@@ -353,8 +372,14 @@ int main(int argc, char **argv)
rx_extaddr != frame.data[0])
continue;
if (color)
printf("%s", (frame.can_id == src) ? FGRED : FGBLUE);
if (color) {
if (frame.can_id == src)
printf("%s", FGRED);
else if (frame.can_id == dst)
printf("%s", FGBLUE);
else if (frame.can_id == bst)
printf("%s", FGGREEN);
}
if (timestamp) {
ioctl(s, SIOCGSTAMP, &tv);
+500
View File
@@ -0,0 +1,500 @@
// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/kernel.h>
#include <net/if.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "j1939_timedate_cmn.h"
#define J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS 10
struct j1939_timedate_cli_priv {
int sock_nack;
int sock_main;
struct sockaddr_can sockname;
struct sockaddr_can peername;
struct j1939_timedate_stats stats;
struct libj1939_cmn cmn;
struct timespec wait_until_time;
bool utc;
bool broadcast;
bool done;
};
static void print_time_date_packet(struct j1939_timedate_cli_priv *priv,
const struct j1939_timedate_msg *msg)
{
const struct j1939_time_date_packet *tdp =
(const struct j1939_time_date_packet *)msg->buf;
char timezone_offset[] = "+00:00 (Local Time)";
char time_buffer[64];
int actual_hour, actual_minute;
int actual_year, actual_month;
double actual_seconds;
double actual_day;
if (msg->len < (int)sizeof(*tdp)) {
pr_warn("received too short time and date packet: %zi",
msg->len);
return;
}
actual_year = 1985 + tdp->year;
actual_month = tdp->month;
actual_day = tdp->day * 0.25;
actual_hour = tdp->hours;
actual_minute = tdp->minutes;
actual_seconds = tdp->seconds * 0.25;
if (tdp->local_hour_offset == 125) {
snprintf(timezone_offset, sizeof(timezone_offset),
"+00:00 (Local Time)");
} else if (!priv->utc) {
actual_hour += tdp->local_hour_offset;
actual_minute += tdp->local_minute_offset;
/* Wraparound for hours and minutes if needed */
if (actual_minute >= 60) {
actual_minute -= 60;
actual_hour++;
} else if (actual_minute < 0) {
actual_minute += 60;
actual_hour--;
}
if (actual_hour >= 24) {
actual_hour -= 24;
actual_day++;
} else if (actual_hour < 0) {
actual_hour += 24;
actual_day--;
}
snprintf(timezone_offset, sizeof(timezone_offset), "%+03d:%02d",
tdp->local_hour_offset, abs(tdp->local_minute_offset));
} else {
snprintf(timezone_offset, sizeof(timezone_offset),
"+00:00 (UTC)");
}
snprintf(time_buffer, sizeof(time_buffer),
"%d-%02d-%02.0f %02d:%02d:%05.2f%.20s",
actual_year, actual_month, actual_day, actual_hour,
actual_minute, actual_seconds, timezone_offset);
printf("SA: 0x%02X, NAME: 0x%016llX, Time: %s\n",
msg->peername.can_addr.j1939.addr,
msg->peername.can_addr.j1939.name, time_buffer);
if (!priv->broadcast)
priv->done = true;
}
static int j1939_timedate_cli_rx_buf(struct j1939_timedate_cli_priv *priv,
struct j1939_timedate_msg *msg)
{
pgn_t pgn = msg->peername.can_addr.j1939.pgn;
int ret = 0;
switch (pgn) {
case J1939_PGN_TD:
print_time_date_packet(priv, msg);
break;
default:
pr_warn("%s: unsupported PGN: %x", __func__, pgn);
/* Not a critical error */
break;
}
return ret;
}
static int j1939_timedate_cli_rx_one(struct j1939_timedate_cli_priv *priv,
int sock)
{
struct j1939_timedate_msg *msg;
int flags = 0;
int ret;
msg = malloc(sizeof(*msg));
if (!msg) {
pr_err("can't allocate rx msg struct\n");
return -ENOMEM;
}
msg->buf_size = J1939_TIMEDATE_MAX_TRANSFER_LENGH;
msg->peer_addr_len = sizeof(msg->peername);
msg->sock = sock;
ret = recvfrom(sock, &msg->buf[0], msg->buf_size, flags,
(struct sockaddr *)&msg->peername, &msg->peer_addr_len);
if (ret < 0) {
ret = -errno;
pr_warn("recvfrom() failed: %i %s", ret, strerror(-ret));
return ret;
}
if (ret < 3) {
pr_warn("received too short message: %i", ret);
return -EINVAL;
}
msg->len = ret;
ret = j1939_timedate_cli_rx_buf(priv, msg);
if (ret < 0) {
pr_warn("failed to process rx buf: %i (%s)\n", ret,
strerror(ret));
return ret;
}
return 0;
}
static int j1939_timedate_cli_handle_events(struct j1939_timedate_cli_priv *priv,
unsigned int nfds)
{
int ret;
unsigned int n;
for (n = 0; n < nfds && n < priv->cmn.epoll_events_size; ++n) {
struct epoll_event *ev = &priv->cmn.epoll_events[n];
if (!ev->events) {
warn("no events");
continue;
}
if (ev->events & POLLIN) {
ret = j1939_timedate_cli_rx_one(priv, ev->data.fd);
if (ret) {
warn("recv one");
return ret;
}
}
}
return 0;
}
static int j1939_timedate_cli_process_events_and_tasks(struct j1939_timedate_cli_priv *priv)
{
int ret, nfds;
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
if (ret)
return ret;
if (nfds > 0) {
ret = j1939_timedate_cli_handle_events(priv, nfds);
if (ret)
return ret;
}
return 0;
}
static int j1939_timedate_cli_send_req(struct j1939_timedate_cli_priv *priv)
{
struct sockaddr_can addr = priv->peername;
uint8_t data[3] = {0};
int ret;
addr.can_addr.j1939.pgn = J1939_PGN_REQUEST_PGN;
data[0] = J1939_PGN_TD & 0xff;
data[1] = (J1939_PGN_TD >> 8) & 0xff;
data[2] = (J1939_PGN_TD >> 16) & 0xff;
ret = sendto(priv->sock_main, data, sizeof(data), 0,
(struct sockaddr *)&addr, sizeof(addr));
if (ret == -1) {
ret = -errno;
pr_warn("failed to send data: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
static int j1939_timedate_cli_sock_main_prepare(struct j1939_timedate_cli_priv *priv)
{
struct sockaddr_can addr = priv->sockname;
int ret;
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_main = ret;
ret = libj1939_bind_socket(priv->sock_main, &addr);
if (ret < 0)
return ret;
ret = libj1939_socket_prio(priv->sock_main,
J1939_TIMEDATE_PRIO_DEFAULT);
if (ret < 0)
return ret;
ret = libj1939_set_broadcast(priv->sock_main);
if (ret < 0)
return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_main, EPOLLIN);
}
static int j1939_timedate_cli_sock_nack_prepare(struct j1939_timedate_cli_priv *priv)
{
struct sockaddr_can addr = priv->sockname;
int ret;
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_nack = ret;
addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK;
ret = libj1939_bind_socket(priv->sock_nack, &addr);
if (ret < 0)
return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_nack, EPOLLIN);
}
static int j1939_timedate_cli_sock_prepare(struct j1939_timedate_cli_priv *priv)
{
int ret;
ret = libj1939_create_epoll();
if (ret < 0)
return ret;
priv->cmn.epoll_fd = ret;
priv->cmn.epoll_events = calloc(J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS,
sizeof(struct epoll_event));
if (!priv->cmn.epoll_events)
return -ENOMEM;
priv->cmn.epoll_events_size = J1939_TIMEDATE_CLI_MAX_EPOLL_EVENTS;
ret = j1939_timedate_cli_sock_main_prepare(priv);
if (ret < 0)
return ret;
return j1939_timedate_cli_sock_nack_prepare(priv);
}
static void j1939_timedate_cli_print_help(void)
{
printf("Usage: j1939_timedate-cli [options]\n");
printf("Options:\n");
printf(" --interface <interface_name> or -i <interface_name>\n");
printf(" Specifies the CAN interface to use (mandatory).\n");
printf(" --local-address <local_address_hex> or -a <local_address_hex>\n");
printf(" Specifies the local address in hexadecimal (mandatory if local name is not provided).\n");
printf(" --local-name <local_name_hex> or -n <local_name_hex>\n");
printf(" Specifies the local NAME in hexadecimal (mandatory if local address is not provided).\n");
printf(" --remote-address <remote_address_hex> or -r <remote_address_hex>\n");
printf(" Specifies the remote address in hexadecimal (optional).\n");
printf(" --remote-name <remote_name_hex> or -m <remote_name_hex>\n");
printf(" Specifies the remote NAME in hexadecimal (optional).\n");
printf(" --utc or -u\n");
printf(" Outputs the time in UTC format.\n");
printf("\n");
printf("Note:\n");
printf(" Local address and local name are mutually exclusive and one must be provided.\n");
printf(" Remote address and remote name are mutually exclusive. \n");
printf(" If no remote property is provided, the broadcast address will be used.\n");
printf("\n");
printf("Behavior:\n");
printf(" In unicast mode (remote address or remote name provided),\n");
printf(" the client will send a request and wait for the first response, then exit.\n");
printf(" In broadcast mode (no remote address or remote name provided),\n");
printf(" the program will wait 1000 milliseconds to collect responses, then exit.\n");
printf("\n");
printf("Time Output Formats:\n");
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 (Local Time) - when no time zone information is received.\n");
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 (UTC) - when the --utc option is used.\n");
printf(" YYYY-MM-DD HH:MM:SS.SS+00:00 - default response with time zone offset automatically calculated.\n");
printf("\n");
printf("Complete Message Format:\n");
printf(" The message will include the Source Address (SA) and J1939 NAME, formatted as follows:\n");
printf(" SA: 0x60, NAME: 0x0000000000000000, Time: 2024-05-16 20:23:40.00+02:00\n");
printf(" If the NAME is known, it will have a non-zero value.\n");
printf("\n");
printf("Usage Examples:\n");
printf(" j1939acd -r 64-95 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0 &\n");
printf("\n");
printf(" Broadcast mode:\n");
printf(" j1939-timedate-cli -i vcan0 -a 0x80\n");
printf("\n");
printf(" Unicast mode:\n");
printf(" j1939-timedate-cli -i vcan0 -a 0x80 -r 0x90\n");
printf("\n");
printf(" Using NAMEs instead of addresses:\n");
printf(" j1939acd -r 64-95 -c /tmp/1122334455667788.jacd 1122334455667788 vcan0 &\n");
printf(" j1939-timedate-cli -i vcan0 -n 0x1122334455667788\n");
}
static int j1939_timedate_cli_parse_args(struct j1939_timedate_cli_priv *priv, int argc, char *argv[])
{
struct sockaddr_can *remote = &priv->peername;
struct sockaddr_can *local = &priv->sockname;
bool local_address_set = false;
bool local_name_set = false;
bool remote_address_set = false;
bool remote_name_set = false;
bool interface_set = false;
int long_index = 0;
int opt;
static struct option long_options[] = {
{"interface", required_argument, 0, 'i'},
{"local-address", required_argument, 0, 'a'},
{"local-name", required_argument, 0, 'n'},
{"remote-address", required_argument, 0, 'r'},
{"remote-name", required_argument, 0, 'm'},
{"utc", no_argument, 0, 'u'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "a:n:r:m:i:u", long_options, &long_index)) != -1) {
switch (opt) {
case 'a':
local->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
local_address_set = true;
break;
case 'n':
local->can_addr.j1939.name = strtoull(optarg, NULL, 16);
local_name_set = true;
break;
case 'r':
remote->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
remote_address_set = true;
break;
case 'm':
remote->can_addr.j1939.name = strtoull(optarg, NULL, 16);
remote_name_set = true;
break;
case 'i':
local->can_ifindex = if_nametoindex(optarg);
if (!local->can_ifindex) {
pr_err("Interface %s not found. Error: %d (%s)\n",
optarg, errno, strerror(errno));
return -EINVAL;
}
remote->can_ifindex = local->can_ifindex;
interface_set = true;
break;
case 'u':
priv->utc = true;
break;
default:
j1939_timedate_cli_print_help();
return -EINVAL;
}
}
if (!interface_set) {
pr_err("interface not specified");
j1939_timedate_cli_print_help();
return -EINVAL;
}
if ((local_address_set && local_name_set) ||
(remote_address_set && remote_name_set)) {
pr_err("Local address and local name or remote address and remote name are mutually exclusive\n");
j1939_timedate_cli_print_help();
return -EINVAL;
}
if (!local_address_set && !local_name_set) {
pr_err("Local address and local name not specified. One of them is required\n");
j1939_timedate_cli_print_help();
return -EINVAL;
}
/* If no remote address is set, set it to broadcast */
if (!remote_address_set && !remote_name_set) {
remote->can_addr.j1939.addr = J1939_NO_ADDR;
priv->broadcast = true;
}
return 0;
}
int main(int argc, char *argv[])
{
struct j1939_timedate_cli_priv *priv;
struct timespec ts;
int64_t time_diff;
int ret;
priv = malloc(sizeof(*priv));
if (!priv)
err(EXIT_FAILURE, "can't allocate priv");
bzero(priv, sizeof(*priv));
libj1939_init_sockaddr_can(&priv->sockname, J1939_PGN_TD);
libj1939_init_sockaddr_can(&priv->peername, J1939_PGN_REQUEST_PGN);
ret = j1939_timedate_cli_parse_args(priv, argc, argv);
if (ret)
return ret;
ret = j1939_timedate_cli_sock_prepare(priv);
if (ret)
return ret;
clock_gettime(CLOCK_MONOTONIC, &ts);
priv->cmn.next_send_time = ts;
priv->wait_until_time = priv->cmn.next_send_time;
/* Wait one second to collect all responses by default */
timespec_add_ms(&priv->wait_until_time, 1000);
ret = j1939_timedate_cli_send_req(priv);
if (ret)
return ret;
while (1) {
ret = j1939_timedate_cli_process_events_and_tasks(priv);
if (ret)
break;
if (priv->done)
break;
clock_gettime(CLOCK_MONOTONIC, &ts);
time_diff = timespec_diff_ms(&priv->wait_until_time, &ts);
if (time_diff < 0)
break;
}
close(priv->cmn.epoll_fd);
free(priv->cmn.epoll_events);
close(priv->sock_main);
close(priv->sock_nack);
return ret;
}
+84
View File
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
#ifndef _J1939_TIMEDATE_H_
#define _J1939_TIMEDATE_H_
#include <stdint.h>
#include <endian.h>
#include <stdbool.h>
#include <sys/epoll.h>
#include <linux/can.h>
#include <linux/kernel.h>
#include "../libj1939.h"
#include "../lib.h"
/* SAE J1939-71:2002 - 5.3 pgn54528 - Time/Date Adjust - TDA - */
#define J1939_PGN_TDA 0x0d500 /* 54528 */
/* SAE J1939-71:2002 - 5.3 pgn65254 - Time/Date - TD - */
#define J1939_PGN_TD 0x0fee6 /* 65254 */
#define J1939_PGN_REQUEST_PGN 0x0ea00 /* 59904 */
/* ISO 11783-3:2018 - 5.4.5 Acknowledgment */
#define ISOBUS_PGN_ACK 0x0e800 /* 59392 */
#define J1939_TIMEDATE_PRIO_DEFAULT 6
#define J1939_TIMEDATE_MAX_TRANSFER_LENGH 8
struct j1939_timedate_stats {
int err;
uint32_t tskey_sch;
uint32_t tskey_ack;
uint32_t send;
};
struct j1939_timedate_msg {
uint8_t buf[J1939_TIMEDATE_MAX_TRANSFER_LENGH];
size_t buf_size;
ssize_t len; /* length of received message */
struct sockaddr_can peername;
socklen_t peer_addr_len;
int sock;
};
struct j1939_timedate_err_msg {
struct sock_extended_err *serr;
struct scm_timestamping *tss;
struct j1939_timedate_stats *stats;
};
/*
* struct time_date_packet - Represents the PGN 65254 Time/Date packet
*
* @seconds: Seconds since the last minute (0-59) with a scaling factor,
* meaning each increment represents 0.25 seconds.
* @minutes: Minutes since the last hour (0-59) with no scaling.
* @hours: Hours since midnight (0-23) with no scaling.
* @month: Current month (1-12) with no scaling.
* @day: Day of the month with a scaling factor, each increment represents 0.25
* day.
* @year: Year offset since 1985, each increment represents one year.
* @local_minute_offset: Offset in minutes from UTC, can range from -125 to 125
* minutes.
* @local_hour_offset: Offset in hours from UTC, can range from -125 to 125
* hours.
*
* This structure defines each component of the Time/Date as described in
* PGN 65254, using each byte to represent different components of the standard
* UTC time and optionally adjusted local time based on offsets.
*/
struct j1939_time_date_packet {
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
uint8_t month;
uint8_t day;
uint8_t year;
int8_t local_minute_offset;
int8_t local_hour_offset;
};
#endif /* !_J1939_TIMEDATE_H_ */
+450
View File
@@ -0,0 +1,450 @@
// SPDX-License-Identifier: LGPL-2.0-only
// SPDX-FileCopyrightText: 2024 Oleksij Rempel <linux@rempel-privat.de>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/kernel.h>
#include <net/if.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "j1939_timedate_cmn.h"
#define J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS 10
struct j1939_timedate_srv_priv {
int sock_nack;
int sock_main;
struct sockaddr_can sockname;
struct j1939_timedate_stats stats;
struct libj1939_cmn cmn;
};
static void gmtime_to_j1939_pgn_65254_td(struct j1939_time_date_packet *tdp)
{
struct tm utc_tm_buf, local_tm_buf;
int hour_offset, minute_offset;
struct tm *utc_tm, *local_tm;
int year_since_1985;
time_t now;
now = time(NULL);
utc_tm = gmtime_r(&now, &utc_tm_buf);
local_tm = localtime_r(&now, &local_tm_buf);
/* Calculate the offsets */
hour_offset = local_tm->tm_hour - utc_tm->tm_hour;
minute_offset = local_tm->tm_min - utc_tm->tm_min;
/* Handle date rollover */
if (local_tm->tm_mday != utc_tm->tm_mday) {
if (local_tm->tm_hour < 12)
hour_offset += 24; /* past midnight */
else
hour_offset -= 24; /* before midnight */
}
/*
* Seconds (spn959):
* Resolution: 0.25 /bit, 0 offset
* Data Range: 0 to 250 (0 to 62.5 seconds)
* Operational Range: 0 to 239 (0 to 59.75 seconds)
*/
tdp->seconds = (uint8_t)(utc_tm->tm_sec / 0.25);
if (tdp->seconds > 239)
tdp->seconds = 239;
/*
* Minutes (spn960):
* Resolution: 1 min/bit, 0 offset
* Data Range: 0 to 250 (0 to 250 minutes)
* Operational Range: 0 to 59 (0 to 59 minutes)
*/
tdp->minutes = (uint8_t)utc_tm->tm_min;
if (tdp->minutes > 59)
tdp->minutes = 59;
/*
* Hours (spn961):
* Resolution: 1 hr/bit, 0 offset
* Data Range: 0 to 250 (0 to 250 hours)
* Operational Range: 0 to 23 (0 to 23 hours)
*/
tdp->hours = (uint8_t)utc_tm->tm_hour;
if (tdp->hours > 23)
tdp->hours = 23;
/*
* Day (spn962):
* Resolution: 0.25 /bit, 0 offset
* Data Range: 0 to 250 (0 to 62.5 days)
* Operational Range: 1 to 127 (0.25 to 31.75 days)
*/
tdp->day = (uint8_t)(utc_tm->tm_mday / 0.25);
if (tdp->day < 1 || tdp->day > 127)
tdp->day = 1;
/*
* Month (spn963):
* Resolution: 1 month/bit, 0 offset
* Data Range: 0 to 250 (0 to 250 months)
* Operational Range: 1 to 12 (1 to 12 months)
*/
tdp->month = (uint8_t)(utc_tm->tm_mon + 1);
if (tdp->month < 1 || tdp->month > 12)
tdp->month = 1;
/*
* Year (spn964):
* Resolution: 1 year/bit, 1985 offset
* Data Range: 0 to 250 (1985 to 2235)
* Operational Range: 0 to 250 (1985 to 2235)
*/
year_since_1985 = utc_tm->tm_year - 85;
if (year_since_1985 < 0) {
/* Fallback to year 1985 if year is before 1985 */
tdp->year = 0;
} else if (year_since_1985 > 250) {
/* Fallback to year 2235 if year is beyond 2235 */
tdp->year = 250;
} else {
tdp->year = (uint8_t)year_since_1985;
}
/*
* Local minute offset (spn1601):
* Resolution: 1 min/bit, -125 offset
* Data Range: -125 to 125 minutes
* Operational Range: -59 to 59 minutes
*/
tdp->local_minute_offset = (int8_t)minute_offset;
/*
* Local hour offset (spn1602):
* Resolution: 1 hr/bit, -125 offset
* Data Range: -125 to +125 hours
* Operational Range: -24 to +23 hours
* Note: If the local hour offset parameter is equal to 125 (0xFA),
* the local time then the time parameter is the local time instead of
* UTC.
*/
tdp->local_hour_offset = (int8_t)hour_offset;
}
static int j1939_timedate_srv_send_res(struct j1939_timedate_srv_priv *priv,
struct sockaddr_can *addr)
{
struct sockaddr_can peername = *addr;
struct j1939_time_date_packet tdp;
int ret;
gmtime_to_j1939_pgn_65254_td(&tdp);
peername.can_addr.j1939.pgn = J1939_PGN_TD;
ret = sendto(priv->sock_main, &tdp, sizeof(tdp), 0,
(struct sockaddr *)&peername, sizeof(peername));
if (ret == -1) {
ret = -errno;
pr_warn("failed to send data: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
// check if the received message is a request for the time and date
static int j1939_timedate_srv_process_request(struct j1939_timedate_srv_priv *priv,
struct j1939_timedate_msg *msg)
{
if (msg->buf[0] != (J1939_PGN_TD & 0xff) ||
msg->buf[1] != ((J1939_PGN_TD >> 8) & 0xff) ||
msg->buf[2] != ((J1939_PGN_TD >> 16) & 0xff)) {
/* Don't care, not a time and date request */
return 0;
}
return j1939_timedate_srv_send_res(priv, &msg->peername);
}
static int j1939_timedate_srv_rx_buf(struct j1939_timedate_srv_priv *priv, struct j1939_timedate_msg *msg)
{
pgn_t pgn = msg->peername.can_addr.j1939.pgn;
int ret = 0;
switch (pgn) {
case J1939_PGN_REQUEST_PGN:
ret = j1939_timedate_srv_process_request(priv, msg);
break;
default:
pr_warn("%s: unsupported PGN: %x", __func__, pgn);
/* Not a critical error */
break;
}
return ret;
}
static int j1939_timedate_srv_rx_one(struct j1939_timedate_srv_priv *priv, int sock)
{
struct j1939_timedate_msg *msg;
int flags = 0;
int ret;
msg = malloc(sizeof(*msg));
if (!msg) {
pr_err("can't allocate rx msg struct\n");
return -ENOMEM;
}
msg->buf_size = J1939_TIMEDATE_MAX_TRANSFER_LENGH;
msg->peer_addr_len = sizeof(msg->peername);
msg->sock = sock;
ret = recvfrom(sock, &msg->buf[0], msg->buf_size, flags,
(struct sockaddr *)&msg->peername, &msg->peer_addr_len);
if (ret < 0) {
ret = -errno;
pr_warn("recvfrom() failed: %i %s", ret, strerror(-ret));
return ret;
}
if (ret < 3) {
pr_warn("received too short message: %i", ret);
return -EINVAL;
}
msg->len = ret;
ret = j1939_timedate_srv_rx_buf(priv, msg);
if (ret < 0) {
pr_warn("failed to process rx buf: %i (%s)\n", ret,
strerror(ret));
return ret;
}
return 0;
}
static int j1939_timedate_srv_handle_events(struct j1939_timedate_srv_priv *priv,
unsigned int nfds)
{
int ret;
unsigned int n;
for (n = 0; n < nfds && n < priv->cmn.epoll_events_size; ++n) {
struct epoll_event *ev = &priv->cmn.epoll_events[n];
if (!ev->events) {
warn("no events");
continue;
}
if (ev->events & POLLIN) {
ret = j1939_timedate_srv_rx_one(priv, ev->data.fd);
if (ret) {
warn("recv one");
return ret;
}
}
}
return 0;
}
static int j1939_timedate_srv_process_events_and_tasks(struct j1939_timedate_srv_priv *priv)
{
int ret, nfds;
ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false);
if (ret)
return ret;
if (nfds > 0) {
ret = j1939_timedate_srv_handle_events(priv, nfds);
if (ret)
return ret;
}
return 0;
}
static int j1939_timedate_srv_sock_main_prepare(struct j1939_timedate_srv_priv *priv)
{
struct sockaddr_can addr = priv->sockname;
int ret;
ret = libj1939_open_socket();
if (ret < 0)
return ret;
priv->sock_main = ret;
ret = libj1939_bind_socket(priv->sock_main, &addr);
if (ret < 0)
return ret;
ret = libj1939_socket_prio(priv->sock_main,
J1939_TIMEDATE_PRIO_DEFAULT);
if (ret < 0)
return ret;
ret = libj1939_set_broadcast(priv->sock_main);
if (ret < 0)
return ret;
return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd,
priv->sock_main, EPOLLIN);
}
static int j1939_timedate_srv_sock_prepare(struct j1939_timedate_srv_priv *priv)
{
int ret;
ret = libj1939_create_epoll();
if (ret < 0)
return ret;
priv->cmn.epoll_fd = ret;
priv->cmn.epoll_events = calloc(J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS,
sizeof(struct epoll_event));
if (!priv->cmn.epoll_events)
return -ENOMEM;
priv->cmn.epoll_events_size = J1939_TIMEDATE_SRV_MAX_EPOLL_EVENTS;
return j1939_timedate_srv_sock_main_prepare(priv);
}
static void j1939_timedate_srv_print_help(void)
{
printf("Usage: j1939-timedate-srv [options]\n");
printf("Options:\n");
printf(" --interface <interface_name> or -i <interface_name>\n");
printf(" Specifies the CAN interface to use (mandatory).\n");
printf(" --local-address <local_address_hex> or -a <local_address_hex>\n");
printf(" Specifies the local address in hexadecimal (mandatory if\n");
printf(" local name is not provided).\n");
printf(" --local-name <local_name_hex> or -n <local_name_hex>\n");
printf(" Specifies the local NAME in hexadecimal (mandatory if\n");
printf(" local address is not provided).\n");
printf("\n");
printf("Note: Local address and local name are mutually exclusive and one\n");
printf(" must be provided.\n");
printf("\n");
printf("Usage Examples:\n");
printf(" Using local address:\n");
printf(" j1939-timedate-srv -i vcan0 -a 0x90\n");
printf("\n");
printf(" Using local NAME:\n");
printf(" j1939acd -r 64-95 -c /tmp/1122334455667789.jacd 1122334455667789 vcan0 &\n");
printf(" j1939-timedate-srv -i vcan0 -n 0x1122334455667789\n");
}
static int j1939_timedate_srv_parse_args(struct j1939_timedate_srv_priv *priv,
int argc, char *argv[])
{
struct sockaddr_can *local = &priv->sockname;
bool local_address_set = false;
bool local_name_set = false;
bool interface_set = false;
int long_index = 0;
int opt;
static struct option long_options[] = {
{"interface", required_argument, 0, 'i'},
{"local-address", required_argument, 0, 'a'},
{"local-name", required_argument, 0, 'n'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "a:n:i:", long_options, &long_index)) != -1) {
switch (opt) {
case 'a':
local->can_addr.j1939.addr = strtoul(optarg, NULL, 16);
local_address_set = true;
break;
case 'n':
local->can_addr.j1939.name = strtoull(optarg, NULL, 16);
local_name_set = true;
break;
case 'i':
local->can_ifindex = if_nametoindex(optarg);
if (!local->can_ifindex) {
pr_err("Interface %s not found. Error: %d (%s)\n",
optarg, errno, strerror(errno));
return -EINVAL;
}
interface_set = true;
break;
default:
j1939_timedate_srv_print_help();
return -EINVAL;
}
}
if (!interface_set) {
pr_err("interface not specified");
j1939_timedate_srv_print_help();
return -EINVAL;
}
if (local_address_set && local_name_set) {
pr_err("local address and local name or remote address and remote name are mutually exclusive");
j1939_timedate_srv_print_help();
return -EINVAL;
}
return 0;
}
int main(int argc, char *argv[])
{
struct j1939_timedate_srv_priv *priv;
struct timespec ts;
int ret;
priv = malloc(sizeof(*priv));
if (!priv)
err(EXIT_FAILURE, "can't allocate priv");
bzero(priv, sizeof(*priv));
libj1939_init_sockaddr_can(&priv->sockname, J1939_PGN_REQUEST_PGN);
ret = j1939_timedate_srv_parse_args(priv, argc, argv);
if (ret)
return ret;
clock_gettime(CLOCK_MONOTONIC, &ts);
priv->cmn.next_send_time = ts;
ret = j1939_timedate_srv_sock_prepare(priv);
if (ret)
return ret;
while (1) {
ret = j1939_timedate_srv_process_events_and_tasks(priv);
if (ret)
break;
}
close(priv->cmn.epoll_fd);
free(priv->cmn.epoll_events);
close(priv->sock_main);
close(priv->sock_nack);
return ret;
}
+1 -15
View File
@@ -38,7 +38,6 @@ static const char help_msg[] =
" e.g. 80,50-100,200-210 (defaults to 0-253)" "\n"
" -c, --cache=FILE Cache file to save/restore the source address" "\n"
" -a, --address=ADDRESS Start with Source Address ADDRESS" "\n"
" -p, --prefix=STR Prefix to use when logging" "\n"
"\n"
"NAME is the 64bit nodename" "\n"
"\n"
@@ -54,14 +53,13 @@ static struct option long_opts[] = {
{ "range", required_argument, NULL, 'r', },
{ "cache", required_argument, NULL, 'c', },
{ "address", required_argument, NULL, 'a', },
{ "prefix", required_argument, NULL, 'p', },
{ },
};
#else
#define getopt_long(argc, argv, optstring, longopts, longindex) \
getopt((argc), (argv), (optstring))
#endif
static const char optstring[] = "vr:c:a:p:?";
static const char optstring[] = "vr:c:a:?";
/* byte swap functions */
static inline int host_is_little_endian(void)
@@ -466,9 +464,6 @@ int main(int argc, char *argv[])
struct sockaddr_can saddr;
uint64_t cmd_name;
#ifdef _GNU_SOURCE
program_invocation_name = program_invocation_short_name;
#endif
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) {
@@ -484,15 +479,6 @@ int main(int argc, char *argv[])
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)");
#else
err(0, "compile with -D_GNU_SOURCE to use -p");
#endif
break;
default:
fputs(help_msg, stderr);
exit(1);
+2 -11
View File
@@ -97,15 +97,6 @@ static const char help_msg[] =
static const char optstring[] = "?hi:vs:rp:P:R:B";
static void j1939cat_init_sockaddr_can(struct sockaddr_can *sac)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = J1939_NO_PGN;
}
static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd,
const void *buf, size_t buf_size)
{
@@ -766,8 +757,8 @@ int main(int argc, char *argv[])
priv->polltimeout = 100000;
priv->repeat = 1;
j1939cat_init_sockaddr_can(&priv->sockname);
j1939cat_init_sockaddr_can(&priv->peername);
libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN);
libj1939_init_sockaddr_can(&priv->peername, J1939_NO_PGN);
ret = j1939cat_parse_args(priv, argc, argv);
if (ret)
+6 -6
View File
@@ -99,7 +99,7 @@ int main(int argc, char **argv)
int filter = 0;
uint8_t priority, dst_addr;
uint64_t dst_name;
long recvflags;
uint64_t recvflags;
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
@@ -230,11 +230,11 @@ int main(int argc, char **argv)
case SOL_SOCKET:
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
memcpy(&tdut, CMSG_DATA(cmsg), sizeof(tdut));
recvflags |= 1 << cmsg->cmsg_type;
recvflags |= 1ULL << cmsg->cmsg_type;
}
break;
case SOL_CAN_J1939:
recvflags |= 1 << cmsg->cmsg_type;
recvflags |= 1ULL << cmsg->cmsg_type;
if (cmsg->cmsg_type == SCM_J1939_DEST_ADDR)
dst_addr = *CMSG_DATA(cmsg);
else if (cmsg->cmsg_type == SCM_J1939_DEST_NAME)
@@ -245,7 +245,7 @@ int main(int argc, char **argv)
}
}
if (recvflags & (1 << SCM_TIMESTAMP)) {
if (recvflags & (1ULL << SCM_TIMESTAMP)) {
if ('z' == s.time) {
if (!tref.tv_sec)
tref = tdut;
@@ -270,9 +270,9 @@ abs_time:
}
}
printf(" %s ", libj1939_addr2str(&src));
if (recvflags & (1 << SCM_J1939_DEST_NAME))
if (recvflags & (1ULL << SCM_J1939_DEST_NAME))
printf("%016llx ", (unsigned long long)dst_name);
else if (recvflags & (1 << SCM_J1939_DEST_ADDR))
else if (recvflags & (1ULL << SCM_J1939_DEST_ADDR))
printf("%02x ", dst_addr);
else
printf("- ");
-3
View File
@@ -94,9 +94,6 @@ int main(int argc, char **argv)
struct pollfd pfd[2];
uint8_t *buf;
#ifdef _GNU_SOURCE
program_invocation_name = program_invocation_short_name;
#endif
/* argument parsing */
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
switch (opt) {
+239 -5
View File
@@ -11,19 +11,24 @@
*/
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <linux/kernel.h>
#include <net/if.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#include <net/if.h>
#include "libj1939.h"
#include "lib.h"
/* static data */
static struct if_nameindex *saved;
@@ -195,3 +200,232 @@ const char *libj1939_addr2str(const struct sockaddr_can *can)
return buf;
}
void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn)
{
sac->can_family = AF_CAN;
sac->can_addr.j1939.addr = J1939_NO_ADDR;
sac->can_addr.j1939.name = J1939_NO_NAME;
sac->can_addr.j1939.pgn = pgn;
}
/**
* libj1939_open_socket - Open a new J1939 socket
*
* This function opens a new J1939 socket.
*
* Return: The file descriptor of the new socket, or a negative error code.
*/
int libj1939_open_socket(void)
{
int ret;
/* Create a new CAN J1939 socket */
ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
if (ret < 0) {
/* Get the error code and print an error message */
ret = -errno;
pr_err("socket(j1939): %d (%s)", ret, strerror(ret));
return ret;
}
return ret;
}
/**
* libj1939_bind_socket - Bind a J1939 socket to a specific address
* @sock: The file descriptor of the socket
* @addr: The address to bind to
*
* This function binds a J1939 socket to a specific address.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_bind_socket(int sock, struct sockaddr_can *addr)
{
int ret;
ret = bind(sock, (void *)addr, sizeof(*addr));
if (ret < 0) {
ret = -errno;
pr_err("failed to bind: %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_socket_prio - Set the priority of a J1939 socket
* @sock: The file descriptor of the socket
* @prio: The priority to set
*
* This function sets the priority of a J1939 socket.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_socket_prio(int sock, int prio)
{
int ret;
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO,
&prio, sizeof(prio));
if (ret < 0) {
ret = -errno;
pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret,
strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_set_broadcast - Enable broadcast on a J1939 socket
* @sock: The file descriptor of the socket
*
* This function enables broadcast on a J1939 socket.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_set_broadcast(int sock)
{
int broadcast = true;
int ret;
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast));
if (ret < 0) {
ret = -errno;
pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_add_socket_to_epoll - Add a socket to an epoll instance
* @epoll_fd: The file descriptor of the epoll instance
* @sock: The file descriptor of the socket
* @events: The events to monitor
*
* This function adds a socket to an epoll instance.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events)
{
struct epoll_event ev = {0};
int ret;
ev.events = events;
ev.data.fd = sock;
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev);
if (ret < 0) {
ret = errno;
pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
/**
* libj1939_create_epoll - Create a new epoll instance
*
* This function creates a new epoll instance.
*
* Return: The file descriptor of the new epoll instance, or a negative error
* code.
*/
int libj1939_create_epoll(void)
{
int ret, epoll_fd;
epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
ret = -errno;
pr_err("epoll_create1: %d (%s)", ret, strerror(ret));
return ret;
}
return epoll_fd;
}
/**
* libj1939_get_timeout_ms - Get the timeout in milliseconds until a specific
* time
* @ts: The time to wait for
* @return: The timeout in milliseconds until the specified time
*
* This function calculates the timeout in milliseconds until a specific time.
*
* Return: The timeout in milliseconds until the specified time.
*/
static int libj1939_get_timeout_ms(struct timespec *ts)
{
struct timespec curr_time;
int64_t time_diff;
int timeout_ms;
clock_gettime(CLOCK_MONOTONIC, &curr_time);
time_diff = timespec_diff_ms(ts, &curr_time);
if (time_diff < 0) {
/* Too late to send next message. Send it now */
timeout_ms = 0;
} else {
if (time_diff > INT_MAX) {
pr_warn("timeout too long: %" PRId64 " ms", time_diff);
time_diff = INT_MAX;
}
timeout_ms = time_diff;
}
return timeout_ms;
}
/**
* libj1939_prepare_for_events - Prepare and wait for events on an epoll
* @cmn: The common J1939 instance data
* @nfds: The number of file descriptors that are ready
* @dont_wait: Don't wait for events, just check if there are any
*
* This function calculates the timeout until the next message should be sent
* or any other event should be handled, prepares the epoll instance for events
* by waiting for the specified timeout or until an event occurs, and waits for
* events on the epoll instance.
*
* Return: 0 on success, or a negative error code.
*/
int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds,
bool dont_wait)
{
int ret, timeout_ms;
if (dont_wait)
timeout_ms = 0;
else
timeout_ms = libj1939_get_timeout_ms(&cmn->next_send_time);
ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events,
cmn->epoll_events_size, timeout_ms);
if (ret < 0) {
ret = -errno;
if (ret != -EINTR) {
*nfds = 0;
return ret;
}
}
*nfds = ret;
ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time);
if (ret < 0) {
ret = -errno;
pr_err("failed to get time: %i (%s)", ret, strerror(ret));
return ret;
}
return 0;
}
+23 -1
View File
@@ -13,9 +13,11 @@
/* needed on some 64 bit platforms to get consistent 64-bit types */
#define __SANE_USERSPACE_TYPES__
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/j1939.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/socket.h>
#ifndef J1939_LIB_H
#define J1939_LIB_H
@@ -24,10 +26,30 @@
extern "C" {
#endif
struct libj1939_cmn {
int epoll_fd;
struct epoll_event *epoll_events;
size_t epoll_events_size;
struct timespec next_send_time;
struct timespec last_time;
};
void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr);
extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can);
extern const char *libj1939_addr2str(const struct sockaddr_can *can);
void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn);
int libj1939_open_socket(void);
int libj1939_bind_socket(int sock, struct sockaddr_can *addr);
int libj1939_socket_prio(int sock, int prio);
int libj1939_set_broadcast(int sock);
int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events);
int libj1939_create_epoll(void);
int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds,
bool dont_wait);
#ifdef __cplusplus
}
#endif
+144 -28
View File
@@ -54,6 +54,15 @@
#include "lib.h"
/* relevant flags in Flags field */
#define ASC_F_RTR 0x00000010
#define ASC_F_FDF 0x00001000
#define ASC_F_BRS 0x00002000
#define ASC_F_ESI 0x00004000
#define ASC_F_XLF 0x00400000
#define ASC_F_RES 0x00800000
#define ASC_F_SEC 0x01000000
extern int optind, opterr, optopt;
static void print_usage(char *prg)
@@ -65,18 +74,17 @@ static void print_usage(char *prg)
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, " -f (use CANFD format also for CAN CC)\n");
fprintf(stderr, " -x (use CANXL format also for CAN CC/FD)\n");
fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n");
}
static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
static void can_asc(struct can_frame *cf, int devno, int nortrdlc,
char *extra_info, FILE *outfile)
{
int i;
unsigned int i, dlc;
char id[10];
char *dir = "Rx";
int dlc;
struct can_frame *cf = (struct can_frame *)cfd; /* for len8_dlc */
fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
@@ -93,7 +101,7 @@ static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
dir = "Tx";
}
fprintf(outfile, "%-15s %s ", id, dir);
fprintf(outfile, "%-15s %-4s ", id, dir);
if (cf->len == CAN_MAX_DLC &&
cf->len8_dlc > CAN_MAX_DLC &&
@@ -120,19 +128,13 @@ static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc,
static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
char *extra_info, FILE *outfile)
{
int i;
unsigned 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 */
@@ -140,7 +142,7 @@ static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
dir = "Tx";
}
fprintf(outfile, "CANFD %3d %s ", devno, dir); /* 3 column channel number right aligned */
fprintf(outfile, "CANFD %3d %-4s ", 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':' ');
@@ -174,13 +176,124 @@ static void canfd_asc(struct canfd_frame *cf, int devno, int mtu,
fprintf(outfile, "%2d", dlen);
for (i = 0; i < (int)dlen; i++) {
for (i = 0; i < dlen; i++) {
fprintf(outfile, " %02X", cf->data[i]);
}
fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags);
}
static void canxl_asc(cu_t *cu, int devno, int mtu,
char *extra_info, FILE *outfile)
{
char id[10];
char *dir = "Rx";
char *frametype;
unsigned char *dataptr;
unsigned int i, dlen, dlc, flags = 0;
/* check for extra info */
if (strlen(extra_info) > 0) {
/* only the first char is defined so far */
if (extra_info[0] == 'T')
dir = "Tx";
}
switch (mtu) {
case CANXL_MTU:
sprintf(id, "%X", cu->xl.prio & CANXL_PRIO_MASK);
frametype = "XLFF";
dataptr = &cu->xl.data[0];
dlen = cu->xl.len;
dlc = dlen - 1;
flags = (ASC_F_XLF | ASC_F_FDF | ASC_F_BRS);
if (cu->xl.flags & CANXL_SEC)
flags |= ASC_F_SEC;
if (cu->xl.flags & CANXL_RRS)
flags |= ASC_F_RES;
break;
case CANFD_MTU:
if (cu->fd.can_id & CAN_EFF_FLAG) {
sprintf(id, "%Xx", cu->fd.can_id & CAN_EFF_MASK);
frametype = "FEFF";
} else {
sprintf(id, "%X", cu->fd.can_id & CAN_SFF_MASK);
frametype = "FBFF";
}
dataptr = &cu->fd.data[0];
dlen = cu->fd.len;
dlc = can_fd_len2dlc(dlen);
flags = ASC_F_FDF;
if (cu->fd.flags & CANFD_BRS)
flags |= ASC_F_BRS;
if (cu->fd.flags & CANFD_ESI)
flags |= ASC_F_ESI;
break;
case CAN_MTU:
if (cu->cc.can_id & CAN_EFF_FLAG) {
sprintf(id, "%Xx", cu->cc.can_id & CAN_EFF_MASK);
frametype = "CEFF";
} else {
sprintf(id, "%X", cu->cc.can_id & CAN_SFF_MASK);
frametype = "CBFF";
}
dataptr = &cu->cc.data[0];
dlen = cu->cc.len;
dlc = dlen ;
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
if ((dlen == CAN_MAX_DLEN) && (cu->cc.len8_dlc > CAN_MAX_DLEN) &&
(cu->cc.len8_dlc <= CAN_MAX_RAW_DLC))
dlc = cu->cc.len8_dlc;
if (cu->cc.can_id & CAN_RTR_FLAG) {
/* no data length but dlc for RTR frames */
dlen = 0;
flags = ASC_F_RTR;
}
break;
default:
return;
}
fprintf(outfile, "CANXL %3d %-4s ", devno, dir); /* 3 column channel number and direction */
fprintf(outfile, "%s 984438 4656 ", frametype); /* frame type / msg duration / bit count */
fprintf(outfile, "%9s ", id); /* ID / symbolic name (empty) */
if (mtu == CANXL_MTU) /* SDT, SEC bit for CAN XL only */
fprintf(outfile, "%02x %d ", cu->xl.sdt, (cu->xl.flags & CANXL_SEC)?1:0);
fprintf(outfile, "%x %d", dlc, dlen); /* DLC and data length */
if (mtu == CANXL_MTU) /* SBC / PCRC / VCID / AF */
fprintf(outfile, " 1 1f96 %02x %08x",
(unsigned char)((cu->xl.prio >> CANXL_VCID_OFFSET) & CANXL_VCID_VAL_MASK),
cu->xl.af);
for (i = 0; i < dlen; i++) {
fprintf(outfile, " %02x", dataptr[i]);
}
if (mtu == CANFD_MTU) /* stuff field */
fprintf(outfile, " 8");
fprintf(outfile, " 123123 %08x %08x", flags, 0); /* fcsc, msg flags, msg flags ext */
fprintf(outfile, /* bitrate settings for CC/FD/XL */
" 000000050005000e 0000000000a00010"
" 0000000a000a001d 0000000000a00002"
" 000000100010000f 0000000000a00001");
}
#define DEVSZ 22
#define EXTRASZ 20
#define TIMESZ sizeof("(1345212884.318850) ")
@@ -205,11 +318,11 @@ int main(int argc, char **argv)
static struct timeval tv, start_tv;
FILE *infile = stdin;
FILE *outfile = stdout;
static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu;
static int maxdev, devno, i, crlf, fdfmt, xlfmt, nortrdlc, d4, opt, mtu;
int print_banner = 1;
unsigned long long sec, usec;
while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) {
while ((opt = getopt(argc, argv, "I:O:4nfxr?")) != -1) {
switch (opt) {
case 'I':
infile = fopen(optarg, "r");
@@ -235,6 +348,10 @@ int main(int argc, char **argv)
fdfmt = 1;
break;
case 'x':
xlfmt = 1;
break;
case 'r':
nortrdlc = 1;
break;
@@ -300,6 +417,9 @@ int main(int argc, char **argv)
(crlf)?"\r\n":"\n");
fprintf(outfile, "no internal events logged%s",
(crlf)?"\r\n":"\n");
fprintf(outfile, "// version 18.2.0%s", (crlf)?"\r\n":"\n");
fprintf(outfile, "// Measurement UUID: cc9c7b54-68ae-"
"46d2-a43a-6aa87df7dd74%s", (crlf)?"\r\n":"\n");
}
for (i = 0, devno = 0; i < maxdev; i++) {
@@ -313,14 +433,8 @@ int main(int argc, char **argv)
mtu = parse_canframe(afrbuf, &cu);
/* convert only CAN CC and CAN FD frames */
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) {
printf("no valid CAN CC/FD frame\n");
return 1;
}
/* we don't support error message frames in CAN FD */
if ((mtu == CANFD_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
/* no error message frames in non CAN CC frames */
if ((mtu != CAN_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
continue;
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
@@ -335,10 +449,12 @@ int main(int argc, char **argv)
else
fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec);
if ((mtu == CAN_MTU) && (fdfmt == 0))
can_asc(&cu.fd, devno, nortrdlc, extra_info, outfile);
else
if ((mtu == CAN_MTU) && (fdfmt == 0) && (xlfmt == 0))
can_asc(&cu.cc, devno, nortrdlc, extra_info, outfile);
else if ((mtu != CANXL_MTU) && (xlfmt == 0))
canfd_asc(&cu.fd, devno, mtu, extra_info, outfile);
else
canxl_asc(&cu, devno, mtu, extra_info, outfile);
if (crlf)
fprintf(outfile, "\r");