Я пытаюсь отправлять/получать данные через порт USB с помощью FTDI, поэтому мне нужно обрабатывать последовательную связь с помощью C/С++. Я работаю над Linux (Ubuntu).
В принципе, я подключен к устройству, которое прослушивает входящие команды. Мне нужно отправить эти команды и прочитать ответ устройства. Обе команды и ответ символы ASCII.
Все работает отлично, используя GtkTerm, но когда я переключаюсь на программирование на С, у меня возникают проблемы.
Здесь мой код:
#include <stdio.h> // standard input / output functions
#include <stdlib.h>
#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
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY );
/* Error Handling */
if ( USB < 0 )
{
cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl;
}
/* *** Configure Port *** */
struct termios tty;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr ( USB, &tty ) != 0 )
{
cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl;
}
/* Set Baud Rate */
cfsetospeed (&tty, B9600);
cfsetispeed (&tty, B9600);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
tty.c_iflag &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
tty.c_oflag &= ~OPOST; // make raw
/* Flush Port, then applies attributes */
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
cout << "Error " << errno << " from tcsetattr" << endl;
}
/* *** WRITE *** */
unsigned char cmd[] = {'I', 'N', 'I', 'T', ' ', '\r', '\0'};
int n_written = write( USB, cmd, sizeof(cmd) -1 );
/* Allocate memory for read buffer */
char buf [256];
memset (&buf, '\0', sizeof buf);
/* *** READ *** */
int n = read( USB, &buf , sizeof buf );
/* Error Handling */
if (n < 0)
{
cout << "Error reading: " << strerror(errno) << endl;
}
/* Print what I read... */
cout << "Read: " << buf << endl;
close(USB);
Что происходит, так это то, что read()
возвращает 0 (без байтов) или блокируется до таймаута (VTIME
). Я предполагаю, что это происходит, потому что write()
ничего не отправляет. В этом случае устройство не получит команду, и я не могу получить ответ. Фактически, выключение устройства, пока моя программа заблокирована при чтении, фактически полученном от ответа (устройство отправляет что-то во время выключения).
Странно то, что добавление этого
cout << "I've written: " << n_written << "bytes" << endl;
сразу после вызова write()
я получаю:
I've written 6 bytes
что я и ожидаю. Только моя программа не работает должным образом, например мое устройство не может получить то, что я на самом деле пишу на порт.
Я пробовал разные вещи и решение, также касающиеся типов данных (я пробовал использовать std::string, например cmd = "INIT \r"
или const char
), но ничего действительно не работало.
Может кто-нибудь сказать мне, где я ошибаюсь?
Спасибо заранее.
EDIT: Раньше версия этого кода использовала
unsigned char cmd[] = "INIT \n"
а также cmd[] = "INIT \r\n"
. Я изменил его, потому что команда sintax для моего устройства сообщается как
<command><SPACE><CR>
.
Я также пытался избегать флага O_NONBLOCK
при чтении, но тогда я блокирую только до бесконечности. Я пробовал использовать select()
, но ничего не происходит. Просто для попытки, я создал цикл ожидания до тех пор, пока данные не будут доступны, но мой код никогда не выходит из цикла. Btw, ожидания или usleep()
- это то, что мне нужно избегать. Сообщенный - это только отрывок из моего кода. Полный код должен работать в среде реального времени (в частности, OROCOS), поэтому мне не нужна функция спящего режима.