diff options
Diffstat (limited to 'arduino-serial.c')
-rw-r--r-- | arduino-serial.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/arduino-serial.c b/arduino-serial.c new file mode 100644 index 0000000..0646f23 --- /dev/null +++ b/arduino-serial.c @@ -0,0 +1,236 @@ +/* + * Arduino-serial + * -------------- + * + * A simple command-line example program showing how a computer can + * communicate with an Arduino board. Works on any POSIX system (Mac/Unix/PC) + * + * + * Compile with something like: + * gcc -o arduino-serial arduino-serial.c + * + * Created 5 December 2006 + * Copyleft (c) 2006, Tod E. Kurt, tod@todbot.com + * http://todbot.com/blog/ + * + * + * Updated 8 December 2006: + * Justin McBride discoevered B14400 & B28800 aren't in Linux's termios.h. + * I've included his patch, but commented out for now. One really needs a + * real make system when doing cross-platform C and I wanted to avoid that + * for this little program. Those baudrates aren't used much anyway. :) + * + * Updated 26 December 2007: + * Added ability to specify a delay (so you can wait for Arduino Diecimila) + * Added ability to send a binary byte number + * + * Update 31 August 2008: + * Added patch to clean up odd baudrates from Andy at hexapodia.org + * + */ + +#include <stdio.h> /* Standard input/output definitions */ +#include <stdlib.h> +#include <stdint.h> /* Standard types */ +#include <string.h> /* String function definitions */ +#include <unistd.h> /* UNIX standard function definitions */ +#include <fcntl.h> /* File control definitions */ +#include <errno.h> /* Error number definitions */ +#include <termios.h> /* POSIX terminal control definitions */ +#include <sys/ioctl.h> +#include <getopt.h> + +void usage(void); +int serialport_init(const char* serialport, int baud); +int serialport_writebyte(int fd, uint8_t b); +int serialport_write(int fd, const char* str); +int serialport_read_until(int fd, char* buf, char until); + +void usage(void) { + printf("Usage: arduino-serial -p <serialport> [OPTIONS]\n" + "\n" + "Options:\n" + " -h, --help Print this help message\n" + " -p, --port=serialport Serial port Arduino is on\n" + " -b, --baud=baudrate Baudrate (bps) of Arduino\n" + " -s, --send=data Send data to Arduino\n" + " -r, --receive Receive data from Arduino & print it out\n" + " -n --num=num Send a number as a single byte\n" + " -d --delay=millis Delay for specified milliseconds\n" + "\n" + "Note: Order is important. Set '-b' before doing '-p'. \n" + " Used to make series of actions: '-d 2000 -s hello -d 100 -r' \n" + " means 'wait 2secs, send 'hello', wait 100msec, get reply'\n" + "\n"); +} + +int main(int argc, char *argv[]) +{ + int fd = 0; + char serialport[256]; + int baudrate = B9600; // default + char buf[256]; + int rc,n; + + if (argc==1) { + usage(); + exit(EXIT_SUCCESS); + } + + /* parse options */ + int option_index = 0, opt; + static struct option loptions[] = { + {"help", no_argument, 0, 'h'}, + {"port", required_argument, 0, 'p'}, + {"baud", required_argument, 0, 'b'}, + {"send", required_argument, 0, 's'}, + {"receive", no_argument, 0, 'r'}, + {"num", required_argument, 0, 'n'}, + {"delay", required_argument, 0, 'd'}, + {NULL, 0, 0, 0} + }; + + while(1) { + opt = getopt_long (argc, argv, "hp:b:s:rn:d:", + loptions, &option_index); + if (opt==-1) break; + switch (opt) { + case '0': break; + case 'd': + n = strtol(optarg,NULL,10); + usleep(n * 1000 ); // sleep milliseconds + break; + case 'h': + usage(); + break; + case 'b': + baudrate = strtol(optarg,NULL,10); + break; + case 'p': + strcpy(serialport,optarg); + fd = serialport_init(optarg, baudrate); + if(fd==-1) return -1; + break; + case 'n': + n = strtol(optarg, NULL, 10); // convert string to number + rc = serialport_writebyte(fd, (uint8_t)n); + if(rc==-1) return -1; + break; + case 's': + strcpy(buf,optarg); + printf("read string '%s'\n", buf); + rc = serialport_write(fd, buf); + if(rc==-1) return -1; + break; + case 'r': + serialport_read_until(fd, buf, '\n'); + printf("read: %s\n",buf); + break; + } + } + + exit(EXIT_SUCCESS); +} // end main + +int serialport_writebyte( int fd, uint8_t b) +{ + int n = write(fd,&b,1); + if( n!=1) + return -1; + return 0; +} + +int serialport_write(int fd, const char* str) +{ + int len = strlen(str); + int n = write(fd, str, len); + if( n!=len ) { + printf("couldn't write whole string\n"); + return -1; + } + return 0; +} + +int serialport_read_until(int fd, char* buf, char until) +{ + char b[1]; + int i=0; + do { + int n = read(fd, b, 1); // read a char at a time + if( n==-1) return -1; // couldn't read + if( n==0 ) { + usleep( 10 * 1000 ); // wait 10 msec try again + continue; + } + buf[i] = b[0]; i++; + } while( b[0] != until ); + + buf[i] = 0; // null terminate the string + return 0; +} + +// takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1") +// and a baud rate (bps) and connects to that port at that speed and 8N1. +// opens the port in fully raw mode so you can send binary data. +// returns valid fd, or -1 on error +int serialport_init(const char* serialport, int baud) +{ + struct termios toptions; + int fd; + + //fprintf(stderr,"init_serialport: opening port %s @ %d bps\n", + // serialport,baud); + + fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) { + perror("init_serialport: Unable to open port "); + return -1; + } + + if (tcgetattr(fd, &toptions) < 0) { + perror("init_serialport: Couldn't get term attributes"); + return -1; + } + speed_t brate = baud; // let you override switch below if needed + switch(baud) { + case 4800: brate=B4800; break; + case 9600: brate=B9600; break; +#ifdef B14400 + case 14400: brate=B14400; break; +#endif + case 19200: brate=B19200; break; +#ifdef B28800 + case 28800: brate=B28800; break; +#endif + case 38400: brate=B38400; break; + case 57600: brate=B57600; break; + case 115200: brate=B115200; break; + } + cfsetispeed(&toptions, brate); + cfsetospeed(&toptions, brate); + + // 8N1 + toptions.c_cflag &= ~PARENB; + toptions.c_cflag &= ~CSTOPB; + toptions.c_cflag &= ~CSIZE; + toptions.c_cflag |= CS8; + // no flow control + toptions.c_cflag &= ~CRTSCTS; + + toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines + toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl + + toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw + toptions.c_oflag &= ~OPOST; // make raw + + // see: http://unixwiz.net/techtips/termios-vmin-vtime.html + toptions.c_cc[VMIN] = 0; + toptions.c_cc[VTIME] = 20; + + if( tcsetattr(fd, TCSANOW, &toptions) < 0) { + perror("init_serialport: Couldn't set term attributes"); + return -1; + } + + return fd; +} |