2016-09-14 4 views
2

Добрый день,Передача двоичных данных через ttyACM

У меня есть периферийное устройство, которое обменивается данными через USB через виртуальный последовательный порт. Все работает хорошо под Windows с универсальным серийным драйвером ACM, например: https://www.kernel.org/doc/Documentation/usb/linux-cdc-acm.inf

В Linux используется драйвер CDC ACM. Все в журналах sys работает нормально, но общение ведет себя странно. Когда я подключаю устройство, около 10 байт в начале связи теряются. Затем, только каждая вторая команда принимается в порядке.

Мои вопросы: 1) Протокол связи этого устройства не использует ASCII, он двоичный (он может случайным образом содержать контрольные символы и т. Д.). Должен ли я использовать stty для настройки только скорости, бит данных, стоп-бит и четность или что-то еще необходимо настроить для двоичной связи? (Чтобы игнорировать контрольные биты в ядре и передавать каждый байт - необработанные данные.)

2) Любая идея, как проверить правильность работы драйверов ACM linux или какие другие драйверы следует использовать для моего устройства CDC ACM?

Спасибо за любую идею!

+0

Вам просто нужно быть уверенным, что * termios * ** (a) ** правильно настроен для неканонического (aka * raw *) режима и ** (b) ** отключен контроль потока программного обеспечения. Вы не детализированы; какое программное обеспечение вы используете для выполнения этой передачи данных? Почему он не настраивает порт должным образом? – sawdust

+1

'stty -F/dev/ttyACM0 raw' может работать (если программа передачи также не настраивает эти атрибуты). Обратите внимание, что нет дефиса, предшествующего параметру «raw». Это параметр, не являющийся переключателем. Если вы введете '-raw', вы отмените назначение этой команды. – sawdust

+0

У меня нет программного обеспечения, я использую echo -ne "\ xXY" для/dev/ttyACMx для записи байта и cat/dev/ttyACM в файл журнала для чтения из порта. Для просмотра полученных данных я открываю файл журнала через xxd. Настройки выполняются stty. Я думаю, что сырой параметр может быть решением, спасибо! – JirkaRCK

ответ

0

Linux будет часто манипулировать такими вещами, как символы окончания строки (0x0A и 0x0D), когда вы пытаетесь отправить их через последовательный порт, что может вызвать проблемы, если они фактически являются двоичными данными и не предназначены для обозначения строк.

Ниже приведен фрагмент from Pololu, который показывает, как правильно настроить последовательный порт, а затем отправить и получить несколько байтов. Обратите внимание на ту часть, которая вызывает, в частности, tcsetattr.

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

#ifdef _WIN32 
#define O_NOCTTY 0 
#else 
#include <termios.h> 
#endif 

// Gets the position of a Maestro channel. 
// See the "Serial Servo Commands" section of the user's guide. 
int maestroGetPosition(int fd, unsigned char channel) 
{ 
    unsigned char command[] = {0x90, channel}; 
    if(write(fd, command, sizeof(command)) == -1) 
    { 
    perror("error writing"); 
    return -1; 
    } 

    unsigned char response[2]; 
    if(read(fd,response,2) != 2) 
    { 
    perror("error reading"); 
    return -1; 
    } 

    return response[0] + 256*response[1]; 
} 

// Sets the target of a Maestro channel. 
// See the "Serial Servo Commands" section of the user's guide. 
// The units of 'target' are quarter-microseconds. 
int maestroSetTarget(int fd, unsigned char channel, unsigned short target) 
{ 
    unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F}; 
    if (write(fd, command, sizeof(command)) == -1) 
    { 
    perror("error writing"); 
    return -1; 
    } 
    return 0; 
} 

int main() 
{ 
    const char * device = "/dev/ttyACM0"; // Linux 
    int fd = open(device, O_RDWR | O_NOCTTY); 
    if (fd == -1) 
    { 
    perror(device); 
    return 1; 
    } 

#ifdef _WIN32 
    _setmode(fd, _O_BINARY); 
#else 
    struct termios options; 
    tcgetattr(fd, &options); 
    options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF); 
    options.c_oflag &= ~(ONLCR | OCRNL); 
    options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 
    tcsetattr(fd, TCSANOW, &options); 
#endif 

    int position = maestroGetPosition(fd, 0); 
    printf("Current position is %d.\n", position); 

    int target = (position < 6000) ? 7000 : 5000; 
    printf("Setting target to %d (%d us).\n", target, target/4); 
    maestroSetTarget(fd, 0, target); 

    close(fd); 
    return 0; 
} 

Вы могли бы быть в состоянии сделать то же самое с помощью утилиты командной строки stty.

Смежные вопросы