Reputation: 19
I have a bluetooth IMU (seen as a serial device at /dev/rfcomm0) that returns the current angle in quaternions 50 times a second.
I did a test program to read data and it worked, but I have to integrate it in a while cycle where, after the reading is done, a thread is a created and a computationally expensive elaboration is done, so I cannot read keep the rate with the IMU data.
The IMU sends me a 54 bytes packet, and the first two bytes are always set to Ascii "tt".
This is the C code I'm using:
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 54;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int start_serial()
{
char *portname = "/dev/rfcomm0";
int fd;
int wlen;
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
set_interface_attribs(fd, B115200);
wlen = fwrite(fd, "?!CALIB050!?\n", 14);
if (wlen != 14) {
printf("Error from write: %d, %d\n", wlen, errno);
}
tcflush(fd,TCIFLUSH);
tcdrain(fd); /* delay for output */
return fd;
}
int read_serial(int fd)
{
char buf[54];
int rdlen;
rdlen = read(fd, buf, 54);
if (rdlen > 0)
{
struct CPacketCalib cc = CPacketCalibConvert(buf);
printf("%f %f %f %f\n",cc.q.I, cc.q.J, cc.q.K,cc.q.W);
}
else if (rdlen < 0)
{
printf("Error from read: %d: %s\r\n", rdlen, strerror(errno));
}
return 1;
}
int stop_serial(int fd)
{
int wlen = write(fd, "?!STOPSEND!?\n", 14);
if (wlen != 14)
{
printf("Error from write: %d, %d\n", wlen, errno);
}
fclose(fd);
return 1;
}
How can I flush the serial buffer at every cycle and start to get correctly my packet?
Thank you for your help.
Upvotes: 1
Views: 2127
Reputation: 1133
What your problem sounds like is that you start your read in the middle of your packet and get half of one packet and half of the other. In that case, you need to read until you get to the start of your packet, and only then feed it to your parsing function. So something like this:
char ch;
char[52] buf;
while(1){
if(read(fd, &ch, sizeof(ch)) > 0 && ch == 't'){
if(read(fd, &ch, sizeof(ch)) > 0 && ch == 't'){
if(read(fd, buf, sizeof(buf)) == sizeof(buf)){
struct CPacketCalib cc = CPacketCalibConvert(buf);
}
}
}
}
So CPacketCalibConvert
only gets called with a complete packet of data (minus the two 't's, perhaps add them back in inside the innermost block?).
Upvotes: 1