CSC231 Arduino-serial.c

From dftwiki3
Revision as of 19:32, 8 October 2010 by Thiebaut (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

/*
 * 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
 *
 * Modified 11/06/08 by D. Thiebaut
 *  Force program to wait until a \n is received from Arduino
 *  Added linking with assembly program
 */

#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>

//extern int asm_main( void );

//-------------------------- prototypes ---------------------------
void usage(void);
int serialport_init(const char* serialport, int baud);
int serialport_writebyte( );
int serialport_write( );
int serialport_read_until( );
int displayBuffer( );

//---------------------------- globals ----------------------------
int  fd = 0;             // file descriptor for USB device
char serialport[256];    // name of the serial port (/dev/ttyUSB0)
int  baudrate = B9600;   // default baud rate
char buf[1024];          // buffer for sent/receive strings
uint8_t byte;
int  pin;

//-----------------------------------------------------------------
//-----------------------------------------------------------------
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 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'}
    };
    
    /*--- process the command line arguments ---*/
    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){
	      printf( "Could not initialize USB port\n\n" );
	      return -1;
	    }
            break;
        case 'n':
            n = strtol(optarg, NULL, 10 ); // convert string to number
	    byte = (uint8_t) n;
            rc = serialport_writebyte( );
            if(rc==-1) return -1;
            break;
        case 's':
            strcpy( buf, optarg );
            rc = serialport_write( );
            if (rc==-1) return -1;
            break;
        case 'r':
	    serialport_read_until( );
            printf("%s\n",buf);
            break;
        }
    }

    //--- call assembly language program ---
    //asm_main();

    //--- exit ---
    exit(EXIT_SUCCESS);    

} // end main
    
//-----------------------------------------------------------------
//-----------------------------------------------------------------
int displayBuffer( ) {
  printf( "buffer = [%s]\n", buf );
  return 0;
}

//-----------------------------------------------------------------
//-----------------------------------------------------------------
int serialport_writebyte( ) {
    int n = write( fd, &byte, 1);
    if( n!=1)
        return -1;
    return 0;
}

//-----------------------------------------------------------------
//-----------------------------------------------------------------
int serialport_write() {
  int len;
  strcat( buf, "\n" );
  len = strlen(buf);
  int n = write( fd, buf, len );

  if( n!=len ) 
    return -1;
  return 0;
}

//-----------------------------------------------------------------
//-----------------------------------------------------------------
int serialport_read_until( ) {
    char b[1];
    int i=0, k;
    do { 
        int n = read(fd, b, 1);  // read a char at a time
        if( n==-1) {
	  usleep( 100*1000 );
	  continue;
	}
        if( n==0 ) {
            usleep( 10 * 1000 ); // wait 10 msec try again
            continue;
        }
	buf[i] = b[0];
	i++;
    } while( b[0] != '\n' );

    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;
}