From 99a3bba852e1bdbb7d1711e8e32f200aac2d8461 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Mon, 30 Oct 2006 13:14:36 +0000 Subject: [PATCH] Added tiny tool cansend and a library to parse ASCII CAN frames (e.g. from the command line) that are defined in one concatenated string. This is a requirement for the comming command line tool 'bcmsend' that allows to send more than one CAN frame at a time. --- Makefile | 6 ++- cansend.c | 117 +++++++++++++++++++++++++++++++++++++++++ lib.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib.h | 86 ++++++++++++++++++++++++++++++ 4 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 cansend.c create mode 100644 lib.c create mode 100644 lib.h diff --git a/Makefile b/Makefile index f7c5153..558587a 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ CFLAGS = -O2 -Wall -Wno-parentheses -I../kernel/2.6/include \ -fno-strict-aliasing -PROGRAMS = candump can-sniffer +PROGRAMS = candump can-sniffer cansend all: $(PROGRAMS) @@ -52,3 +52,7 @@ clean: distclean: rm -f $(PROGRAMS) *~ + +cansend.o: lib.h + +cansend: cansend.o lib.o \ No newline at end of file diff --git a/cansend.c b/cansend.c new file mode 100644 index 0000000..7b94ff8 --- /dev/null +++ b/cansend.c @@ -0,0 +1,117 @@ +/* + * $Id$ + */ + +/* + * cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets + * + * Copyright (c) 2002-2005 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, the following disclaimer and + * the referenced file 'COPYING'. + * 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 as distributed in the 'COPYING' + * file from the main directory of the linux kernel source. + * + * 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 + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "lib.h" + +int main(int argc, char **argv) +{ + int s; /* can raw socket */ + int nbytes; + struct sockaddr_can addr; + struct can_frame frame; + struct ifreq ifr; + + /* check command line options */ + if (argc != 3) { + fprintf(stderr, "Usage: %s .\n", argv[0]); + return 1; + } + + /* parse CAN frame */ + if (parse_canframe(argv[2], &frame)){ + fprintf(stderr, "\nWrong CAN-frame format!\n\n"); + fprintf(stderr, "Try: #{R|data}\n"); + fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n"); + fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)"); + fprintf(stderr, " be seperated by '.'\n\n"); + fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / "); + fprintf(stderr, "5AA# /\n 1F334455#1122334455667788 / 123#R "); + fprintf(stderr, "for remote transmission request.\n\n"); + return 1; + } + + /* open socket */ + if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + perror("socket"); + return 1; + } + + strcpy(ifr.ifr_name, argv[1]); + ioctl(s, SIOCGIFINDEX, &ifr); + + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + return 1; + } + + /* send frame */ + if ((nbytes = write(s, &frame, sizeof(frame))) != sizeof(frame)) { + perror("write"); + return 1; + } + + //fprint_canframe(stdout, &frame, "\n"); + + close(s); + + return 0; +} diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..0de7e11 --- /dev/null +++ b/lib.c @@ -0,0 +1,154 @@ +/* + * $Id$ + */ + +/* + * cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets + * + * Copyright (c) 2002-2005 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, the following disclaimer and + * the referenced file 'COPYING'. + * 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 as distributed in the 'COPYING' + * file from the main directory of the linux kernel source. + * + * 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 + * + */ + +#include +#include + +#include + +#define CANID_DELIM '#' +#define DATA_SEPERATOR '.' + +static int asc2nibble(char c){ + + if ((c >= '0') && (c <= '9')) + return c - '0'; + + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + + return 16; /* error */ +} + +int parse_canframe(char *cs, struct can_frame *cf){ + /* documentation see lib.h */ + + int i, idx, dlc, len, tmp; + + len = strlen(cs); + //printf("'%s' len %d\n", cs, len); + + memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */ + + if (len < 4) + return 1; + + if (!((cs[3] == CANID_DELIM) || (cs[8] == CANID_DELIM))) + return 1; + + if (cs[8] == CANID_DELIM) { + + idx = 9; + cf->can_id = CAN_EFF_FLAG; + for (i=0; i<8; i++){ + if ((tmp = asc2nibble(cs[i])) > 0x0F) + return 1; + cf->can_id |= (tmp << (7-i)*4); + } + + } else { + + idx = 4; + for (i=0; i<3; i++){ + if ((tmp = asc2nibble(cs[i])) > 0x0F) + return 1; + cf->can_id |= (tmp << (2-i)*4); + } + } + + if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */ + cf->can_id |= CAN_RTR_FLAG; + return 0; + } + + for (i=0, dlc=0; i<8; i++){ + + if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */ + idx++; + + if(idx >= len) /* end of string => end of data */ + break; + + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 1; + cf->data[i] = (tmp << 4); + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 1; + cf->data[i] |= tmp; + dlc++; + } + + cf->can_dlc = dlc; + + return 0; +} + +void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol){ + /* documentation see lib.h */ + + int i; + + if (cf->can_id & CAN_EFF_FLAG) + fprintf(stream, "%8X ", cf->can_id & CAN_EFF_MASK); + else + fprintf(stream, "%3X ", cf->can_id & CAN_SFF_MASK); + + fprintf(stream, "[%d] ", cf->can_dlc); + + for (i = 0; i < cf->can_dlc; i++) { + fprintf(stream, "%02X ", cf->data[i]); + } + if (cf->can_id & CAN_RTR_FLAG) + fprintf(stream, "remote request"); + if (eol) + fprintf(stream, "%s", eol); +} + diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..cf86953 --- /dev/null +++ b/lib.h @@ -0,0 +1,86 @@ +/* + * $Id$ + */ + +/* + * cansend.c - simple command line tool to send CAN-frames via CAN_RAW sockets + * + * Copyright (c) 2002-2005 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, the following disclaimer and + * the referenced file 'COPYING'. + * 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 as distributed in the 'COPYING' + * file from the main directory of the linux kernel source. + * + * 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 + * + */ + +int parse_canframe(char *cs, struct can_frame *cf); +/* + * Transfers a valid ASCII string decribing a CAN frame into struct can_frame. + * + * #{R|data} + * + * can_id can have 3 (standard frame format) or 8 (extended frame format) + * hexadecimal chars + * + * data has 0 to 8 hex-values that can (optionally) be seperated by '.' + * + * Examples: + * + * 123# -> standard CAN-Id = 0x123, dlc = 0 + * 12345678# -> exended CAN-Id = 0x12345678, dlc = 0 + * 123#R -> standard CAN-Id = 0x123, dlc = 0, RTR-frame + * 7A1#r -> standard CAN-Id = 0x7A1, dlc = 0, RTR-frame + * + * 123#00 -> standard CAN-Id = 0x123, dlc = 1, data[0] = 0x00 + * 123#1122334455667788 -> standard CAN-Id = 0x123, dlc = 8 + * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8 + * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, dlc = 8 + * + */ + +void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol); +/* + * Creates a CAN frame hexadecimal output in user readable format. + * + * 12345678 [3] 11 22 33 -> exended CAN-Id = 0x12345678, dlc = 3, data + * 12345678 [0] remote request -> exended CAN-Id = 0x12345678, RTR + * + * Examples: + * + * fprint_canframe(stdout, &frame, "\n"); // with eol to STDOUT + * fprint_canframe(stderr, &frame, NULL); // no eol to STDERR + * + */