You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/15 13:23:43 UTC

[incubator-nuttx-apps] branch master updated (faba024 -> 1ae2f4a)

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git.


    from faba024  Include malloc.h instead of stdlib.h for mallinfo()
     new 839b353  netlib: add AF_CAN family and CONFIG_NET_CAN support
     new 1ae2f4a  Ported candump & cansend apps from can-utils (https://github.com/linux-can/can-utils)

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 canutils/candump/Kconfig                           |  16 +
 .../hdc1008_demo => canutils/candump}/Make.defs    |   7 +-
 .../hdc1008_demo => canutils/candump}/Makefile     |  18 +-
 canutils/candump/candump.c                         | 809 +++++++++++++++++++++
 canutils/cansend/Kconfig                           |  16 +
 .../hdc1008_demo => canutils/cansend}/Make.defs    |   7 +-
 .../hdc1008_demo => canutils/cansend}/Makefile     |  18 +-
 canutils/cansend/cansend.c                         | 169 +++++
 canutils/libcanutils/Kconfig                       |  16 +
 .../libcanutils}/Make.defs                         |   6 +-
 .../Make.defs => canutils/libcanutils/Makefile     |  13 +-
 canutils/libcanutils/lib.c                         | 609 ++++++++++++++++
 canutils/libcanutils/lib.h                         | 222 ++++++
 canutils/libcanutils/terminal.h                    |  95 +++
 include/netutils/netlib.h                          |   4 +
 netutils/netinit/netinit.c                         |  12 +
 16 files changed, 2008 insertions(+), 29 deletions(-)
 create mode 100644 canutils/candump/Kconfig
 copy {examples/hdc1008_demo => canutils/candump}/Make.defs (85%)
 copy {examples/hdc1008_demo => canutils/candump}/Makefile (72%)
 create mode 100644 canutils/candump/candump.c
 create mode 100644 canutils/cansend/Kconfig
 copy {examples/hdc1008_demo => canutils/cansend}/Make.defs (85%)
 copy {examples/hdc1008_demo => canutils/cansend}/Makefile (72%)
 create mode 100644 canutils/cansend/cansend.c
 create mode 100644 canutils/libcanutils/Kconfig
 copy {examples/hdc1008_demo => canutils/libcanutils}/Make.defs (88%)
 copy examples/hdc1008_demo/Make.defs => canutils/libcanutils/Makefile (82%)
 create mode 100644 canutils/libcanutils/lib.c
 create mode 100644 canutils/libcanutils/lib.h
 create mode 100644 canutils/libcanutils/terminal.h


[incubator-nuttx-apps] 01/02: netlib: add AF_CAN family and CONFIG_NET_CAN support

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git

commit 839b3530d45bcec8c5933aae2dc5ae32630bfd83
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 10:52:34 2020 +0200

    netlib: add AF_CAN family and CONFIG_NET_CAN support
---
 include/netutils/netlib.h  |  4 ++++
 netutils/netinit/netinit.c | 12 ++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h
index 8ddcde7..04c87e7 100644
--- a/include/netutils/netlib.h
+++ b/include/netutils/netlib.h
@@ -98,6 +98,8 @@
 #  define NETLIB_SOCK_FAMILY  AF_LOCAL
 #elif defined(CONFIG_NET_PKT)
 #  define NETLIB_SOCK_FAMILY  AF_PACKET
+#elif defined(CONFIG_NET_CAN)
+#  define NETLIB_SOCK_FAMILY  AF_CAN
 #elif defined(CONFIG_NET_IEEE802154)
 #  define NETLIB_SOCK_FAMILY  AF_IEEE802154
 #elif defined(CONFIG_WIRELESS_PKTRADIO)
@@ -152,6 +154,8 @@
 #  endif
 #elif NETLIB_SOCK_FAMILY == AF_PACKET
 #  define NETLIB_SOCK_TYPE SOCK_RAW
+#elif NETLIB_SOCK_FAMILY == AF_CAN
+#  define NETLIB_SOCK_TYPE SOCK_RAW
 #elif NETLIB_SOCK_FAMILY == AF_IEEE802154
 #  define NETLIB_SOCK_TYPE SOCK_DGRAM
 #elif NETLIB_SOCK_FAMILY == AF_BLUETOOTH
diff --git a/netutils/netinit/netinit.c b/netutils/netinit/netinit.c
index 0bc5346..c2ae868 100644
--- a/netutils/netinit/netinit.c
+++ b/netutils/netinit/netinit.c
@@ -100,6 +100,7 @@
 #  undef CONFIG_NET_LOCAL
 #  undef CONFIG_NET_USRSOCK
 #  undef CONFIG_NET_IEEE802154
+#  undef CONFIG_NET_CAN
 #  undef CONFIG_NET_LOOPBACK
 #elif defined(CONFIG_NET_6LOWPAN)
 #  undef CONFIG_NET_SLIP
@@ -107,26 +108,34 @@
 #  undef CONFIG_NET_LOCAL
 #  undef CONFIG_NET_USRSOCK
 #  undef CONFIG_NET_IEEE802154
+#  undef CONFIG_NET_CAN
 #  undef CONFIG_NET_LOOPBACK
 #elif defined(CONFIG_NET_SLIP)
 #  undef CONFIG_NET_TUN
 #  undef CONFIG_NET_LOCAL
 #  undef CONFIG_NET_USRSOCK
 #  undef CONFIG_NET_IEEE802154
+#  undef CONFIG_NET_CAN
 #  undef CONFIG_NET_LOOPBACK
 #elif defined(CONFIG_NET_TUN)
 #  undef CONFIG_NET_LOCAL
 #  undef CONFIG_NET_USRSOCK
 #  undef CONFIG_NET_IEEE802154
+#  undef CONFIG_NET_CAN
 #  undef CONFIG_NET_LOOPBACK
 #elif defined(CONFIG_NET_LOCAL)
 #  undef CONFIG_NET_USRSOCK
 #  undef CONFIG_NET_IEEE802154
+#  undef CONFIG_NET_CAN
 #  undef CONFIG_NET_LOOPBACK
 #elif defined(CONFIG_NET_USRSOCK)
 #  undef CONFIG_NET_IEEE802154
+#  undef CONFIG_NET_CAN
 #  undef CONFIG_NET_LOOPBACK
 #elif defined(CONFIG_NET_IEEE802154)
+#  undef CONFIG_NET_CAN
+#  undef CONFIG_NET_LOOPBACK
+#elif defined(CONFIG_NET_CAN)
 #  undef CONFIG_NET_LOOPBACK
 #endif
 
@@ -189,6 +198,9 @@
 #elif defined(CONFIG_NET_LOCAL)
 #  define NET_DEVNAME "lo"
 #  define NETINIT_HAVE_NETDEV
+#elif defined(CONFIG_NET_CAN)
+#  define NET_DEVNAME "can0"
+#  define NETINIT_HAVE_NETDEV
 #endif
 
 /* If we have no network device (perhaps only USRSOCK, local loopback, or


[incubator-nuttx-apps] 02/02: Ported candump & cansend apps from can-utils (https://github.com/linux-can/can-utils)

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git

commit 1ae2f4a304ff324493612ad590aba155ec99d4ea
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 12:29:01 2020 +0200

    Ported candump & cansend apps from can-utils (https://github.com/linux-can/can-utils)
---
 canutils/candump/Kconfig        |  16 +
 canutils/candump/Make.defs      |  24 ++
 canutils/candump/Makefile       |  34 ++
 canutils/candump/candump.c      | 809 ++++++++++++++++++++++++++++++++++++++++
 canutils/cansend/Kconfig        |  16 +
 canutils/cansend/Make.defs      |  24 ++
 canutils/cansend/Makefile       |  34 ++
 canutils/cansend/cansend.c      | 169 +++++++++
 canutils/libcanutils/Kconfig    |  16 +
 canutils/libcanutils/Make.defs  |  23 ++
 canutils/libcanutils/Makefile   |  28 ++
 canutils/libcanutils/lib.c      | 609 ++++++++++++++++++++++++++++++
 canutils/libcanutils/lib.h      | 222 +++++++++++
 canutils/libcanutils/terminal.h |  95 +++++
 14 files changed, 2119 insertions(+)

diff --git a/canutils/candump/Kconfig b/canutils/candump/Kconfig
new file mode 100644
index 0000000..0ba3eb0
--- /dev/null
+++ b/canutils/candump/Kconfig
@@ -0,0 +1,16 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config CANUTILS_CANDUMP
+	tristate "SocketCAN candump tool"
+	default n
+	depends on NET_CAN
+        select CANUTILS_LIBCANUTILS
+	---help---
+		Enable the SocketCAN candump tool ported from
+		https://github.com/linux-can/can-utils
+
+if CANUTILS_CANDUMP
+endif
diff --git a/canutils/candump/Make.defs b/canutils/candump/Make.defs
new file mode 100644
index 0000000..bf15862
--- /dev/null
+++ b/canutils/candump/Make.defs
@@ -0,0 +1,24 @@
+############################################################################
+# apps/canutils/candump/Make.defs
+# Adds selected applications to apps/ build
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################/
+
+ifneq ($(CONFIG_CANUTILS_CANDUMP),)
+CONFIGURED_APPS += $(APPDIR)/canutils/candump
+endif
diff --git a/canutils/candump/Makefile b/canutils/candump/Makefile
new file mode 100644
index 0000000..97b0d09
--- /dev/null
+++ b/canutils/candump/Makefile
@@ -0,0 +1,34 @@
+############################################################################
+# apps/canutils/candump/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################/
+
+-include $(TOPDIR)/Make.defs
+
+# SocketCAN userspace utilities and tools candump tool
+# https://github.com/linux-can/can-utils/blob/master/candump.c
+
+PROGNAME = candump
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 3072
+MODULE = $(CONFIG_CANUTILS_CANDUMP)
+
+CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/canutils/libcanutils}
+MAINSRC = candump.c
+
+include $(APPDIR)/Application.mk
diff --git a/canutils/candump/candump.c b/canutils/candump/candump.c
new file mode 100644
index 0000000..c0f6bd3
--- /dev/null
+++ b/canutils/candump/candump.c
@@ -0,0 +1,809 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * candump.c
+ *
+ * Copyright (c) 2002-2009 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <li...@vger.kernel.org>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <time.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <net/if.h>
+
+#include <nuttx/can.h>
+#include <netpacket/can.h>
+
+#include "terminal.h"
+#include "lib.h"
+
+/* for hardware timestamps - since Linux 2.6.30 */
+#ifndef SO_TIMESTAMPING
+#define SO_TIMESTAMPING 37
+#endif
+
+/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
+#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
+#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
+#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
+
+#define MAXSOCK 16    /* max. number of CAN interfaces given on the cmdline */
+#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
+#define MAXCOL 6      /* number of different colors for colorized output */
+#define ANYDEV "any"  /* name of interface to receive from any CAN interface */
+#define ANL "\r\n"    /* newline in ASC mode */
+
+#define SILENT_INI 42 /* detect user setting on commandline */
+#define SILENT_OFF 0  /* no silent mode */
+#define SILENT_ANI 1  /* silent mode with animation */
+#define SILENT_ON  2  /* silent mode (completely silent) */
+
+#define BOLD    ATTBOLD
+#define RED     ATTBOLD FGRED
+#define GREEN   ATTBOLD FGGREEN
+#define YELLOW  ATTBOLD FGYELLOW
+#define BLUE    ATTBOLD FGBLUE
+#define MAGENTA ATTBOLD FGMAGENTA
+#define CYAN    ATTBOLD FGCYAN
+
+const char col_on [MAXCOL][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
+const char col_off [] = ATTRESET;
+
+static char *cmdlinename[MAXSOCK];
+static __u32 dropcnt[MAXSOCK];
+static __u32 last_dropcnt[MAXSOCK];
+static char devname[MAXIFNAMES][IFNAMSIZ+1];
+static int  dindex[MAXIFNAMES];
+static int  max_devname_len; /* to prevent frazzled device name output */ 
+const int canfd_on = 1;
+
+#define MAXANI 4
+const char anichar[MAXANI] = {'|', '/', '-', '\\'};
+const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
+
+extern int optind, opterr, optopt;
+
+static volatile int running = 1;
+
+void print_usage(char *prg)
+{
+	fprintf(stderr, "%s - dump CAN bus traffic.\n", prg);
+	fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
+	fprintf(stderr, "  (use CTRL-C to terminate %s)\n\n", prg);
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "         -t <type>   (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
+	fprintf(stderr, "         -H          (read hardware timestamps instead of system timestamps)\n");
+	fprintf(stderr, "         -c          (increment color mode level)\n");
+	fprintf(stderr, "         -i          (binary output - may exceed 80 chars/line)\n");
+	fprintf(stderr, "         -a          (enable additional ASCII output)\n");
+	fprintf(stderr, "         -S          (swap byte order in printed CAN data[] - marked with '%c' )\n", SWAP_DELIMITER);
+	fprintf(stderr, "         -s <level>  (silent mode - %d: off (default) %d: animation %d: silent)\n", SILENT_OFF, SILENT_ANI, SILENT_ON);
+	fprintf(stderr, "         -l          (log CAN-frames into file. Sets '-s %d' by default)\n", SILENT_ON);
+	fprintf(stderr, "         -L          (use log file format on stdout)\n");
+	fprintf(stderr, "         -n <count>  (terminate after reception of <count> CAN frames)\n");
+	fprintf(stderr, "         -r <size>   (set socket receive buffer to <size>)\n");
+	fprintf(stderr, "         -D          (Don't exit if a \"detected\" can device goes down.\n");
+	fprintf(stderr, "         -d          (monitor dropped CAN frames)\n");
+	fprintf(stderr, "         -e          (dump CAN error frames in human-readable format)\n");
+	fprintf(stderr, "         -x          (print extra message infos, rx/tx brs esi)\n");
+	fprintf(stderr, "         -T <msecs>  (terminate after <msecs> without any reception)\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
+	fprintf(stderr, "on the commandline in the form: <ifname>[,filter]*\n");
+	fprintf(stderr, "\nFilters:\n");
+	fprintf(stderr, "  Comma separated filters can be specified for each given CAN interface:\n");
+	fprintf(stderr, "    <can_id>:<can_mask>\n         (matches when <received_can_id> & mask == can_id & mask)\n");
+	fprintf(stderr, "    <can_id>~<can_mask>\n         (matches when <received_can_id> & mask != can_id & mask)\n");
+	fprintf(stderr, "    #<error_mask>\n         (set error frame filter, see include/linux/can/error.h)\n");
+	fprintf(stderr, "    [j|J]\n         (join the given CAN filters - logical AND semantic)\n");
+	fprintf(stderr, "\nCAN IDs, masks and data content are given and expected in hexadecimal values.\n");
+	fprintf(stderr, "When the can_id is 8 digits long the CAN_EFF_FLAG is set for 29 bit EFF format.\n");
+	fprintf(stderr, "Without any given filter all data frames are received ('0:0' default filter).\n");
+	fprintf(stderr, "\nUse interface name '%s' to receive from all CAN interfaces.\n", ANYDEV);
+	fprintf(stderr, "\nExamples:\n");
+	fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n\n", prg);
+	fprintf(stderr, "%s -l any,0~0,#FFFFFFFF\n         (log only error frames but no(!) data frames)\n", prg);
+	fprintf(stderr, "%s -l any,0:0,#FFFFFFFF\n         (log error frames and also all data frames)\n", prg);
+	fprintf(stderr, "%s vcan2,12345678:DFFFFFFF\n         (match only for extended CAN ID 12345678)\n", prg);
+	fprintf(stderr, "%s vcan2,123:7FF\n         (matches CAN ID 123 - including EFF and RTR frames)\n", prg);
+	fprintf(stderr, "%s vcan2,123:C00007FF\n         (matches CAN ID 123 - only SFF and non-RTR frames)\n", prg);
+	fprintf(stderr, "\n");
+}
+
+void sigterm(int signo)
+{
+	running = 0;
+}
+
+int idx2dindex(int ifidx, int socket) {
+
+	int i;
+	struct ifreq ifr;
+
+	for (i=0; i < MAXIFNAMES; i++) {
+		if (dindex[i] == ifidx)
+			return i;
+	}
+
+	/* create new interface index cache entry */
+
+	/* remove index cache zombies first */
+	for (i=0; i < MAXIFNAMES; i++) {
+		if (dindex[i]) {
+			ifr.ifr_ifindex = dindex[i];
+			if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
+				dindex[i] = 0;
+		}
+	}
+
+	for (i=0; i < MAXIFNAMES; i++)
+		if (!dindex[i]) /* free entry */
+			break;
+
+	if (i == MAXIFNAMES) {
+		fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
+		       MAXIFNAMES);
+		exit(1);
+	}
+
+	dindex[i] = ifidx;
+
+	ifr.ifr_ifindex = ifidx;
+	if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
+		perror("SIOCGIFNAME");
+
+	if (max_devname_len < (int)strlen(ifr.ifr_name))
+		max_devname_len = strlen(ifr.ifr_name);
+
+	strcpy(devname[i], ifr.ifr_name);
+
+#ifdef DEBUG
+	printf("new index %d (%s)\n", i, devname[i]);
+#endif
+
+	return i;
+}
+
+int main(int argc, char **argv)
+{
+	fd_set rdfs;
+	int s[MAXSOCK];
+	unsigned char timestamp = 0;
+	unsigned char hwtimestamp = 0;
+	unsigned char down_causes_exit = 1;
+	unsigned char dropmonitor = 0;
+	unsigned char extra_msg_info = 0;
+	unsigned char silent = SILENT_INI;
+	unsigned char silentani = 0;
+	unsigned char color = 0;
+	unsigned char view = 0;
+	unsigned char log = 0;
+	unsigned char logfrmt = 0;
+	int count = 0;
+	int rcvbuf_size = 0;
+	int opt, ret;
+	int currmax, numfilter;
+	int join_filter;
+	char *ptr, *nptr;
+	struct sockaddr_can addr;
+	char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
+	struct iovec iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct can_filter *rfilter;
+	can_err_mask_t err_mask;
+	struct canfd_frame frame;
+	int nbytes, i, maxdlen;
+	struct ifreq ifr;
+	struct timeval tv, last_tv;
+	struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
+	FILE *logfile = NULL;
+
+#if 0 /* NuttX doesn't support these signals */   
+	signal(SIGTERM, sigterm);
+	signal(SIGHUP, sigterm);
+#endif
+	signal(SIGINT, sigterm);
+
+	last_tv.tv_sec  = 0;
+	last_tv.tv_usec = 0;
+
+	while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:heT:?")) != -1) {
+		switch (opt) {
+		case 't':
+			timestamp = optarg[0];
+			if ((timestamp != 'a') && (timestamp != 'A') &&
+			    (timestamp != 'd') && (timestamp != 'z')) {
+				fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
+				       basename(argv[0]), optarg[0]);
+				timestamp = 0;
+			}
+			break;
+
+		case 'H':
+			hwtimestamp = 1;
+			break;
+
+		case 'c':
+			color++;
+			break;
+
+		case 'i':
+			view |= CANLIB_VIEW_BINARY;
+			break;
+
+		case 'a':
+			view |= CANLIB_VIEW_ASCII;
+			break;
+
+		case 'S':
+			view |= CANLIB_VIEW_SWAP;
+			break;
+
+		case 'e':
+			view |= CANLIB_VIEW_ERROR;
+			break;
+
+		case 's':
+			silent = atoi(optarg);
+			if (silent > SILENT_ON) {
+				print_usage(basename(argv[0]));
+				exit(1);
+			}
+			break;
+
+		case 'l':
+			log = 1;
+			break;
+
+		case 'D':
+			down_causes_exit = 0;
+			break;
+
+		case 'd':
+			dropmonitor = 1;
+			break;
+
+		case 'x':
+			extra_msg_info = 1;
+			break;
+
+		case 'L':
+			logfrmt = 1;
+			break;
+
+		case 'n':
+			count = atoi(optarg);
+			if (count < 1) {
+				print_usage(basename(argv[0]));
+				exit(1);
+			}
+			break;
+
+		case 'r':
+			rcvbuf_size = atoi(optarg);
+			if (rcvbuf_size < 1) {
+				print_usage(basename(argv[0]));
+				exit(1);
+			}
+			break;
+
+		case 'T':
+			errno = 0;
+			timeout_config.tv_usec = strtol(optarg, NULL, 0);
+			if (errno != 0) {
+				print_usage(basename(argv[0]));
+				exit(1);
+			}
+			timeout_config.tv_sec = timeout_config.tv_usec / 1000;
+			timeout_config.tv_usec = (timeout_config.tv_usec % 1000) * 1000;
+			timeout_current = &timeout;
+			break;
+		default:
+			print_usage(basename(argv[0]));
+			exit(1);
+			break;
+		}
+	}
+
+	if (optind == argc) {
+		print_usage(basename(argv[0]));
+		exit(0);
+	}
+	
+	if (logfrmt && view) {
+		fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
+		exit(0);
+	}
+
+	if (silent == SILENT_INI) {
+		if (log) {
+			fprintf(stderr, "Disabled standard output while logging.\n");
+			silent = SILENT_ON; /* disable output on stdout */
+		} else
+			silent = SILENT_OFF; /* default output */
+	}
+
+	currmax = argc - optind; /* find real number of CAN devices */
+
+	if (currmax > MAXSOCK) {
+		fprintf(stderr, "More than %d CAN devices given on commandline!\n", MAXSOCK);
+		return 1;
+	}
+
+	for (i=0; i < currmax; i++) {
+
+		ptr = argv[optind+i];
+		nptr = strchr(ptr, ',');
+
+#ifdef DEBUG
+		printf("open %d '%s'.\n", i, ptr);
+#endif
+
+		s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+		if (s[i] < 0) {
+			perror("socket");
+			return 1;
+		}
+
+		cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
+
+		if (nptr)
+			nbytes = nptr - ptr;  /* interface name is up the first ',' */
+		else
+			nbytes = strlen(ptr); /* no ',' found => no filter definitions */
+
+		if (nbytes >= IFNAMSIZ) {
+			fprintf(stderr, "name of CAN device '%s' is too long!\n", ptr);
+			return 1;
+		}
+
+		if (nbytes > max_devname_len)
+			max_devname_len = nbytes; /* for nice printing */
+
+		addr.can_family = AF_CAN;
+
+		memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
+		strncpy(ifr.ifr_name, ptr, nbytes);
+
+#ifdef DEBUG
+		printf("using interface name '%s'.\n", ifr.ifr_name);
+#endif
+
+		if (strcmp(ANYDEV, ifr.ifr_name)) {
+			if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
+				perror("SIOCGIFINDEX");
+				exit(1);
+			}
+			addr.can_ifindex = ifr.ifr_ifindex;
+		} else
+			addr.can_ifindex = 0; /* any can interface */
+
+		if (nptr) {
+
+			/* found a ',' after the interface name => check for filters */
+
+			/* determine number of filters to alloc the filter space */
+			numfilter = 0;
+			ptr = nptr;
+			while (ptr) {
+				numfilter++;
+				ptr++; /* hop behind the ',' */
+				ptr = strchr(ptr, ','); /* exit condition */
+			}
+
+			rfilter = malloc(sizeof(struct can_filter) * numfilter);
+			if (!rfilter) {
+				fprintf(stderr, "Failed to create filter space!\n");
+				return 1;
+			}
+
+			numfilter = 0;
+			err_mask = 0;
+			join_filter = 0;
+
+			while (nptr) {
+
+				ptr = nptr+1; /* hop behind the ',' */
+				nptr = strchr(ptr, ','); /* update exit condition */
+
+				if (sscanf(ptr, "%x:%x",
+					   &rfilter[numfilter].can_id, 
+					   &rfilter[numfilter].can_mask) == 2) {
+ 					rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
+					if (*(ptr+8) == ':')
+						rfilter[numfilter].can_id |= CAN_EFF_FLAG;
+					numfilter++;
+				} else if (sscanf(ptr, "%x~%x",
+						  &rfilter[numfilter].can_id, 
+						  &rfilter[numfilter].can_mask) == 2) {
+ 					rfilter[numfilter].can_id |= CAN_INV_FILTER;
+ 					rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
+					if (*(ptr+8) == '~')
+						rfilter[numfilter].can_id |= CAN_EFF_FLAG;
+					numfilter++;
+				} else if (*ptr == 'j' || *ptr == 'J') {
+					join_filter = 1;
+				} else if (sscanf(ptr, "#%x", &err_mask) != 1) { 
+					fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
+					return 1;
+				}
+			}
+
+			if (err_mask)
+				setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
+					   &err_mask, sizeof(err_mask));
+
+			if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
+						      &join_filter, sizeof(join_filter)) < 0) {
+				perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
+				return 1;
+			}
+
+			if (numfilter)
+				setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
+					   rfilter, numfilter * sizeof(struct can_filter));
+
+			free(rfilter);
+
+		} /* if (nptr) */
+
+		/* try to switch the socket into CAN FD mode */
+		setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
+
+		if (rcvbuf_size) {
+
+			int curr_rcvbuf_size;
+			socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
+
+			/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
+			if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
+				       &rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
+#ifdef DEBUG
+				printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
+#endif
+				if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
+					       &rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
+					perror("setsockopt SO_RCVBUF");
+					return 1;
+				}
+
+				if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
+					       &curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
+					perror("getsockopt SO_RCVBUF");
+					return 1;
+				}
+
+				/* Only print a warning the first time we detect the adjustment */
+				/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
+				if (!i && curr_rcvbuf_size < rcvbuf_size*2)
+					fprintf(stderr, "The socket receive buffer size was "
+						"adjusted due to /proc/sys/net/core/rmem_max.\n");
+			}
+		}
+
+		if (timestamp || log || logfrmt) {
+
+			if (hwtimestamp) {
+				const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
+								SOF_TIMESTAMPING_RX_SOFTWARE | \
+								SOF_TIMESTAMPING_RAW_HARDWARE);
+
+				if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
+						&timestamping_flags, sizeof(timestamping_flags)) < 0) {
+					perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
+					return 1;
+				}
+			} else {
+				const int timestamp_on = 1;
+
+				if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
+					       &timestamp_on, sizeof(timestamp_on)) < 0) {
+					perror("setsockopt SO_TIMESTAMP");
+					return 1;
+				}
+			}
+		}
+
+		if (dropmonitor) {
+
+			const int dropmonitor_on = 1;
+
+			if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
+				       &dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
+				perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
+				return 1;
+			}
+		}
+
+		if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+			perror("bind");
+			return 1;
+		}
+	}
+
+	if (log) {
+		time_t currtime;
+		struct tm now;
+		char fname[83]; /* suggested by -Wformat-overflow= */
+
+		if (time(&currtime) == (time_t)-1) {
+			perror("time");
+			return 1;
+		}
+
+		localtime_r(&currtime, &now);
+
+		sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
+			now.tm_year + 1900,
+			now.tm_mon + 1,
+			now.tm_mday,
+			now.tm_hour,
+			now.tm_min,
+			now.tm_sec);
+
+		if (silent != SILENT_ON)
+			fprintf(stderr, "Warning: Console output active while logging!\n");
+
+		fprintf(stderr, "Enabling Logfile '%s'\n", fname);
+
+		logfile = fopen(fname, "w");
+		if (!logfile) {
+			perror("logfile");
+			return 1;
+		}
+	}
+
+	/* 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 = &ctrlmsg;
+
+	while (running) {
+
+		FD_ZERO(&rdfs);
+		for (i=0; i<currmax; i++)
+			FD_SET(s[i], &rdfs);
+
+		if (timeout_current)
+			*timeout_current = timeout_config;
+
+		if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
+			//perror("select");
+			running = 0;
+			continue;
+		}
+
+		for (i=0; i<currmax; i++) {  /* check all CAN RAW sockets */
+
+			if (FD_ISSET(s[i], &rdfs)) {
+
+				int idx;
+
+				/* these settings may be modified by recvmsg() */
+				iov.iov_len = sizeof(frame);
+				msg.msg_namelen = sizeof(addr);
+				msg.msg_controllen = sizeof(ctrlmsg);  
+				msg.msg_flags = 0;
+
+				nbytes = recvmsg(s[i], &msg, 0);
+				idx = idx2dindex(addr.can_ifindex, s[i]);
+
+				if (nbytes < 0) {
+					if ((errno == ENETDOWN) && !down_causes_exit) {
+						fprintf(stderr, "%s: interface down\n", devname[idx]);
+						continue;
+					}
+					perror("read");
+					return 1;
+				}
+
+				if ((size_t)nbytes == CAN_MTU)
+					maxdlen = CAN_MAX_DLEN;
+				else if ((size_t)nbytes == CANFD_MTU)
+					maxdlen = CANFD_MAX_DLEN;
+				else {
+					fprintf(stderr, "read: incomplete CAN frame\n");
+					return 1;
+				}
+
+				if (count && (--count == 0))
+					running = 0;
+		    
+				for (cmsg = CMSG_FIRSTHDR(&msg);
+				     cmsg && (cmsg->cmsg_level == SOL_SOCKET);
+				     cmsg = CMSG_NXTHDR(&msg,cmsg)) {
+					if (cmsg->cmsg_type == SO_TIMESTAMP) {
+						memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
+					} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
+
+						struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
+
+						/*
+						 * stamp[0] is the software timestamp
+						 * stamp[1] is deprecated
+						 * stamp[2] is the raw hardware timestamp
+						 * See chapter 2.1.2 Receive timestamps in
+						 * linux/Documentation/networking/timestamping.txt
+						 */
+						tv.tv_sec = stamp[2].tv_sec;
+						tv.tv_usec = stamp[2].tv_nsec/1000;
+					} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
+						memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
+				}
+
+				/* check for (unlikely) dropped frames on this specific socket */
+				if (dropcnt[i] != last_dropcnt[i]) {
+
+					__u32 frames = dropcnt[i] - last_dropcnt[i];
+
+					if (silent != SILENT_ON)
+						printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
+						       frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
+
+					if (log)
+						fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
+							frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
+
+					last_dropcnt[i] = dropcnt[i];
+				}
+
+				/* once we detected a EFF frame indent SFF frames accordingly */
+				if (frame.can_id & CAN_EFF_FLAG)
+					view |= CANLIB_VIEW_INDENT_SFF;
+
+				if (log) {
+					char buf[CL_CFSZ]; /* max length */
+
+					/* log CAN frame with absolute timestamp & device */
+					sprint_canframe(buf, &frame, 0, maxdlen);
+					fprintf(logfile, "(%010ld.%06ld) %*s %s\n",
+						tv.tv_sec, tv.tv_usec,
+						max_devname_len, devname[idx], buf);
+				}
+
+				if ((logfrmt) && (silent == SILENT_OFF)){
+					char buf[CL_CFSZ]; /* max length */
+
+					/* print CAN frame in log file style to stdout */
+					sprint_canframe(buf, &frame, 0, maxdlen);
+					printf("(%010ld.%06ld) %*s %s\n",
+					       tv.tv_sec, tv.tv_usec,
+					       max_devname_len, devname[idx], buf);
+					goto out_fflush; /* no other output to stdout */
+				}
+
+				if (silent != SILENT_OFF){
+					if (silent == SILENT_ANI) {
+						printf("%c\b", anichar[silentani%=MAXANI]);
+						silentani++;
+					}
+					goto out_fflush; /* no other output to stdout */
+				}
+		      
+				printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
+
+				switch (timestamp) {
+
+				case 'a': /* absolute with timestamp */
+					printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
+					break;
+
+				case 'A': /* absolute with date */
+				{
+					struct tm tm;
+					char timestring[25];
+
+					tm = *localtime(&tv.tv_sec);
+					strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
+					printf("(%s.%06ld) ", timestring, tv.tv_usec);
+				}
+				break;
+
+				case 'd': /* delta */
+				case 'z': /* starting with zero */
+				{
+					struct timeval diff;
+
+					if (last_tv.tv_sec == 0)   /* first init */
+						last_tv = tv;
+					diff.tv_sec  = tv.tv_sec  - last_tv.tv_sec;
+					diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
+					if (diff.tv_usec < 0)
+						diff.tv_sec--, diff.tv_usec += 1000000;
+					if (diff.tv_sec < 0)
+						diff.tv_sec = diff.tv_usec = 0;
+					printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec);
+				
+					if (timestamp == 'd')
+						last_tv = tv; /* update for delta calculation */
+				}
+				break;
+
+				default: /* no timestamp output */
+					break;
+				}
+
+				printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
+				printf("%*s", max_devname_len, devname[idx]);
+
+				if (extra_msg_info) {
+
+					if (msg.msg_flags & MSG_DONTROUTE)
+						printf ("  TX %s", extra_m_info[frame.flags & 3]);
+					else
+						printf ("  RX %s", extra_m_info[frame.flags & 3]);
+				}
+
+				printf("%s  ", (color==1)?col_off:"");
+
+				fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
+
+				printf("%s", (color>1)?col_off:"");
+				printf("\n");
+			}
+
+		out_fflush:
+			fflush(stdout);
+		}
+	}
+
+	for (i=0; i<currmax; i++)
+		close(s[i]);
+
+	if (log)
+		fclose(logfile);
+
+	return 0;
+}
diff --git a/canutils/cansend/Kconfig b/canutils/cansend/Kconfig
new file mode 100644
index 0000000..9d4adea
--- /dev/null
+++ b/canutils/cansend/Kconfig
@@ -0,0 +1,16 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config CANUTILS_CANSEND
+	tristate "SocketCAN cansend tool"
+	default n
+	depends on NET_CAN
+        select CANUTILS_LIBCANUTILS
+	---help---
+		Enable the SocketCAN cansend tool ported from
+		https://github.com/linux-can/can-utils
+
+if CANUTILS_CANSEND
+endif
diff --git a/canutils/cansend/Make.defs b/canutils/cansend/Make.defs
new file mode 100644
index 0000000..2361a59
--- /dev/null
+++ b/canutils/cansend/Make.defs
@@ -0,0 +1,24 @@
+############################################################################
+# apps/canutils/cansend/Make.defs
+# Adds selected applications to apps/ build
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################/
+
+ifneq ($(CONFIG_CANUTILS_CANSEND),)
+CONFIGURED_APPS += $(APPDIR)/canutils/cansend
+endif
diff --git a/canutils/cansend/Makefile b/canutils/cansend/Makefile
new file mode 100644
index 0000000..ccfca2a
--- /dev/null
+++ b/canutils/cansend/Makefile
@@ -0,0 +1,34 @@
+############################################################################
+# apps/canutils/cansend/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################/
+
+-include $(TOPDIR)/Make.defs
+
+# SocketCAN userspace utilities and tools cansend tool
+# https://github.com/linux-can/can-utils/blob/master/cansend.c
+
+PROGNAME = cansend
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 2048
+MODULE = $(CONFIG_CANUTILS_CANSEND)
+
+CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/canutils/libcanutils}
+MAINSRC = cansend.c
+
+include $(APPDIR)/Application.mk
diff --git a/canutils/cansend/cansend.c b/canutils/cansend/cansend.c
new file mode 100644
index 0000000..0a8e677
--- /dev/null
+++ b/canutils/cansend/cansend.c
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * cansend.c - send CAN-frames via CAN_RAW sockets
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <li...@vger.kernel.org>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <nuttx/can.h>
+#include <netpacket/can.h>
+
+#include "lib.h"
+
+void print_usage_send(char *prg)
+{
+	fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
+	fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
+	fprintf(stderr, "\n<can_frame>:\n");
+	fprintf(stderr, " <can_id>#{data}          for 'classic' CAN 2.0 data frames\n");
+	fprintf(stderr, " <can_id>#R{len}          for 'classic' CAN 2.0 data frames\n");
+	fprintf(stderr, " <can_id>##<flags>{data}  for CAN FD frames\n\n");
+	fprintf(stderr, "<can_id>:\n"
+	        " 3 (SFF) or 8 (EFF) hex chars\n");
+	fprintf(stderr, "{data}:\n"
+	        " 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
+	fprintf(stderr, "{len}:\n"
+		 " an optional 0..8 value as RTR frames can contain a valid dlc field\n");
+	fprintf(stderr, "<flags>:\n"
+	        " a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
+	fprintf(stderr, "Examples:\n");
+	fprintf(stderr, "  5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
+		 "  1F334455#1122334455667788 / 123#R / 00000123#R3\n\n");
+}
+
+
+
+int main(int argc, char **argv)
+{
+	int s; /* can raw socket */ 
+	int required_mtu;
+	int mtu;
+	int enable_canfd = 1;
+	struct sockaddr_can addr;
+	struct canfd_frame frame;
+	struct ifreq ifr;
+
+	/* check command line options */
+	if (argc != 3) {
+		print_usage_send(argv[0]);
+		return 1;
+	}
+
+	/* parse CAN frame */
+	required_mtu = parse_canframe(argv[2], &frame);
+	if (!required_mtu){
+		fprintf(stderr, "\nWrong CAN-frame format!\n\n");
+		print_usage_send(argv[0]);
+		return 1;
+	}
+
+	/* open socket */
+	if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+		perror("socket");
+		return 1;
+	}
+
+	strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);
+	ifr.ifr_name[IFNAMSIZ - 1] = '\0';
+	ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
+	if (!ifr.ifr_ifindex) {
+		perror("if_nametoindex");
+		return 1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.can_family = AF_CAN;
+	addr.can_ifindex = ifr.ifr_ifindex;
+
+	if (required_mtu > (int)CAN_MTU) {
+
+		/* check if the frame fits into the CAN netdevice */
+		if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
+			perror("SIOCGIFMTU");
+			return 1;
+		}
+		mtu = ifr.ifr_mtu;
+
+		if (mtu != CANFD_MTU) {
+			printf("CAN interface is not CAN FD capable - sorry.\n");
+			return 1;
+		}
+
+		/* interface is ok - try to switch the socket into CAN FD mode */
+		if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
+			       &enable_canfd, sizeof(enable_canfd))){
+			printf("error when enabling CAN FD support\n");
+			return 1;
+		}
+
+		/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
+		frame.len = can_dlc2len(can_len2dlc(frame.len));
+	}
+
+	/* disable default receive filter on this RAW socket */
+	/* This is obsolete as we do not read from the socket at all, but for */
+	/* this reason we can remove the receive list in the Kernel to save a */
+	/* little (really a very little!) CPU usage.                          */
+	setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	/* send frame */
+	if (write(s, &frame, required_mtu) != required_mtu) {
+		perror("write");
+		return 1;
+	}
+
+	close(s);
+
+	return 0;
+}
diff --git a/canutils/libcanutils/Kconfig b/canutils/libcanutils/Kconfig
new file mode 100644
index 0000000..922fb1f
--- /dev/null
+++ b/canutils/libcanutils/Kconfig
@@ -0,0 +1,16 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config CANUTILS_LIBCANUTILS
+	bool "CAN-utils support library"
+	default n
+	depends on NET_CAN
+	---help---
+		Enable the CAN-utils support library ported from
+		https://github.com/linux-can/can-utils
+
+if CANUTILS_LIBCANUTILS
+
+endif
diff --git a/canutils/libcanutils/Make.defs b/canutils/libcanutils/Make.defs
new file mode 100644
index 0000000..7f6c7bc
--- /dev/null
+++ b/canutils/libcanutils/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/canutils/libcanutils/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################/
+
+ifeq ($(CONFIG_CANUTILS_LIBCANUTILS),y)
+CONFIGURED_APPS += $(APPDIR)/canutils/libcanutils
+endif
diff --git a/canutils/libcanutils/Makefile b/canutils/libcanutils/Makefile
new file mode 100644
index 0000000..01e7022
--- /dev/null
+++ b/canutils/libcanutils/Makefile
@@ -0,0 +1,28 @@
+############################################################################
+# apps/canutils/libcanutils/Makefile
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################/
+
+include $(TOPDIR)/Make.defs
+
+# SocketCAN userspace utilities and tools library
+# https://github.com/linux-can/can-utils
+
+CSRCS = lib.c
+
+include $(APPDIR)/Application.mk
diff --git a/canutils/libcanutils/lib.c b/canutils/libcanutils/lib.c
new file mode 100644
index 0000000..e8a645f
--- /dev/null
+++ b/canutils/libcanutils/lib.c
@@ -0,0 +1,609 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * lib.c - library for command line tools
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <li...@vger.kernel.org>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <sys/socket.h> /* for sa_family_t */
+#include <nuttx/can.h>
+#include <nuttx/can/error.h>
+#include <netpacket/can.h>
+
+#include "lib.h"
+
+#define CANID_DELIM '#'
+#define DATA_SEPERATOR '.'
+
+const char hex_asc_upper[] = "0123456789ABCDEF";
+
+#define hex_asc_upper_lo(x)	hex_asc_upper[((x) & 0x0F)]
+#define hex_asc_upper_hi(x)	hex_asc_upper[((x) & 0xF0) >> 4]
+
+static inline void put_hex_byte(char *buf, __u8 byte)
+{
+	buf[0] = hex_asc_upper_hi(byte);
+	buf[1] = hex_asc_upper_lo(byte);
+}
+
+static inline void _put_id(char *buf, int end_offset, canid_t id)
+{
+	/* build 3 (SFF) or 8 (EFF) digit CAN identifier */
+	while (end_offset >= 0) {
+		buf[end_offset--] = hex_asc_upper_lo(id);
+		id >>= 4;
+	}
+}
+
+#define put_sff_id(buf, id) _put_id(buf, 2, id)
+#define put_eff_id(buf, id) _put_id(buf, 7, id)
+
+/* CAN DLC to real data length conversion helpers */
+
+static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
+					8, 12, 16, 20, 24, 32, 48, 64};
+
+/* get data length from can_dlc with sanitized can_dlc */
+unsigned char can_dlc2len(unsigned char can_dlc)
+{
+	return dlc2len[can_dlc & 0x0F];
+}
+
+static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,		/* 0 - 8 */
+					9, 9, 9, 9,				/* 9 - 12 */
+					10, 10, 10, 10,				/* 13 - 16 */
+					11, 11, 11, 11,				/* 17 - 20 */
+					12, 12, 12, 12,				/* 21 - 24 */
+					13, 13, 13, 13, 13, 13, 13, 13,		/* 25 - 32 */
+					14, 14, 14, 14, 14, 14, 14, 14,		/* 33 - 40 */
+					14, 14, 14, 14, 14, 14, 14, 14,		/* 41 - 48 */
+					15, 15, 15, 15, 15, 15, 15, 15,		/* 49 - 56 */
+					15, 15, 15, 15, 15, 15, 15, 15};	/* 57 - 64 */
+
+/* map the sanitized data length to an appropriate data length code */
+unsigned char can_len2dlc(unsigned char len)
+{
+	if (len > 64)
+		return 0xF;
+
+	return len2dlc[len];
+}
+
+unsigned char asc2nibble(char c) {
+
+	if ((c >= '0') && (c <= '9'))
+		return c - '0';
+
+	if ((c >= 'A') && (c <= 'F'))
+		return c - 'A' + 10;
+
+	if ((c >= 'a') && (c <= 'f'))
+		return c - 'a' + 10;
+
+	return 16; /* error */
+}
+
+int hexstring2data(char *arg, unsigned char *data, int maxdlen) {
+
+	int len = strlen(arg);
+	int i;
+	unsigned char tmp;
+
+	if (!len || len%2 || len > maxdlen*2)
+		return 1;
+
+	memset(data, 0, maxdlen);
+
+	for (i=0; i < len/2; i++) {
+
+		tmp = asc2nibble(*(arg+(2*i)));
+		if (tmp > 0x0F)
+			return 1;
+
+		data[i] = (tmp << 4);
+
+		tmp = asc2nibble(*(arg+(2*i)+1));
+		if (tmp > 0x0F)
+			return 1;
+
+		data[i] |= tmp;
+	}
+
+	return 0;
+}
+
+int parse_canframe(char *cs, struct canfd_frame *cf) {
+	/* documentation see lib.h */
+
+	int i, idx, dlen, len;
+	int maxdlen = CAN_MAX_DLEN;
+	int ret = CAN_MTU;
+	unsigned char tmp;
+
+	len = strlen(cs);
+	//printf("'%s' len %d\n", cs, len);
+
+	memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */
+
+	if (len < 4)
+		return 0;
+
+	if (cs[3] == CANID_DELIM) { /* 3 digits */
+
+		idx = 4;
+		for (i=0; i<3; i++){
+			if ((tmp = asc2nibble(cs[i])) > 0x0F)
+				return 0;
+			cf->can_id |= (tmp << (2-i)*4);
+		}
+
+	} else if (cs[8] == CANID_DELIM) { /* 8 digits */
+
+		idx = 9;
+		for (i=0; i<8; i++){
+			if ((tmp = asc2nibble(cs[i])) > 0x0F)
+				return 0;
+			cf->can_id |= (tmp << (7-i)*4);
+		}
+		if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe?  */
+			cf->can_id |= CAN_EFF_FLAG;   /* then it is an extended frame */
+
+	} else
+		return 0;
+
+	if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
+		cf->can_id |= CAN_RTR_FLAG;
+
+		/* check for optional DLC value for CAN 2.0B frames */
+		if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
+			cf->len = tmp;
+
+		return ret;
+	}
+
+	if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
+
+		maxdlen = CANFD_MAX_DLEN;
+		ret = CANFD_MTU;
+
+		/* CAN FD frame <canid>##<flags><data>* */
+		if ((tmp = asc2nibble(cs[idx+1])) > 0x0F)
+			return 0;
+
+		cf->flags = tmp;
+		idx += 2;
+	}
+
+	for (i=0, dlen=0; i < maxdlen; i++){
+
+		if(cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */
+			idx++;
+
+		if(idx >= len) /* end of string => end of data */
+			break;
+
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		cf->data[i] = (tmp << 4);
+		if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+			return 0;
+		cf->data[i] |= tmp;
+		dlen++;
+	}
+	cf->len = dlen;
+
+	return ret;
+}
+
+void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen) {
+	/* documentation see lib.h */
+
+	char buf[CL_CFSZ]; /* max length */
+
+	sprint_canframe(buf, cf, sep, maxdlen);
+	fprintf(stream, "%s", buf);
+	if (eol)
+		fprintf(stream, "%s", eol);
+}
+
+void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
+	/* documentation see lib.h */
+
+	int i,offset;
+	int len = (cf->len > maxdlen) ? maxdlen : cf->len;
+
+	if (cf->can_id & CAN_ERR_FLAG) {
+		put_eff_id(buf, cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
+		buf[8] = '#';
+		offset = 9;
+	} else if (cf->can_id & CAN_EFF_FLAG) {
+		put_eff_id(buf, cf->can_id & CAN_EFF_MASK);
+		buf[8] = '#';
+		offset = 9;
+	} else {
+		put_sff_id(buf, cf->can_id & CAN_SFF_MASK);
+		buf[3] = '#';
+		offset = 4;
+	}
+
+	/* standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
+	if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
+		buf[offset++] = 'R';
+		/* print a given CAN 2.0B DLC if it's not zero */
+		if (cf->len && cf->len <= CAN_MAX_DLC)
+			buf[offset++] = hex_asc_upper_lo(cf->len);
+
+		buf[offset] = 0;
+		return;
+	}
+
+	if (maxdlen == CANFD_MAX_DLEN) {
+		/* add CAN FD specific escape char and flags */
+		buf[offset++] = '#';
+		buf[offset++] = hex_asc_upper_lo(cf->flags);
+		if (sep && len)
+			buf[offset++] = '.';
+	}
+
+	for (i = 0; i < len; i++) {
+		put_hex_byte(buf + offset, cf->data[i]);
+		offset += 2;
+		if (sep && (i+1 < len))
+			buf[offset++] = '.';
+	}
+
+	buf[offset] = 0;
+}
+
+void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen) {
+	/* documentation see lib.h */
+
+	char buf[CL_LONGCFSZ];
+
+	sprint_long_canframe(buf, cf, view, maxdlen);
+	fprintf(stream, "%s", buf);
+	if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) {
+		snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
+		fprintf(stream, "\n\t%s", buf);
+	}
+	if (eol)
+		fprintf(stream, "%s", eol);
+}
+
+void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen) {
+	/* documentation see lib.h */
+
+	int i, j, dlen, offset;
+	int len = (cf->len > maxdlen)? maxdlen : cf->len;
+
+	/* initialize space for CAN-ID and length information */
+	memset(buf, ' ', 15);
+
+	if (cf->can_id & CAN_ERR_FLAG) {
+		put_eff_id(buf, cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
+		offset = 10;
+	} else if (cf->can_id & CAN_EFF_FLAG) {
+		put_eff_id(buf, cf->can_id & CAN_EFF_MASK);
+		offset = 10;
+	} else {
+		if (view & CANLIB_VIEW_INDENT_SFF) {
+			put_sff_id(buf + 5, cf->can_id & CAN_SFF_MASK);
+			offset = 10;
+		} else {
+			put_sff_id(buf, cf->can_id & CAN_SFF_MASK);
+			offset = 5;
+		}
+	}
+
+	/* The len value is sanitized by maxdlen (see above) */
+	if (maxdlen == CAN_MAX_DLEN) {
+		buf[offset + 1] = '[';
+		buf[offset + 2] = len + '0';
+		buf[offset + 3] = ']';
+
+		/* standard CAN frames may have RTR enabled */
+		if (cf->can_id & CAN_RTR_FLAG) {
+			sprintf(buf+offset+5, " remote request");
+			return;
+		}
+	} else {
+		buf[offset] = '[';
+		buf[offset + 1] = (len/10) + '0';
+		buf[offset + 2] = (len%10) + '0';
+		buf[offset + 3] = ']';
+	}
+	offset += 5;
+
+	if (view & CANLIB_VIEW_BINARY) {
+		dlen = 9; /* _10101010 */
+		if (view & CANLIB_VIEW_SWAP) {
+			for (i = len - 1; i >= 0; i--) {
+				buf[offset++] = (i == len-1)?' ':SWAP_DELIMITER;
+				for (j = 7; j >= 0; j--)
+					buf[offset++] = (1<<j & cf->data[i])?'1':'0';
+			}
+		} else {
+			for (i = 0; i < len; i++) {
+				buf[offset++] = ' ';
+				for (j = 7; j >= 0; j--)
+					buf[offset++] = (1<<j & cf->data[i])?'1':'0';
+			}
+		}
+	} else {
+		dlen = 3; /* _AA */
+		if (view & CANLIB_VIEW_SWAP) {
+			for (i = len - 1; i >= 0; i--) {
+				if (i == len-1)
+					buf[offset++] = ' ';
+				else
+					buf[offset++] = SWAP_DELIMITER;
+
+				put_hex_byte(buf + offset, cf->data[i]);
+				offset += 2;
+			}
+		} else {
+			for (i = 0; i < len; i++) {
+				buf[offset++] = ' ';
+				put_hex_byte(buf + offset, cf->data[i]);
+				offset += 2;
+			}
+		}
+	}
+
+	buf[offset] = 0; /* terminate string */
+
+	/*
+	 * The ASCII & ERRORFRAME output is put at a fixed len behind the data.
+	 * For now we support ASCII output only for payload length up to 8 bytes.
+	 * Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console?
+	 */
+	if (len > CAN_MAX_DLEN)
+		return;
+
+	if (cf->can_id & CAN_ERR_FLAG)
+		sprintf(buf+offset, "%*s", dlen*(8-len)+13, "ERRORFRAME");
+	else if (view & CANLIB_VIEW_ASCII) {
+		j = dlen*(8-len)+4;
+		if (view & CANLIB_VIEW_SWAP) {
+			sprintf(buf+offset, "%*s", j, "`");
+			offset += j;
+			for (i = len - 1; i >= 0; i--)
+				if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
+					buf[offset++] = cf->data[i];
+				else
+					buf[offset++] = '.';
+
+			sprintf(buf+offset, "`");
+		} else {
+			sprintf(buf+offset, "%*s", j, "'");
+			offset += j;
+			for (i = 0; i < len; i++)
+				if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
+					buf[offset++] = cf->data[i];
+				else
+					buf[offset++] = '.';
+
+			sprintf(buf+offset, "'");
+		}
+	}
+}
+
+static const char *error_classes[] = {
+	"tx-timeout",
+	"lost-arbitration",
+	"controller-problem",
+	"protocol-violation",
+	"transceiver-status",
+	"no-acknowledgement-on-tx",
+	"bus-off",
+	"bus-error",
+	"restarted-after-bus-off",
+};
+
+static const char *controller_problems[] = {
+	"rx-overflow",
+	"tx-overflow",
+	"rx-error-warning",
+	"tx-error-warning",
+	"rx-error-passive",
+	"tx-error-passive",
+	"back-to-error-active",
+};
+
+static const char *protocol_violation_types[] = {
+	"single-bit-error",
+	"frame-format-error",
+	"bit-stuffing-error",
+	"tx-dominant-bit-error",
+	"tx-recessive-bit-error",
+	"bus-overload",
+	"active-error",
+	"error-on-tx",
+};
+
+static const char *protocol_violation_locations[] = {
+	"unspecified",
+	"unspecified",
+	"id.28-to-id.21",
+	"start-of-frame",
+	"bit-srtr",
+	"bit-ide",
+	"id.20-to-id.18",
+	"id.17-to-id.13",
+	"crc-sequence",
+	"reserved-bit-0",
+	"data-field",
+	"data-length-code",
+	"bit-rtr",
+	"reserved-bit-1",
+	"id.4-to-id.0",
+	"id.12-to-id.5",
+	"unspecified",
+	"active-error-flag",
+	"intermission",
+	"tolerate-dominant-bits",
+	"unspecified",
+	"unspecified",
+	"passive-error-flag",
+	"error-delimiter",
+	"crc-delimiter",
+	"acknowledge-slot",
+	"end-of-frame",
+	"acknowledge-delimiter",
+	"overload-flag",
+	"unspecified",
+	"unspecified",
+	"unspecified",
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+static int snprintf_error_data(char *buf, size_t len, uint8_t err,
+			       const char **arr, int arr_len)
+{
+	int i, n = 0, count = 0;
+
+	if (!err || len <= 0)
+		return 0;
+
+	for (i = 0; i < arr_len; i++) {
+		if (err & (1 << i)) {
+			if (count)
+				n += snprintf(buf + n, len - n, ",");
+			n += snprintf(buf + n, len - n, "%s", arr[i]);
+			count++;
+		}
+	}
+
+	return n;
+}
+
+static int snprintf_error_lostarb(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	if (len <= 0)
+		return 0;
+	return snprintf(buf, len, "{at bit %d}", cf->data[0]);
+}
+
+static int snprintf_error_ctrl(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	int n = 0;
+
+	if (len <= 0)
+		return 0;
+
+	n += snprintf(buf + n, len - n, "{");
+	n += snprintf_error_data(buf + n, len - n, cf->data[1],
+				controller_problems,
+				ARRAY_SIZE(controller_problems));
+	n += snprintf(buf + n, len - n, "}");
+
+	return n;
+}
+
+static int snprintf_error_prot(char *buf, size_t len, const struct canfd_frame *cf)
+{
+	int n = 0;
+
+	if (len <= 0)
+		return 0;
+
+	n += snprintf(buf + n, len - n, "{{");
+	n += snprintf_error_data(buf + n, len - n, cf->data[2],
+				protocol_violation_types,
+				ARRAY_SIZE(protocol_violation_types));
+	n += snprintf(buf + n, len - n, "}{");
+	if (cf->data[3] > 0 &&
+	    cf->data[3] < ARRAY_SIZE(protocol_violation_locations))
+		n += snprintf(buf + n, len - n, "%s",
+			      protocol_violation_locations[cf->data[3]]);
+	n += snprintf(buf + n, len - n, "}}");
+
+	return n;
+}
+
+void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
+                  const char* sep)
+{
+	canid_t class, mask;
+	int i, n = 0, classes = 0;
+	char *defsep = ",";
+
+	if (!(cf->can_id & CAN_ERR_FLAG))
+		return;
+
+	class = cf->can_id & CAN_EFF_MASK;
+	if (class > (1 << ARRAY_SIZE(error_classes))) {
+		fprintf(stderr, "Error class %#x is invalid\n", class);
+		return;
+	}
+
+	if (!sep)
+		sep = defsep;
+
+	for (i = 0; i < (int)ARRAY_SIZE(error_classes); i++) {
+		mask = 1 << i;
+		if (class & mask) {
+			if (classes)
+				n += snprintf(buf + n, len - n, "%s", sep);
+ 			n += snprintf(buf + n, len - n, "%s", error_classes[i]);
+			if (mask == CAN_ERR_LOSTARB)
+				n += snprintf_error_lostarb(buf + n, len - n,
+							   cf);
+			if (mask == CAN_ERR_CRTL)
+				n += snprintf_error_ctrl(buf + n, len - n, cf);
+			if (mask == CAN_ERR_PROT)
+				n += snprintf_error_prot(buf + n, len - n, cf);
+			classes++;
+		}
+	}
+
+	if (cf->data[6] || cf->data[7]) {
+		n += snprintf(buf + n, len - n, "%s", sep);
+		n += snprintf(buf + n, len - n, "error-counter-tx-rx{{%d}{%d}}",
+			      cf->data[6], cf->data[7]);
+	}
+}
diff --git a/canutils/libcanutils/lib.h b/canutils/libcanutils/lib.h
new file mode 100644
index 0000000..24fd41e
--- /dev/null
+++ b/canutils/libcanutils/lib.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * lib.h - library include for command line tools
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <li...@vger.kernel.org>
+ *
+ */
+
+#ifndef CAN_UTILS_LIB_H
+#define CAN_UTILS_LIB_H
+
+#include <stdio.h>
+
+/* Compatibility for NuttX */
+typedef uint8_t __u8; 
+typedef uint32_t __u32; 
+
+/* buffer sizes for CAN frame string representations */
+
+#define CL_ID (sizeof("12345678##1"))
+#define CL_DATA sizeof(".AA")
+#define CL_BINDATA sizeof(".10101010")
+
+ /* CAN FD ASCII hex short representation with DATA_SEPERATORs */
+#define CL_CFSZ (2*CL_ID + 64*CL_DATA)
+
+/* CAN FD ASCII hex long representation with binary output */
+#define CL_LONGCFSZ (2*CL_ID + sizeof("   [255]  ") + (64*CL_BINDATA))
+
+/* CAN DLC to real data length conversion helpers especially for CAN FD */
+
+/* get data length from can_dlc with sanitized can_dlc */
+unsigned char can_dlc2len(unsigned char can_dlc);
+
+/* map the sanitized data length to an appropriate data length code */
+unsigned char can_len2dlc(unsigned char len);
+
+unsigned char asc2nibble(char c);
+/*
+ * Returns the decimal value of a given ASCII hex character.
+ *
+ * While 0..9, a..f, A..F are valid ASCII hex characters.
+ * On invalid characters the value 16 is returned for error handling.
+ */
+
+int hexstring2data(char *arg, unsigned char *data, int maxdlen);
+/*
+ * Converts a given ASCII hex string to a (binary) byte string.
+ *
+ * A valid ASCII hex string consists of an even number of up to 16 chars.
+ * Leading zeros '00' in the ASCII hex string are interpreted.
+ *
+ * Examples:
+ *
+ * "1234"   => data[0] = 0x12, data[1] = 0x34
+ * "001234" => data[0] = 0x00, data[1] = 0x12, data[2] = 0x34
+ *
+ * Return values:
+ * 0 = success
+ * 1 = error (in length or the given characters are no ASCII hex characters)
+ *
+ * Remark: The not written data[] elements are initialized with zero.
+ *
+ */
+
+int parse_canframe(char *cs, struct canfd_frame *cf);
+/*
+ * Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
+ *
+ * CAN 2.0 frames
+ * - string layout <can_id>#{R{len}|data}
+ * - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
+ * - {len} can take values from 0 to 8 and can be omitted if zero
+ * - return value on successful parsing: CAN_MTU
+ *
+ * CAN FD frames
+ * - string layout <can_id>##<flags>{data}
+ * - <flags> a single ASCII Hex value (0 .. F) which defines canfd_frame.flags
+ * - {data} has 0 to 64 hex-values that can (optionally) be separated by '.'
+ * - return value on successful parsing: CANFD_MTU
+ *
+ * Return value on detected problems: 0
+ *
+ * <can_id> can have 3 (standard frame format) or 8 (extended frame format)
+ * hexadecimal chars
+ *
+ *
+ * Examples:
+ *
+ * 123# -> standard CAN-Id = 0x123, len = 0
+ * 12345678# -> extended CAN-Id = 0x12345678, len = 0
+ * 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
+ * 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
+ * 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
+ * 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
+ *
+ * 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
+ * 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
+ * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
+ * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
+ * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ *
+ * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
+ * 123##1112233 -> CAN FD frame, flags = CANFD_BRS, len = 3
+ * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
+ * 123##3 -> CAN FD frame, flags = (CANFD_ESI | CANFD_BRS), len = 0
+ *     ^^
+ *     CAN FD extension to handle the canfd_frame.flags content
+ *
+ * Simple facts on this compact ASCII CAN frame representation:
+ *
+ * - 3 digits: standard frame format
+ * - 8 digits: extendend frame format OR error frame
+ * - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
+ * - an error frame is never a RTR frame
+ * - CAN FD frames do not have a RTR bit
+ */
+
+void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen);
+void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
+/*
+ * Creates a CAN frame hexadecimal output in compact format.
+ * The CAN data[] is separated by '.' when sep != 0.
+ *
+ * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
+ * maxdlen = 8 -> CAN2.0 frame
+ * maxdlen = 64 -> CAN FD frame
+ *
+ * 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0
+ * 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
+ * 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
+ * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
+ * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
+ * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
+ *
+ * Examples:
+ *
+ * fprint_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT
+ * fprint_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
+ *
+ */
+
+#define CANLIB_VIEW_ASCII	0x1
+#define CANLIB_VIEW_BINARY	0x2
+#define CANLIB_VIEW_SWAP	0x4
+#define CANLIB_VIEW_ERROR	0x8
+#define CANLIB_VIEW_INDENT_SFF	0x10
+
+#define SWAP_DELIMITER '`'
+
+void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen);
+void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen);
+/*
+ * Creates a CAN frame hexadecimal output in user readable format.
+ *
+ * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
+ * maxdlen = 8 -> CAN2.0 frame
+ * maxdlen = 64 -> CAN FD frame
+ *
+ * 12345678   [3]  11 22 33 -> extended CAN-Id = 0x12345678, dlc = 3, data
+ * 12345678   [0]  remote request -> extended CAN-Id = 0x12345678, RTR
+ * 14B0DC51   [8]  4A 94 E8 2A EC 58 55 62   'J..*.XUb' -> (with ASCII output)
+ * 20001111   [7]  C6 23 7B 32 69 98 3C      ERRORFRAME -> (CAN_ERR_FLAG set)
+ * 12345678  [03]  11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, dlc = 3
+ *
+ * 123   [3]  11 22 33         -> CANLIB_VIEW_INDENT_SFF == 0
+ *      123   [3]  11 22 33    -> CANLIB_VIEW_INDENT_SFF == set
+ *
+ * Examples:
+ *
+ * // CAN FD frame with eol to STDOUT
+ * fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
+ *
+ * // CAN 2.0 frame without eol to STDERR
+ * fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN);
+ *
+ */
+
+void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf,
+                  const char *sep);
+/*
+ * Creates a CAN error frame output in user readable format.
+ */
+
+#endif
diff --git a/canutils/libcanutils/terminal.h b/canutils/libcanutils/terminal.h
new file mode 100644
index 0000000..198b48e
--- /dev/null
+++ b/canutils/libcanutils/terminal.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <li...@vger.kernel.org>
+ *
+ */
+
+#ifndef TERMINAL_H
+#define TERMINAL_H
+
+/* reset to default */
+
+#define ATTRESET "\33[0m"
+
+/* attributes */
+
+#define ATTBOLD      "\33[1m"
+#define ATTUNDERLINE "\33[4m"
+#define ATTBLINK     "\33[5m"
+#define ATTINVERSE   "\33[7m"
+#define ATTINVISIBLE "\33[8m"
+
+/* foreground colors */
+
+#define FGBLACK   "\33[30m"
+#define FGRED     "\33[31m"
+#define FGGREEN   "\33[32m"
+#define FGYELLOW  "\33[33m"
+#define FGBLUE    "\33[34m"
+#define FGMAGENTA "\33[35m"
+#define FGCYAN    "\33[36m"
+#define FGWHITE   "\33[37m"
+
+/* background colors */
+
+#define BGBLACK   "\33[40m"
+#define BGRED     "\33[41m"
+#define BGGREEN   "\33[42m"
+#define BGYELLOW  "\33[43m"
+#define BGBLUE    "\33[44m"
+#define BGMAGENTA "\33[45m"
+#define BGCYAN    "\33[46m"
+#define BGWHITE   "\33[47m"
+
+/* cursor */
+
+#define CSR_HOME  "\33[H"
+#define CSR_UP    "\33[A"
+#define CSR_DOWN  "\33[B"
+#define CSR_RIGHT "\33[C"
+#define CSR_LEFT  "\33[D"
+
+#define CSR_HIDE  "\33[?25l"
+#define CSR_SHOW  "\33[?25h"
+
+/* clear screen */
+
+#define CLR_SCREEN  "\33[2J"
+
+#endif /* TERMINAL_H */