/* 2009/11/10 Modified by Mark Sadgrove for simplicity of use with dc / sequencer control project * Original comment header directly below. */ /* * 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 dcset dcset.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 /* Standard input/output definitions */ #include #include /* Standard types */ #include /* String function definitions */ #include /* UNIX standard function definitions */ #include /* File control definitions */ #include /* Error number definitions */ #include /* POSIX terminal control definitions */ #include #include void usage(void); int serialport_init(const char* serialport, int baud); int serialport_writebyte(int fd, uint8_t b); int serialport_writelong(int fd, uint32_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: dcset -p [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" " -o, --opcode Choose d for digital, a for analog,\n" " e to add events, f to finish adding events\n" " p to print out a list of all events to serial port\n" " c clear all events from the current experiment\n" " -n, --pin Pin number from 1-18 for digital, 1-14 for analog\n" " -v, --value 0 or 1 for digital, 0-255 for analog\n" " -t, --time Integer time in units of the intterupt period\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]; char alert[1]; int rc,n; char opcode[256]; int pin; int val; uint32_t etime; 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'}, {"opcode", required_argument, 0, 'o'}, {"pin", required_argument, 0, 'n'}, {"value", required_argument, 0, 'v'}, {"time", required_argument, 0, 't'} //{"receive", no_argument, 0, 'r'}, //{"num", required_argument, 0, 'n'}, //{"delay", required_argument, 0, 'd'} }; alert[1] = 1; while(1) { opt = getopt_long (argc, argv, "hp:b:o:n:v:t:", 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); usleep(500*1000); if(fd==-1) return -1; break; case 'o': strcpy(buf,optarg); // The following line is a kind of kludge. // The arduino always seems to read the first string argument and then miss the // following integers the first time you send a command. However, it gets it // right the second time. The following line trips the serial.read function of // the arduino so that the next time it does the read, it gets the right data! rc = serialport_write(fd, buf); // Trigger arduino serial read rc = serialport_write(fd, buf); //usleep(500*1000); if(rc==-1) return -1; break; case 'n': pin = strtol(optarg, NULL, 10); // convert string to number rc = serialport_writebyte(fd, (uint8_t)pin); //usleep(500*1000); if(rc==-1) return -1; break; case 'v': val = strtol(optarg, NULL, 10); // convert string to number rc = serialport_writebyte(fd, (uint8_t)val); usleep(1*1000); if(rc==-1) return -1; break; case 't': etime = strtol(optarg, NULL, 10); // convert string to number //printf("We got this etime: %ld \n",etime); int z=0; for (z = 0; z < 4; z++) { uint8_t eb = etime>>(8*z); rc = serialport_writebyte(fd, (uint8_t)eb); usleep(1*1000); } //usleep(500*1000); if(rc==-1) return -1; break; // case 's': // strcpy(buf,optarg); // 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_writelong( int fd, uint32_t l) { // Added by Mark Sadgrove to support long experimental run times int len = sizeof(l); int n = write(fd,&l,4); //int n = fprintf(&fd,"%l",&l); 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 ) 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; }