To Compile: g++ tut_linux_serial.cpp -g -o tut_linux_serial -O3
-g to allow gdb to work
-o tut_linux_serial is the output name
-O3 is the optimization level
using namespace std;
#define SERIALPORT "/dev/ttyS0" // port the device is plugged in to
#define BAUDRATE B38400 // baud rate the device spits out at
#define UPDATE_RATE 20 // update speed in Hz (probably set anywhere from 10-50
#include
#include
#include
#include
#include
#include
string serial_buffer; // Unprocessed data off the serial port
int fd_serial;
void timer_handler(int x); // used in automation
void serial_handler(int status); // interrupt function called on new data (position isn't guaranteed), pass to ReadSerial()
int main() {
struct termios tty; // will be used for new port settings
struct termios oldtty; // will be used to save old port settings
fd_serial = open(SERIALPORT, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd_serial < 0) {
printf("\nUnable to write to serial port (%s), are you root?\n", SERIALPORT);
_exit(1);
}
tcgetattr(fd_serial, &oldtty); // save current port settings
bzero(&tty, sizeof(tty)); // Initialize the port settings structure to all zeros
tty.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CRTSCTS; // 8N1
tty.c_iflag = IGNPAR;
tty.c_oflag = 0;
tty.c_lflag = 0;
tty.c_cc[VMIN] = 0; // 0 means use-vtime
tty.c_cc[VTIME] = 1; // time to wait until exiting read (tenths of a second)
tcflush(fd_serial, TCIFLUSH); // flush old data
tcsetattr(fd_serial, TCSANOW, &tty); // apply new settings
fcntl(fd_serial, F_SETOWN, getpid()); // enable our PID to receive serial interrupts
fcntl(fd_serial, F_SETFL, FASYNC);
struct sigaction saio; // set the serial interrupt handler
saio.sa_handler = serial_handler; // to this function
sigemptyset(&saio.sa_mask); // clear existing settings
saio.sa_flags = 0; // make sure sa_flags is cleared
saio.sa_restorer = NULL; // no restorer
sigaction(SIGIO, &saio, NULL); // apply new settings
// set up the main timer
struct itimerval timer1; // set up the timers
signal(SIGALRM, timer_handler); // call this function on rollover
timer1.it_interval.tv_sec = 0; // reset val
timer1.it_interval.tv_usec = (__suseconds_t)((1.0/(double)UPDATE_RATE)*1000000); // reset val (converts UPDATE_RATE from Hz into microseconds
timer1.it_value.tv_sec = timer1.it_interval.tv_sec; // initial val
timer1.it_value.tv_usec = timer1.it_interval.tv_usec; // initial val
setitimer(ITIMER_REAL, &timer1, NULL); // apply new settings
while (1) { } // press ctrl-c to exit the program
write(fd_serial, "t", 1); // where t is the test char to send
tcsetattr(fd_serial, TCSANOW, &oldtty); // restore the old port settings before quitting
}
void serial_handler (int status) {
// this function is called whenever there is new data to be read off the serial port.
// It has to execute quickly, so the data processing is *not* done here.
char temp_buffer[256*2]; // max chars to read at once, if you don't read the entire buffer then the function will get called again
int len = read(fd_serial, temp_buffer, sizeof(temp_buffer)); // do the actual read
temp_buffer[len] = 0; // null terminate the string **important**
serial_buffer += temp_buffer; // append what we read to the serial_buffer of unprocessed data
}
void timer_handler(int x) {
// this function gets called UPDATE_RATE times per second, it handles the data processing off the serial port
// ** note that serial_buffer gets populated from serial_handler
signal(SIGALRM, timer_handler); // clear the interrupt flag, so it will trigger again when we exit
int infinite_loop_preventer = 0; // sanity check to make sure this section won't run forever
if (serial_buffer.length() > 0) { // unprocessed data exists
int start_pos; // position of the first $ char (all packets must start with a $
int end_pos_n; // position of the first \n char following the first $
int end_pos_r; // position of the first \r char following the first $
int end_pos; // set to the lesser of end_pos_n or end_pos_r
do {
infinite_loop_preventer++;
// 1) find start char
// 2) find end char (\n or \r)
// 3) process that data
// loop while there's more data
start_pos = serial_buffer.find("$", 0);
end_pos_n = serial_buffer.find("\n", start_pos);
end_pos_r = serial_buffer.find("\r", start_pos);
end_pos = end_pos_n < end_pos_r ? end_pos_n : end_pos_r; // choose the lesser of the two ending points
if (start_pos != string::npos && end_pos != string::npos) {
string data = serial_buffer.substr(start_pos, end_pos-start_pos); // just the current packet
serial_buffer = serial_buffer.substr(end_pos+1); // remove parsed section
// cout << "Debug: ";
// cout << " start_pos=" <<>
// cout << " end_pos=" <<>
// cout << " data.len=" <<>
// cout << data=" << data << ">
// cout << serial_buffer=" << serial_buffer << ">
// cout <<>
cout << data << endl;
}
} while (start_pos != string::npos && end_pos != string::npos && infinite_loop_preventer < color="#008800"> // keep processing if buffer has end char in it
}
}
Sample Output:
GPGLL,3354.4970,N,11759.5354,W,025604,V,S*52GPGLL,3354.4980,N,11759.5353,W,025605,V,S*55
GPGLL,3354.4990,N,11759.5355,W,025606,V,S*22
0 comments:
Post a Comment