C # SerialPort - проблемы смешивания портов с разной скоростью - PullRequest
5 голосов
/ 23 марта 2010

У меня есть два устройства, которые я хотел бы подключить через последовательный интерфейс, но у них несовместимые соединения. Чтобы обойти эту проблему, я подключил их обоих к своему ПК и работаю над программой на C #, которая будет направлять трафик через COM-порт X на COM-порт Y и наоборот.

Программа подключается к двум COM-портам. В обработчике полученных данных я читаю входящие данные и записываю их на другой COM-порт. Для этого у меня есть следующий код:

    private void HandleDataReceived(SerialPort inPort, SerialPort outPort)
    {
        byte[] data = new byte[1];

        while (inPort.BytesToRead > 0)
        {
            // Read the data
            data[0] = (byte)inPort.ReadByte();

            // Write the data
            if (outPort.IsOpen)
            {
                outPort.Write(data, 0, 1);
            }
        }
    }

Этот код работал нормально, если исходящий COM-порт работал с более высокой скоростью передачи, чем входящий COM-порт. Если входящий COM-порт был быстрее, чем исходящий COM-порт, я начинал пропускать данные. Я должен был исправить код следующим образом:

    private void HandleDataReceived(SerialPort inPort, SerialPort outPort)
    {
        byte[] data = new byte[1];

        while (inPort.BytesToRead > 0)
        {
            // Read the data
            data[0] = (byte)inPort.ReadByte();

            // Write the data
            if (outPort.IsOpen)
            {
                outPort.Write(data, 0, 1);
                while (outPort.BytesToWrite > 0);  //<-- Change to fix problem
            }
        }
    }

Я не понимаю, зачем мне это исправление. Я новичок в C # (это моя первая программа), поэтому мне интересно, есть ли что-то, что мне не хватает. По умолчанию SerialPort использует буфер записи 2048 байт, а мои команды имеют размер менее десяти байт. Буфер записи должен иметь возможность буферизовать данные до тех пор, пока они не будут записаны в более медленный COM-порт.

Итак, я получаю данные на COM X и записываю их на COM Y. COM X подключается с большей скоростью передачи данных, чем COM Y. Почему буферизация в буфере записи не обрабатывает эту разницу? Почему кажется, что мне нужно подождать, пока буфер записи истощится, чтобы избежать потери данных?

Спасибо!

* Обновление *

Как уже отмечалось, этот код может очень легко перейти в состояние переполнения при большой и / или быстрой передаче входящих данных. Я должен был написать больше о моем потоке данных. Я ожидаю команды <10 байтов (с ответами <10 байтов) при 10 Гц. Кроме того, я вижу сбои в первой команде. </p>

Так что, хотя я знаю, что этот код не масштабируется и не является оптимальным, мне интересно, почему буферы чтения / записи 2-4К не могли даже обработать первую команду. Мне интересно, есть ли ошибка при записи одного байта данных или что-то с обработчиком событий, который я не понимаю. Спасибо.

* Обновление *

Вот пример сбоя:

Допустим, моя команда состоит из четырех байтов: 0x01 0x02 0x3 0x4. Устройство на COM X отправляет команду. Я вижу, как программа C # получает четыре байта и отправляет их на устройство по COM Y. Устройство по COM Y получает два байта: 0x01 0x03. Я знаю, что устройство на COM Y надежно, поэтому мне интересно, как два байта были сброшены.

Кстати, может кто-нибудь сообщить мне, лучше ли просто отвечать на ответы с комментариями или мне следует продолжать редактировать оригинальный вопрос? Что более полезно?

Ответы [ 2 ]

2 голосов
/ 23 марта 2010

То, что вы пытаетесь сделать, эквивалентно питью из пожарного шланга. Вы полагаетесь на приемный буфер для хранения воды, это не продлится долго, когда кто-то не выключит кран. Обходным путем вы гарантируете, что буфер приема будет тихо переполнен, возможно, вы не реализовали событие ErrorReceived.

Чтобы это работало, вы должны указать устройству ввода прекратить отправку, когда буфер заполнен. Сделайте это, установив свойство Handshake. Сначала установите его в Handshake.RequestToSend. Используйте XOnXOff дальше. Это зависит от устройства, будет ли оно правильно использовать сигналы рукопожатия.

Используйте метод Read (), чтобы сделать это немного более эффективным.


Хорошо, не пожарный шланг. Я могу думать только об одной другой возможности. Распространенная проблема с ранними конструкциями чипов UART, они имели встроенный буфер приема, который мог хранить только один байт. Для чего требовалась процедура обработки прерывания, чтобы прочитать этот байт до того, как прибудет следующий. Если ISR недостаточно быстр, микросхема включает состояние SerialError.Overrun и байт безвозвратно теряется.

Обходной путь для этой проблемы заключался в искусственной установке задержки между каждым передаваемым байтом, давая ISR в устройстве больше времени для чтения байта. Что делает ваш обходной код, как побочный эффект.

Это не очень хорошее объяснение, современные чипы имеют буфер FIFO глубиной не менее 8 байт. Если в этом есть какая-то правда, вы должны увидеть, что проблема исчезнет, ​​когда вы уменьшите скорость. Кроме того, использование Read () вместо ReadByte () должно усугубить проблему, поскольку ваш вызов Write () теперь может передавать более одного байта за раз, устраняя межсимвольную задержку. Чтобы было понятно, я говорю об устройстве вывода.

0 голосов
/ 23 марта 2010

Вы должны убедиться, что outPort.WriteBufferSize больше самого большого буфера, который вы ожидаете отправить.Кроме того, вызов ReadByte и WriteByte в цикле обычно будет медленным.Если вы измените свой обработчик на что-то вроде:

int NumBytes = 20; //or whatever makes sense
byte[] data = new byte[NumBytes];

while (inPort.BytesToRead > 0)
{
    // Read as much data as possible at once
    count = inPort.Read(data, 0, min(NumBytes, inPort.BytesToRead));

    // Write the data
    if (outPort.IsOpen)
    {
        outPort.Write(data, 0, count);
    }
}

, это уменьшит накладные расходы, которые должны помочьЗатем буфер записи будет (надеюсь) обрабатывать время, как вы ожидаете.

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