Почему событие System.IO.Ports.SerialPort.DataReceived не срабатывает, когда модем находится в режиме данных?

В настоящее время в моем университете мы поддерживаем связь между этими старыми модемами 56k. Поскольку сообщения от ПК к модему проходят через последовательный порт, я решил использовать класс System.IO.Ports.SerialPort .NET.

Я написал довольно большое приложение на C # для связи с модемом, дозвона до другого модема и связи через них. Все работало нормально, пока мне не удалось установить соединение между двумя модемами. Когда это происходит, оба модема (как и должно быть) переключаются из режима COMMAND (где я могу отправлять команды Hayes модему) в режим DATA (где все данные, которые я отправляю модему, перенаправляются на другой модем).

Мое приложение может как отправлять вещи, так и получать их через последовательный порт. Он установлен на обоих подключенных ПК. Но когда я что-то набираю в своем приложении, например «Здравствуйте», с другой стороны не получено. А вот и самое странное. Вот как я отправляю сообщения через последовательный порт («порт» - это экземпляр класса SerialPort, «данные» - это экземпляр строки):

port.Write(data);

Так что работает. Это должно работать. Тем более, что если я использую свое приложение для отправки с одной стороны и PuTTy для приема с другой - это работает! PuTTy, подключенный к действующему последовательному порту, получает мое сообщение. Это также означает, что не только мое сообщение приходит на первый модем; он отправляется по сети на другой модем, а затем другой модем отправляет его через последовательный порт на принимающий ПК. Но это не все. Когда я использую свое приложение для приема, я использую событие SerialPort.DataReceived, как это (конечно, метод был + = ed для обработчика событий):

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    //this message box should pop up if event hit:
    MessageBox.Show("Data from serial port received!");
    //calling my method to handle incoming message
    DataReceived((SerialPort)sender); 
}

И это работает, когда модем (подключенный к принимающему ПК) находится в режиме КОМАНДА. Например. когда я посылаю модему команду «AT» Хейса (что означает не что иное, как «пинг»), модем отвечает «ОК», и я получаю ее. Событие SerialPort.DataReceived запускается. Но когда этот модем находится в режиме DATA (когда я не могу посылать ему команды Хейса), и он получает сообщение об отправке модема и пересылает его на последовательный порт - ничего. Событие даже не срабатывает. Я хорошо это проверил.

Это странно!

Это только подводит меня к выводу, что способ, которым модем отправляет сообщение на последовательный порт, немного отличается в режиме DATA и в режиме COMMAND, и PuTTy каким-то образом понимает этот другой способ, а класс SerialPort - нет.

Я действительно этого не понимаю.


person Sushi271    schedule 12.10.2012    source источник
comment
Прошло много времени с тех пор, как я занимался программированием модемов, но я не припомню каких-либо отличий между командным и прозрачным режимами. Во всяком случае, разница должна быть в линиях управления EIA / RS-232. Так что, возможно, вам нужно прикрепить коммутационный блок со светодиодными индикаторами состояния каждой линии подтверждения. Кстати, вы ничего не упоминаете о режимах набора и ответа модемов. Я всегда использовал автоответчик на удаленном конце, то есть удаленный модем уже находится в режиме данных и готов к отправке / получению через свой последовательный порт.   -  person sawdust    schedule 13.10.2012
comment
Меня учили, что у модема есть два режима: КОМАНДА для команд Хейса и ДАННЫЕ для передачи данных. Я набираю номер и отвечаю: я просто отправляю команду ATDT ‹number› на модем для набора номера, а с другой стороны, когда модем отправляет RING сообщение, я отправляю команду ATA. Я намеренно не использую автоответчик, но когда я это делаю, проблема все равно возникает. И я скорее думал о каком-то программном решении, чем о коммутационном боксе со светодиодами ... что однозначно превосходит мои возможности (и время).   -  person Sushi271    schedule 13.10.2012
comment
Вам не обязательно использовать коммутационный блок, но это один из простых методов быстрой проверки правильности управления потоком HW и сигналов установления связи модема. В противном случае вам лучше убедиться, что управление потоком (как аппаратное, так и программное обеспечение) и сигналы модема правильно настроены на всех модемах и программах ПК. он получает сообщение от отправляющего модема и пересылает его на последовательный порт - Откуда вы это знаете? Если это действительно так, то линейный ученик вашей программы нуждается в проверке. Ваша программа ожидает строки текста, но вы отправили только Hello без CR и LF? Режим данных BTW также называется интерактивным или прозрачным режимом.   -  person sawdust    schedule 13.10.2012
comment
он получает сообщение от отправляющего модема и пересылает его на последовательный порт - я знаю это, потому что когда это похоже: myApp - ›1-й модем ----› 2-й модем - ›PuTTy, тогда PuTTy получает сообщение и показывает его. А когда вроде: myApp - ›1-й модем ----› 2-й модем - ›myApp, то ничего нет. И когда я проверяю с помощью отладчика, событие SerialPort.DataReceived - единственный способ проверить, поступило ли что-то на последовательный порт с использованием класса SerialPort - даже не срабатывает. Как будто я ничего не пришлю. Кроме того, я также проверил CRLF (пытаясь добавить его в каждую отправляемую строку), и никакой разницы не было.   -  person Sushi271    schedule 14.10.2012
comment
У меня была точно такая же проблема! Когда в конце был PuTTY, он работал, с моим приложением - нет. Рад, что нашел это, у меня ушло больше времени, чем следовало. Мне помогло рукопожатие, установленное на RequestToSend, как и предложил Шан К. в своем ответе.   -  person podvlada    schedule 11.10.2019


Ответы (2)


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

До сих пор я выполнил несколько проектов с классом SerialPort для обработки модемной связи с использованием .NET40, и связь работала должным образом.

Я предполагаю, что ваш метод DataReceived ((SerialPort) sender); блокирует дальнейшее получение данных.

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

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var com = sender as SerialPort;
    var lst = new List<byte>();

    if (com != null)
    {
        lock (com)
        {
            do
            {
                if (com.BytesToRead == 0) break;
                var one = com.ReadByte();
                if (one >= 0 && one < 256) lst.Add(Convert.ToByte(one));
            } while (one >= 0 && one < 256);

            // lst.ToArray(); // get bytes
        }

        // ... // do something with received data
    }
}

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

В приведенном примере есть два основных момента:

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

Кроме того, предоставленный код (в аналогичной форме) всегда использовался в многопоточном приложении, поэтому атрибут [MTAThread] в Main!

Одним из самых быстрых способов устранения неполадок последовательной связи может быть установка com0com, виртуального последовательного порта с http://com0com.sourceforge.net/ и попробовать прямую связь без модема, просто чтобы убедиться, что обмен данными работает.

Фактически вы можете использовать его в своем приложении. Просто установите одну пару виртуальных COM-портов, прикрепите свое приложение к одному последовательному порту, прикрепите замазку к другому, и когда вы увидите ATZ на замазке, просто ответьте OK \ r \ n :) Но если вы используете считывание контактов, тогда шпатлевка не может помогите, хоть как поменять флаги из шпатлевки не знаю.

Я знаю, что эта ветка устарела, но некоторые отзывы приветствуются.

Счастливого кодирования.

person recineshto    schedule 12.09.2013

SerialDataReceivedEventHandler не запускался, потому что Handshake был установлен неправильно.

Мне пришлось использовать аппаратные средства управления потоком, что Handshake.RequestToSend, и сейчас оно у меня работает.

person Shan K    schedule 13.09.2013
comment
Извините, что откопал этот старый пост, но да, рукопожатие RTS мне тоже помогло. Я имел дело с устройствами, которым при прямом подключении требовалось установить для квитирования значение Нет, но при подключении через модем квитирование приходилось включать с настройкой RTS. Я пробовал буквально любую другую конфигурацию, мне следовало начать с этой. - person podvlada; 11.10.2019