Поведение PARMRK termios не работает в Linux

Я пытаюсь получать сообщения от устройства, которое использует контроль четности для байта адреса и контроль четности пробела для тела сообщения. Устройство является «мастером» многоабонентской последовательной шины. Основываясь на справочной странице termios, я использую CMSPAR, PARENB, ~PARODD, INPCK, ~IGNPAR и PARMRK. Я ожидаю получить 3-байтовую последовательность для каждого байта адреса: '\377' '\0' . Этого не происходит... Я всегда получаю байт адреса (и байты тела), но не начальные символы '\377' '\0'.

Я попытался заставить PARMRK работать с настройками нечетной и четной четности на тот случай, если CMSPAR не поддерживается. По-прежнему нет 3-байтовых последовательностей в потоке данных. Я использую Ubuntu 12.04 LTS.

n_tty.c: n_tty_receive_parity_error() имеет логику, реализующую PARMRK. 8250_core.c имеет логику для пометки ошибок четности. dmesg | grep ttyS0 показывает serail8250: ... это 16550A. Хммм... последующее сообщение показывает 00:0a: ... это 16550A. Возможно, драйвер 8250 на самом деле не обрабатывает ttyS0?

Любые идеи? Даже если вы не видите, что я сделал неправильно, но заставили PARMAR работать, комментарии о вашей ситуации могут мне помочь.

ОБНОВЛЕНИЕ: мой Linux работает на виртуальной машине VMware, поэтому я попробовал конфигурацию без виртуальной машины, и теперь она работает! Если кто-то знает, я все же хотел бы знать, почему ошибки четности не обнаруживаются на виртуальной машине.

Вот мой код конфигурации:

struct termios tio;
bzero(&tio, sizeof(tio));
tcgetattr(fd, &tio);

// Frame bus runs at 38,400 BAUD
const int BAUD_Rate = B38400;

cfsetispeed(&tio, BAUD_Rate);
cfsetospeed(&tio, BAUD_Rate);

// Initialize to raw mode. PARMRK and PARENB will be over-ridden before calling tcsetattr()
cfmakeraw(&tio);

// Ignore modem lines and enable receiver
tio.c_cflag |= (CLOCAL | CREAD);

// No flow control
tio.c_cflag &= ~CRTSCTS;        // No HW flow control
tio.c_iflag &= ~(IXON | IXOFF); // Set the input flags to disable in-band flow control

// Set bits per byte
tio.c_cflag &= ~CSIZE;
tio.c_cflag |=  CS8;

// Use space parity to get 3-byte sequence (0xff 0x00 <address>) on address byte
tio.c_cflag |=  CMSPAR;         // Set "stick" parity (either mark or space)
tio.c_cflag &= ~PARODD;         // Select space parity so that only address byte causes error

// NOTE: The following block overrides PARMRK and PARENB bits cleared by cfmakeraw.
tio.c_cflag |=  PARENB;         // Enable parity generation
tio.c_iflag |=  INPCK;          // Enable parity checking
tio.c_iflag |=  PARMRK;         // Enable in-band marking 
tio.c_iflag &= ~IGNPAR;         // Make sure input parity errors are not ignored

// Set it up now
if (tcsetattr(fd, TCSANOW, &tio) == -1)
{
    cout << "Failed to setup the port: " << errno << endl;
    return -1;
}

person Dan George    schedule 21.11.2013    source источник
comment
У меня была аналогичная проблема с получением escape-последовательностей. Ваш хорошо задокументированный код выше помог мне понять, что после использования cfmakeraw я не очищал IGNPAR, который, как написано на коробке, игнорировал ошибки четности.   -  person ottago    schedule 26.01.2017


Ответы (1)


У меня была аналогичная проблема (но с противоположной стороны):

Мастер последовательного протокола должен посылать 1-й байт кадра с меткой четности, а все остальные — с промежутком четности, тогда как ведомый отвечает только с промежутком четности.

Многие драйверы последовательной связи будут игнорировать бит «CMSPAR» без возврата ошибки, поэтому вы можете подумать, что вы установили четность Mark/Space, в то время как вместо этого вы выбрали четность Odd/Even.

Мне пришлось использовать анализатор протокола, чтобы понять это.

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

Большинству адаптеров USB-Serial потребуется аналогичный подход, поскольку они не поддерживают знак четности/пробел.

Например, предположим, что мы хотим отправить следующие данные:

01 03 07 0F 1F

1-й байт должен быть отправлен с пометкой четности, а остальные - с пробелом четности.

Мы могли бы сделать следующее:

Send 01 with odd  parity (parity bit=1)
Send 03 with odd  parity (parity bit=0)
Send 07 with even parity (parity bit=0)
Send 0F with odd  parity (parity bit=0)
Send 1F with even parity (parity bit=0)

Таким образом, мы можем смоделировать необходимый результат.

Загвоздка здесь в том, что при переключении четности драйвер выполняет множество проверок, которые отнимают много времени и это может повлиять на конечную скорость передачи данных.

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

Если ваша межсимвольная задержка критична, вам может понадобиться другое решение.

person Sophoclis Kesinis    schedule 08.06.2015
comment
Я не уверен, что мой ответ на самом деле вам сильно поможет, потому что изначально я думал, что вы хотите отправить байты с отметкой четности/пробелом, а не получить их. У меня также возникла аналогичная проблема с попыткой подключиться через канал последовательного порта на двух симуляторах последовательного протокола VMWare, которые используют знак четности/пробел. - person Sophoclis Kesinis; 08.06.2015