view src/lwwire-serial.c @ 14:e4d98cbf95eb

packet: add get value semantics
author Brett Gordon
date Tue, 13 Dec 2016 11:26:37 -0500
parents cfc9524cca2c
children
line wrap: on
line source

/*
Set up a serial port and launch a lwwire process to handle it. The lwwire
process will be called with "exec".

Usage:

lwwire-serial <port> [speed] [lwwire binary args...]

<port> is the device name for the serial port. [speed] is the optional speed
to set the port to with a default of 115200. [lwwire binary] is the optional
name for the lwwire binary. Default is "./lwwire". If [lwwire binary] is
specified, then [speed] must also be specified.

*/

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	char *lwwire = "lwwire";
	int speed = 115200;
	char *port;
	int i, rargc;
	char **rargv;
	int fd;
	struct termios io_mod;

	if (argc >= 4)
	{
		lwwire = argv[3];
	}
	if (argc >= 3)
	{
		speed = strtol(argv[2], NULL, 10);
	}
	if (argc < 2)
	{
		fprintf(stderr, "Usage: %s <port> [<speed> [<lwwire binary> [args]]]\n", argv[0]);
		exit(0);
	}
	port = argv[1];
	
	fprintf(stderr, "Starting lwwire on port '%s' at speed %d\n", port, speed);
	
	// open serial port
	fd = open(port, O_RDWR | O_NOCTTY);
	if (fd < 0)
	{
		fprintf(stderr, "Error opening port %s: %s\n", port, strerror(errno));
		exit(1);
	}
	// set up parameters
	// this is all theoretically *mostly* posix correct except for some of the 
	// Bxxxx constants.	
	tcgetattr(fd, &io_mod);
	io_mod.c_iflag &= 
		~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
	io_mod.c_oflag &= ~OPOST;
	io_mod.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
	io_mod.c_cflag &= ~(CSIZE|PARENB);
	io_mod.c_cflag |= CS8;
	switch (speed)
	{
	case 38400:
		cfsetispeed(&io_mod, B38400);
		cfsetospeed(&io_mod, B38400);
		break;
	
	case 57600:
		cfsetispeed(&io_mod, B57600);
		cfsetospeed(&io_mod, B57600);
		break;
	
	case 115200:
		cfsetispeed(&io_mod, B115200);
		cfsetospeed(&io_mod, B115200);
		break;

#ifdef B230400	
	case 230400:
		cfsetispeed(&io_mod, B230400);
		cfsetospeed(&io_mod, B230400);
		break;
#endif

#ifdef B460800
	case 460800:
		cfsetispeed(&io_mod, B460800);
		cfsetospeed(&io_mod, B460800);
		break;
#endif

#ifdef B921600
	case 921600:
		cfsetispeed(&io_mod, B921600);
		cfsetospeed(&io_mod, B921600);
		break;
#endif

	default:
		fprintf(stderr, "Unrecognzied speed %d on port %s; using 38400\n", speed, port);
		cfsetispeed(&io_mod, B38400);
		cfsetospeed(&io_mod, B38400);
		break;	
	}

	if (tcsetattr(fd, TCSANOW, &io_mod) < 0)
	{
		fprintf(stderr, "Cannot set serial line mode properly: %s", strerror(errno));
		exit(1);
	}

	// set up stdin/stdout
	if (dup2(fd, 0) < 0)
	{
		fprintf(stderr, "Cannot set up stdin file descriptor: %s\n", strerror(errno));
		exit(1);
	}
	if (dup2(fd, 1) < 0)
	{
		fprintf(stderr, "Cannot set up stdout file descriptor: %s\n", strerror(errno));
		exit(1);
	}
	// close the original FD since we don't need it any more.
	close(fd);

	// execute binary
	rargc = 1;
	if (argc >= 5)
	{
		rargc += argc - 4;
	}
	rargv = malloc(sizeof(char *) * (rargc + 1));
	rargv[0] = lwwire;
	for (i = 4; i < argc; i++)
	{
		fprintf(stderr, "Passing argument %d of %d: %s\n", i - 3, rargc, argv[i]);
		rargv[i - 3] = argv[i];
	}
	rargv[rargc] = NULL;
	
	execv(lwwire, rargv);
	fprintf(stderr, "Failed to execute %s: %s\n", lwwire, strerror(errno));
	exit(1);
}