C - Данные не получены последовательным устройством - PullRequest
0 голосов
/ 27 апреля 2018

Я использую C, чтобы открыть последовательное устройство и отправлять / получать данные на него или с него. Прием работает без проблем, но любые отправляемые данные не доходят до устройства. Я открываю устройство так:

int open_tty() {
    int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_CLOEXEC);  

    struct termios config;
    cfsetispeed(&config, B38400);
    cfsetospeed(&config, B38400);
    config.c_cflag &= ~PARENB;                                                                                                                                          
    config.c_cflag &= ~CSTOPB;                                                                                                                                          
    config.c_cflag &= ~CSIZE;                                                                                                                                           
    config.c_cflag |= CS8;                                                                                                                                              

    tcsetattr(fd, TCSANOW, &config);                                                         

    return fd;
}

...
write(fd, data, length)
...

По словам strace, все работает просто отлично:

openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_CLOEXEC) = 3
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
write(3, "some data.......", 16) = 16

Однако устройство не получает никаких данных (оно должно отправить пакет ACK). Если я делаю то же самое в Python, все работает нормально:

s=serial.Serial('/dev/ttyUSB0', baudrate=9600*4)
s.write('some data.......')

Трассирование:

openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC) = 3
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TIOCMBIS, [TIOCM_DTR])         = 0
ioctl(3, TIOCMBIS, [TIOCM_RTS])         = 0
ioctl(3, TCFLSH, TCIFLUSH)              = 0
write(3, "some data.......", 16) = 16

Любая помощь будет принята с благодарностью.

EDIT: Как предложил @abarnert, я установил биты DTR и RTS и очистил буфер:

char rts = TIOCM_RTS;
char dtr = TIOCM_DTR;
ioctl(fd, TIOCMBIS, &dtr);
ioctl(fd, TIOCMBIS, &rts);
tcflush(fd, TCIFLUSH);

Это привело к тому, что следующие дополнительные системные вызовы отправлялись непосредственно перед вызовом write:

ioctl(3, TIOCMBIS, [TIOCM_DTR|TIOCM_DSR|0x200]) = 0
ioctl(3, TIOCMBIS, [[TIOCM_RTS|0x30200}) = 0
ioctl(3, TCFLSH, TCIFLUSH)               = 0

Тем не менее, я все еще не получаю ACK-пакет от устройства.

Устройство представляет собой VirtualRobotix GPS uBlox 8 (http://www.virtualrobotix.it/index.php/en/shop/gps/3dr-gps-ublox-8-542015-11-30-13-35-34_-detail), подключенный с использованием преобразователя USB в последовательный интерфейс.

1 Ответ

0 голосов
/ 30 апреля 2018

Хммм, боюсь, вы не выполнили правильную процедуру установки termios параметров. Сначала вы должны использовать tcgetattrs(3), чтобы получить действительные сконфигурированные параметры (и инициализировать структуру termios, в противном случае неинициализированную для мусора в вашем коде, поскольку вы объявили его как автоматическую переменную), затем вы измените, что вы хотите, и, наконец, вы установите желаемую конфигурацию.

Правильная процедура:

 struct termios param;
 res = tcgetattrs(fd, &param); /* VERY IMPORTANT: first get the actual parameters */
 if (res < 0) {
      perror("tegetattrs");
      exit(EXIT_FAILURE);
 }
 cfsetispeed(&param, B38400);
 cfsetospeed(&param, B38400);
 param.c_cflag &= ~PARENB;
 /* ... all the needed configuration. */
 /* and finally. */
 res = tcsetattrs(fd, &param);
 if (res < 0) { /* error */
     perror("tcsetattrs");
     exit(EXIT_FAILURE);
 }

(Также обычно проверяется возвращаемое значение res на наличие ошибок)

как указано на странице руководства termios(3) в отношении настройки скорости линии:

Скорость линии

Функции скорости передачи данных предназначены для получения и установки значений. скоростей ввода и вывода в структуре termios. новые значения не вступают в силу, пока tcsetattr() не будет успешно называется .

Установка скорости на B0 заставляет модем "зависнуть". Настоящий битрейт, соответствующий B38400, может быть изменен с setserial(8).

Скорость ввода / вывода сохраняется в структуре termios .

(цитата моя)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...