All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Wahren <stefan.wahren@i2se.com>
To: yegorslists@googlemail.com
Cc: linux-can@vger.kernel.org, socketcan@hartkopp.net, mkl@pengutronix.de
Subject: Re: [PATCH v3] slcand: add slcan_attach and UART settings
Date: Fri, 13 Sep 2013 13:29:55 +0200	[thread overview]
Message-ID: <5232F733.2040707@i2se.com> (raw)
In-Reply-To: <1379067102-27741-1-git-send-email-yegorslists@googlemail.com>

Hello Yegor,

Am 13.09.2013 12:11, schrieb yegorslists@googlemail.com:
> From: Yegor Yefremov <yegorslists@googlemail.com>
>
> slcand takes settings known from slcan_attach to configure CAN
> interface, like open/close channel, set bitrate etc (Oliver Hartkopp).
>
> In addition -S option sets UART's baudrate (Yegor Yefremov).
>
> This way slcand combines three autilities in one: old slcand,
> slcan_attach and stty.
>
> Example: slcand -o -s8 -S 3000000 ttyUSB0
>
> Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
> CC: stefan.wahren@i2se.com
> CC: socketcan@hartkopp.net
> CC: mkl@pengutronix.de
> ---
> Changes since v2:
>    More style fixes as suggested by Stefan Wahren
> Changes since v1:
>    Implement suggestions from Stefan Wahren
>    - fix style issues
>    - changed look_up_uart_speed parameter from int to long int
>    - look_up_uart_speed return value will be checked for unsupported baudrates
>   slcand.c |  297 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
>   1 files changed, 255 insertions(+), 42 deletions(-)
>
> diff --git a/slcand.c b/slcand.c
> index 807ffaa..7708d9f 100644
> --- a/slcand.c
> +++ b/slcand.c
> @@ -40,16 +40,16 @@
>   #include <stdlib.h>
>   #include <string.h>
>   #include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
>   #include <fcntl.h>
>   #include <syslog.h>
>   #include <errno.h>
>   #include <pwd.h>
>   #include <signal.h>
> -#include <sys/socket.h>
>   #include <sys/ioctl.h>
> -#include <sys/types.h>
> -#include <sys/stat.h>
>   #include <net/if.h>
> +#include <termios.h>
>   
>   /* default slcan line discipline since Kernel 2.6.25 */
>   #define LDISC_N_SLCAN 17
> @@ -71,44 +71,119 @@
>   
>   void print_usage(char *prg)
>   {
> -	fprintf(stderr, "\nUsage: %s tty [name]\n\n", prg);
> -	fprintf(stderr, "Example:\n");
> -	fprintf(stderr, "%s ttyUSB1\n", prg);
> -	fprintf(stderr, "%s ttyS0 can0\n", prg);
> +	fprintf(stderr, "\nUsage: %s [options] <tty> [canif-name]\n\n", prg);
> +	fprintf(stderr, "Options: -o         (send open command 'O\\r')\n");
> +	fprintf(stderr, "         -c         (send close command 'C\\r')\n");
> +	fprintf(stderr, "         -f         (read status flags with 'F\\r' to reset error states)\n");
> +	fprintf(stderr, "         -s <speed> (set CAN speed 0..8)\n");
> +	fprintf(stderr, "         -S <speed> (set UART speed in baud)\n");
> +	fprintf(stderr, "         -b <btr>   (set bit time register value)\n");
> +	fprintf(stderr, "         -F         (stay in foreground; no daemonize)\n");
> +	fprintf(stderr, "         -h         (show this help page)\n");
> +	fprintf(stderr, "\nExamples:\n");
> +	fprintf(stderr, "slcand -o -c -f -s6 ttyslcan0\n");
> +	fprintf(stderr, "slcand -o -c -f -s6 ttyslcan0 can0\n");
>   	fprintf(stderr, "\n");
>   	exit(EXIT_FAILURE);
>   }
>   
> +static int slcand_running = 0;
> +static int exit_code = 0;
> +static char ttypath[TTYPATH_LENGTH];
> +static char pidfile[PIDFILE_LENGTH];
> +
>   static void child_handler (int signum)
>   {
> -	switch (signum)
> -	{
> -	case SIGALRM:
> -		exit (EXIT_FAILURE);
> -		break;
> +	switch (signum) {
>   	case SIGUSR1:
> -		exit (EXIT_SUCCESS);
> +		/* exit parent */
> +		exit(EXIT_SUCCESS);
>   		break;
> +	case SIGALRM:
>   	case SIGCHLD:
> -		exit (EXIT_FAILURE);
> +		syslog (LOG_NOTICE, "received signal %i on %s", signum, ttypath);
> +		exit_code = EXIT_FAILURE;
> +		slcand_running = 0;
>   		break;
> +	case SIGINT:
> +	case SIGTERM:
> +		syslog (LOG_NOTICE, "received signal %i on %s", signum, ttypath);
> +		exit_code = EXIT_SUCCESS;
> +		slcand_running = 0;
> +		break;
> +	}
> +}
> +
> +static int look_up_uart_speed(long int s)
> +{
> +	switch (s) {
> +	case 9600:
> +		return B9600;
> +	case 19200:
> +		return B19200;
> +	case 38400:
> +		return B38400;
> +	case 57600:
> +		return B57600;
> +	case 115200:
> +		return B115200;
> +	case 230400:
> +		return B230400;
> +	case 460800:
> +		return B460800;
> +	case 500000:
> +		return B500000;
> +	case 576000:
> +		return B576000;
> +	case 921600:
> +		return B921600;
> +	case 1000000:
> +		return B1000000;
> +	case 1152000:
> +		return B1152000;
> +	case 1500000:
> +		return B1500000;
> +	case 2000000:
> +		return B2000000;
> +#ifdef B2500000
> +	case 2500000:
> +		return B2500000;
> +#endif
> +#ifdef B3000000
> +	case 3000000:
> +		return B3000000;
> +#endif
> +#ifdef B3500000
> +	case 3500000:
> +		return B3500000;
> +#endif
> +#ifdef B3710000
> +	case 3710000
> +		return B3710000;
> +#endif
> +#ifdef B4000000
> +	case 4000000:
> +		return B4000000;
> +#endif
> +	default:
> +		return -1;
>   	}
>   }
>   
> -static void daemonize (const char *lockfile, char *tty)
> +static pid_t daemonize (const char *lockfile, char *tty, char *name)
>   {
>   	pid_t pid, sid, parent;
>   	int lfp = -1;
>   	FILE * pFile;
> +	FILE * dummyFile;
>   	char const *pidprefix = "/var/run/";
>   	char const *pidsuffix = ".pid";
> -	char pidfile[PIDFILE_LENGTH];
>   
>   	snprintf(pidfile, PIDFILE_LENGTH, "%s%s-%s%s", pidprefix, DAEMON_NAME, tty, pidsuffix);
>   
>   	/* already a daemon */
>   	if (getppid () == 1)
> -		return;
> +		return 0;
>   
>   	/* Create the lock file as the current user */
>   	if (lockfile && lockfile[0])
> @@ -134,6 +209,8 @@ static void daemonize (const char *lockfile, char *tty)
>   	}
>   
>   	/* Trap signals that we expect to receive */
> +	signal (SIGINT, child_handler);
> +	signal (SIGTERM, child_handler);
>   	signal (SIGCHLD, child_handler);
>   	signal (SIGUSR1, child_handler);
>   	signal (SIGALRM, child_handler);
> @@ -151,10 +228,9 @@ static void daemonize (const char *lockfile, char *tty)
>   	{
>   
>   		/* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
> -		   for two seconds to elapse (SIGALRM).  pause() should not return. */
> -		alarm (2);
> +		   for five seconds to elapse (SIGALRM).  pause() should not return. */
> +		alarm (5);
>   		pause ();
> -
>   		exit (EXIT_FAILURE);
>   	}
>   
> @@ -167,7 +243,8 @@ static void daemonize (const char *lockfile, char *tty)
>   	signal (SIGTTOU, SIG_IGN);
>   	signal (SIGTTIN, SIG_IGN);
>   	signal (SIGHUP, SIG_IGN);	/* Ignore hangup signal */
> -	signal (SIGTERM, SIG_DFL);	/* Die on SIGTERM */
> +	signal (SIGINT, child_handler);
> +	signal (SIGTERM, child_handler);
>   
>   	/* Change the file mode mask */
>   	umask (0);
> @@ -182,7 +259,7 @@ static void daemonize (const char *lockfile, char *tty)
>   	}
>   
>   	pFile = fopen (pidfile,"w");
> -	if (pFile == NULL)
> +	if (NULL == pFile)
>   	{
>   		syslog (LOG_ERR, "unable to create pid file %s, code=%d (%s)",
>   			pidfile, errno, strerror (errno));
> @@ -201,36 +278,90 @@ static void daemonize (const char *lockfile, char *tty)
>   	}
>   
>   	/* Redirect standard files to /dev/null */
> -	freopen ("/dev/null", "r", stdin);
> -	freopen ("/dev/null", "w", stdout);
> -	freopen ("/dev/null", "w", stderr);
> +	dummyFile = freopen ("/dev/null", "r", stdin);
> +	dummyFile = freopen ("/dev/null", "w", stdout);
> +	dummyFile = freopen ("/dev/null", "w", stderr);
>   
>   	/* Tell the parent process that we are A-okay */
> -	kill (parent, SIGUSR1);
> +	//kill (parent, SIGUSR1);
> +	return parent;
>   }
>   
>   int main (int argc, char *argv[])
>   {
>   	char *tty = NULL;
> -	char ttypath[TTYPATH_LENGTH];
>   	char const *devprefix = "/dev/";
>   	char *name = NULL;
>   	char buf[IFNAMSIZ+1];
> +	struct termios tios;
> +	speed_t old_ispeed;
> +	speed_t old_ospeed;
> +
> +	int opt;
> +	int send_open = 0;
> +	int send_close = 0;
> +	int send_read_status_flags = 0;
> +	char *speed = NULL;
> +	char *uart_speed_str = NULL;
> +	long int uart_speed = 0;
> +	char *btr = NULL;
> +	int run_as_daemon = 1;
> +	pid_t parent_pid = 0;
> +
> +	ttypath[0] = '\0';
> +
> +	while ((opt = getopt(argc, argv, "ocfs:S:b:?hF")) != -1) {
> +		switch (opt) {
> +		case 'o':
> +			send_open = 1;
> +			break;
> +		case 'c':
> +			send_close = 1;
> +			break;
> +		case 'f':
> +			send_read_status_flags = 1;
> +			break;
> +		case 's':
> +			speed = optarg;
> +			if (strlen(speed) > 1)
> +				print_usage(argv[0]);
> +			break;
> +		case 'S':
> +			uart_speed_str = optarg;
> +			errno = 0;
> +			uart_speed = strtol(uart_speed_str, NULL, 10);
> +			if (errno)
> +				print_usage(argv[0]);
> +			if (look_up_uart_speed(uart_speed) == -1) {
> +				fprintf(stderr, "Unsupported UART speed (%lu)\n", uart_speed);
> +				exit(EXIT_FAILURE);
> +			}
> +			break;
> +		case 'b':
> +			btr = optarg;
> +			if (strlen(btr) > 6)
> +				print_usage(argv[0]);
> +			break;
> +		case 'F':
> +			run_as_daemon = 0;
> +			break;
> +		case 'h':
> +		case '?':
> +		default:
> +			print_usage(argv[0]);
> +			break;
> +		}
> +	}
>   
>   	/* Initialize the logging interface */
>   	openlog (DAEMON_NAME, LOG_PID, LOG_LOCAL5);
>   
> -	/* See how we're called */
> -	if (argc == 2) {
> -		tty = argv[1];
> -	} else if (argc == 3) {
> -		tty = argv[1];
> -		name = argv[2];
> -		if (strlen(name) > IFNAMSIZ-1)
> -			print_usage(argv[0]);
> -	} else {
> +	/* Parse serial device name and optional can interface name */
> +	tty = argv[optind];
> +	if(NULL == tty) {
>   		print_usage(argv[0]);
>   	}
> +	name = argv[optind + 1];
>   
>   	/* Prepare the tty device name string */
>   	char * pch;
> @@ -243,16 +374,68 @@ int main (int argc, char *argv[])
>   	syslog (LOG_INFO, "starting on TTY device %s", ttypath);
>   
>   	/* Daemonize */
> -	daemonize ("/var/lock/" DAEMON_NAME, tty);
> +	if(run_as_daemon) {
> +		parent_pid = daemonize ("/var/lock/" DAEMON_NAME, tty, name);
> +	}
> +	else {
> +		/* Trap signals that we expect to receive */
> +		signal (SIGINT, child_handler);
> +		signal (SIGTERM, child_handler);
> +	}
> +
> +	/* */
> +	slcand_running = 1;
>   
>   	/* Now we are a daemon -- do the work for which we were paid */
>   	int fd;
>   	int ldisc = LDISC_N_SLCAN;
>   
> -	if ((fd = open (ttypath, O_WRONLY | O_NOCTTY )) < 0) {
> +	if ((fd = open (ttypath, O_RDWR | O_NONBLOCK | O_NOCTTY )) < 0) {
>   	    syslog (LOG_NOTICE, "failed to open TTY device %s\n", ttypath);
>   		perror(ttypath);
> -		exit(1);
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Configure baud rate */
> +	memset(&tios, 0, sizeof(struct termios));
> +	if(tcgetattr(fd, &tios) < 0) {
> +		syslog (LOG_NOTICE, "failed to get attributes for TTY device %s: %s\n", ttypath, strerror(errno));
> +		exit (EXIT_FAILURE);
> +	}
> +
> +	/* Get old values for later restore */
> +	old_ispeed = cfgetispeed(&tios);
> +	old_ospeed = cfgetospeed(&tios);
> +
> +	/* Baud Rate */
> +	cfsetispeed(&tios, look_up_uart_speed(uart_speed));
> +	cfsetospeed(&tios, look_up_uart_speed(uart_speed));
> +
> +	/* apply changes */
> +	if(tcsetattr(fd, TCSADRAIN, &tios) < 0) {
> +		syslog(LOG_NOTICE, "Cannot set attributes for device \"%s\": %s!\n", ttypath, strerror(errno));
> +	}
> +
> +	if (speed) {
> +		sprintf(buf, "C\rS%s\r", speed);
> +		if(write(fd, buf, strlen(buf)) < 0) {
> +			//syslog (LO, "failed to get attributes for TTY device %s: %s\n", ttypath, strerror(errno));
> +		}
> +	}
> +
> +	if (btr) {
> +		sprintf(buf, "C\rs%s\r", btr);
> +		write(fd, buf, strlen(buf));
> +	}
> +
> +	if (send_read_status_flags) {
> +		sprintf(buf, "F\r");
> +		write(fd, buf, strlen(buf));
> +	}
> +
> +	if (send_open) {
> +		sprintf(buf, "O\r");
> +		write(fd, buf, strlen(buf));
>   	}
>   
>   	/* set slcan like discipline on given tty */
> @@ -289,14 +472,44 @@ int main (int argc, char *argv[])
>   			close(s);
>   		}	
>   	}
> +	if(parent_pid > 0) {
> +		kill(parent_pid, SIGUSR1);
> +	}
>   
>   	/* The Big Loop */
> -	while (1) {
> -		sleep(60); /* wait 60 seconds */
> +	while (slcand_running) {
> +		sleep(1); /* wait 1 second */
> +	}
> +
> +	/* Reset line discipline */
> +	syslog (LOG_INFO, "stopping on TTY device %s", ttypath);
> +	ldisc = N_TTY;
> +	if (ioctl (fd, TIOCSETD, &ldisc) < 0) {
> +		perror("ioctl TIOCSETD");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	if (send_close) {
> +		sprintf(buf, "C\r");
> +		write(fd, buf, strlen(buf));
> +	}
> +
> +	/* Reset old rates */
> +	cfsetispeed(&tios, old_ispeed);
> +	cfsetospeed(&tios, old_ospeed);
> +
> +	/* apply changes */
> +	if(tcsetattr(fd, TCSADRAIN, &tios) < 0) {
> +		syslog(LOG_NOTICE, "Cannot set attributes for device \"%s\": %s!\n", ttypath, strerror(errno));
> +	}
> +
> +	/* Remove pidfile */
> +	if(run_as_daemon) {
> +		unlink(pidfile);
>   	}
>   
>   	/* Finish up */
>   	syslog (LOG_NOTICE, "terminated on %s", ttypath);
>   	closelog ();
> -	return 0;
> +	return exit_code;
>   }

okay, looks good to me.

Best regards

Stefan


  reply	other threads:[~2013-09-13 11:29 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-09-13 10:11 [PATCH v3] slcand: add slcan_attach and UART settings yegorslists
2013-09-13 11:29 ` Stefan Wahren [this message]
2013-09-15 20:11   ` Oliver Hartkopp
2013-09-16  7:14     ` Oliver Hartkopp
2013-09-17  7:22       ` Stefan Wahren
2013-09-17 12:08         ` Yegor Yefremov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5232F733.2040707@i2se.com \
    --to=stefan.wahren@i2se.com \
    --cc=linux-can@vger.kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=socketcan@hartkopp.net \
    --cc=yegorslists@googlemail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.