2016-12-28 6 views
0

Я использую малиновый Pi Zero в режиме устройства и малиновый Pi B в режиме хоста. Я подключаю два кабеля USB. Моя цель прямо сейчас - просто отправить простые, произвольные данные назад и вперед между двумя Pi.чтение из последовательного порта всегда возвращает то, что было написано

Проблема в том, что Pi пишет в последовательный порт, сначала заканчивает чтение того, что он написал. Программа, которую я написал, отправляет устройство d\n, а хост отправляет h\n. Итак, если устройство записывает сначала, хост правильно считывает d\n, а затем записывает h\n в последовательный порт. Но устройство заканчивается чтением d\n! Проблема сохраняется, если я переключу его так, чтобы хост сначала записывал.

Я попытался добавить различные tcflush звонки в программу после записи, но перед чтением, но это не сработает. Я также пробовал спать в течение некоторого времени. Я читал, ожидая 100 микросекунд за каждый написанный персонаж, и я спал несколько секунд.

Моя установка требует, чтобы у меня не было постоянной связи между обоими Pi в то же время из-за единственного порта USB с поддержкой данных Pi Zero. Итак, чтобы проверить, я фактически подключаю клавиатуру и запускаю программу, а затем подключаю соответствующий кабель для передачи данных. Я могу передавать данные, но не после записи, потому что программа просто читает, что она написала.

Я начинаю думать, что попал в ловушку noob, которую я не могу понять. Вот код, я использую:

#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h>  
#include <termios.h> 
#include <errno.h> 

/* 
* gcc -o device_rw -DDEVICE serial_rw.c 
* gcc -o host_rw serial_rw.c 
*/ 

#define SERIAL_DEVICE "/dev/ttyGS0" 
#define SERIAL_HOST "/dev/ttyACM0" 

#ifdef DEVICE 
#define _TTY SERIAL_DEVICE 
#else 
#define _TTY SERIAL_HOST 
#endif 

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 &= ~PARENB;  /* no parity bit */ 
    tty.c_cflag &= ~CSTOPB;  /* only need 1 stop bit */ 
    tty.c_cflag &= ~CSIZE; 
    tty.c_cflag |= CS8;   /* 8-bit characters */ 

    tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ 
    tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ 

    tty.c_iflag |= IGNPAR | IGNCR; 
    tty.c_iflag &= ~(IXON | IXOFF | IXANY); 
    tty.c_iflag |= ICANON; 
    tty.c_iflag &= ~OPOST; 

    if (tcsetattr(fd, TCSANOW, &tty) != 0) { 
     printf("Error from tcsetattr: %s\n", strerror(errno)); 
     return -1; 
    } 

    return 0; 
} 

void 
write_serial (int fd, const char *buf, int len) 
{ 
    printf("WRITE: %s\n", buf); 
    write(fd, buf, len); 
} 

void 
read_serial (int fd, char *buf, int len) 
{ 
    ssize_t nread = read(fd, buf, len); 
    if (nread > 0 && nread <= len) { 
     buf[nread] = 0; 
     printf(" READ: %s\n", buf); 
    } 
} 

int 
main (int argc, char **argv) 
{ 
    char buf[80]; 
    int fd = open(_TTY, O_RDWR | O_NOCTTY); 

    if (fd < 0) { 
     fprintf(stderr, "Can't open %s: %s\n", _TTY, strerror(errno)); 
     goto exit; 
    } 

    if (set_interface_attribs(fd, B115200) < 0) { 
     goto exit; 
    } 

#ifdef DEVICE 
    printf("device: %s\n", _TTY); 
    write_serial(fd, "d\n", 2); 
    usleep((2 + 25) * 100); 
    read_serial(fd, buf, 2); 
#else 
    printf("host: %s\n", _TTY); 
    read_serial(fd, buf, 2); 
    //usleep((2 + 25) * 100); 
    write_serial(fd, "h\n", 2); 
#endif 

    close(fd); 
exit: 
    return 0; 
} 
+0

Где вы положили '#define DEVICE', чтобы удовлетворить ваши версии компиляции, управляемые' #ifdef DEVICE'? –

+0

Я скомпилирую с '-DDEVICE', чтобы вызвать его. – Leroy

+0

О, я вижу, как прокомментировано в коде. Но мне это не нравится - может привести к неприятностям с пальцами. Я предлагаю, чтобы * конкретное значение * должно быть определено, чтобы компиляция завершилась без него. –

ответ

0

Я многому научился из ответов каждого и благодарен им за то, что они мне понадобятся, когда я перехожу к этому проекту. Для этот конкретный случай, однако проблема в конечном итоге была разрешением. Да, разрешения на файл: ttyGSO.

Я полностью ожидал ошибку permission denied от open и никогда не получал ее, поэтому я никогда не рассматривал возможность. Тем более, что я открыл файлы в RDWR режиме, я мог записать в серийный файл, и появился Я читал данные (хотя те же данные), что мне никогда не приходило в голову, что, возможно, у меня не было прав на чтение.

4

Помимо не отключив атрибуты ECHO (как прокомментировал @MarkPlotnick), у вас есть два задания: неправильно использованных

tty.c_iflag |= ICANON; 

ICANON принадлежит члену lflag, и

tty.c_iflag &= ~OPOST; 

OPOST относится к члену oflag.
Учитывая эти ошибки, вы правильно применили предложение @ MarkPlotnick?

См. Working with linux serial port in C, Not able to get full data для рабочей канонической установки.

cfsetospeed(&tty, (speed_t)speed); 
cfsetispeed(&tty, (speed_t)speed); 

tty.c_cflag |= CLOCAL | CREAD; 
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 */ 

tty.c_lflag |= ICANON | ISIG; /* canonical input */ 
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN); 

tty.c_iflag &= ~INPCK; 
tty.c_iflag |= IGNCR; 
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL); 
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */ 

tty.c_oflag &= ~OPOST; 

Обратите внимание, что также возможно, чтобы иметь эхо включено на дальнем конце.
Чтобы определить, генерируется ли эхо локально или с дальнего конца, просто отключите удаленное устройство (при условии, что вы используете UART и/или USB-последовательные адаптеры) и передаете.
Если вы все еще получаете эхо, то он генерируется локально, который контролируется termios ECHO.
Если вы больше не получаете эхо, то это удаленный блок, который повторяет свой вход обратно отправителю.


BTW Ваша программа как отправленная не компилируется чисто.
Это отсутствует #include <string.h>
termios инициализации рутинную, скопированный (но тогда неправильно модифицированный) имеет надлежащую проверку возвращаемых значений, но ваши чтения и записи процедуры не проверяют на наличие ошибок.