231a-ag arduino serial

From CSclasswiki
Jump to: navigation, search

arduino_serial.c

*                                                                                 
 * 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>
#include <time.h>

extern int asm_main( void );
extern time_t currentTime;

int* _getLocalTime() {
  return (int*) localtime( &currentTime );
}

//-------------------------- 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[]) {
  srand( time( 0 ) );

  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,);  // read a char at a time                          
      if( n==-1) {
        usleep( 100*1000 );
        continue;
      }
      if( n==0 ) {
        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;
  }