Разве два события timer_tick не могут работать параллельно при чтении одних и тех же данных, но при выполнении разных задач?

Я разработал приложение C# для чтения звонков с GSM-модема. Я использовал таймер, чтобы регулярно читать порт и уведомлять меня о входящем звонке.

Теперь я пытаюсь использовать другой таймер, который будет писать AT+CSQ -Чтобы узнать качество сигнала, на порту и прочитать порт для значения качества. В обоих таймерах я использовал регулярные выражения для сопоставления и разделения нужных данных. Теперь проблема в том, что работает только мой timer2, который считывает качество сигнала, но не считывает таймер для входящих вызовов.

Мощность сигнала чтения таймера:

private void tmr_sig_quality_Tick(object sender, EventArgs e)
    {
        if (port.IsOpen)
        {
            port.WriteLine("AT+CSQ");
            string s= port.ReadExisting();
            var match= Regex.Match(s,@"\+CSQ: (\d+),(\d+)");
            if (match.Success)
            {
                progressBar1.Value = int.Parse(match.Groups[1].Value);
            }

        }
    }

Таймер считывает входящие вызовы:

      private void timer1_Tick(object sender, EventArgs e)
       {
                s = port.ReadExisting();

                var match = Regex.Match(s, "RING[^\\+]*\\+CLIP:\\s*\"(?<phone>[^\"]*)\",(\\d+),\"([^\"]*)\",(\\w*),\"(\\w*)\",(\\w*)");

                if (match.Success && s.Contains("RING"))
                {
                    incall_status.Text = "Incoming Call...." + match.Groups["phone"].Value;
                    incall_status.Visible = true;
                }
        }

Почему это происходит и решение, пожалуйста?


person Cdeez    schedule 30.07.2012    source источник
comment
Почему у вас нет обоих в одном вызове таймера?   -  person Gavin    schedule 30.07.2012
comment
Вот у меня типичная проблема. Я сделал так, но мой индикатор выполнения ничего не показывает. Я использовал точки останова, чтобы увидеть, что прочитала моя строка, и, к моему удивлению, она читалась правильно, и мой индикатор выполнения показывает статус. Но когда я напрямую запускаю свое приложение, индикатор выполнения ничего не показывает.   -  person Cdeez    schedule 30.07.2012
comment
Вы обнаружите, что вы не можете изменить пользовательский интерфейс через поток. Если я правильно помню, таймеры используют потоки, поэтому вам нужно использовать Invoke, т.е. c" title="как обновить графический интерфейс из другого потока в c"> stackoverflow.com/questions/661561/   -  person Gavin    schedule 30.07.2012
comment
Правильно, обычный System.Timer не может обновить пользовательский интерфейс DispachedTimer (при использовании WPF) (msdn.microsoft.com/en-us/library/) может обновить пользовательский интерфейс, но это также приведет к замедлению работы пользовательского интерфейса при выполнении длительной задачи, такой как опрос последовательного порт.   -  person Per    schedule 30.07.2012


Ответы (2)


Две основные проблемы. Во-первых, это ReadExisting(), который всегда возвращает пустую строку. За исключением случаев, когда вы отлаживаете и выполняете код построчно. Это дает модему достаточно времени для отправки ответа. Но это не сработает, когда вы работаете на полной скорости, вам нужно будет сделать блокирующий вызов, который гарантирует, что ваша программа будет ждать достаточно долго, чтобы получить все возвращаемые символы. Вместо этого используйте ReadLine().

Вторая проблема-убийца заключается в том, что вы смешиваете команды. Ваш метод tmr_sig_quality_Tick(), скорее всего, прочитает все, что должен был прочитать timer1_Tick(). Вам нужно будет переосмыслить этот подход. Что-то вроде очереди команд, которая не продвигается вперед, пока не будет получен ответ на команду.

person Hans Passant    schedule 30.07.2012
comment
Первая проблема, как вы сказали, с ReadExisting(), может быть в первый раз, когда он будет пустым, но, по крайней мере, после 2 или 3 интервалов выполнения события тика будет какой-то ответ на чтение, верно? - person Cdeez; 31.07.2012
comment
Нет, вы используете WriteLine() перед этим и надеетесь получить ответ на эту команду. ReadExisting() не даст вам такого ответа, он вернет пустую строку. Как я уже сказал, вам нужно переосмыслить свой подход. - person Hans Passant; 31.07.2012

Не фактический ответ на ваш вопрос, а общий совет для связи с модемом GSM:

Имейте в виду, что у вас есть только один последовательный порт, следовательно, только один канал связи. Модем GSM может отправлять спонтанные события, такие как события RING, FAX, VOICE, поэтому нет гарантии, что при вводе AT+CSQ первым ответом будет то, что вы ожидаете, то есть качество сигнала.

Наличие двух таймеров, как вы намереваетесь, не является хорошей идеей, поскольку в конечном итоге вы получите ответ одной команды в таймере A, когда он ожидался в B, потому что A прочитал одно из спонтанных событий... и т.д.

Гораздо лучший и надежный способ — иметь рабочий поток, который считывает и интерпретирует входящие данные, а затем распределяет их в вашем приложении по мере необходимости. Он также может обрабатывать исходящие данные. Используйте одновременные очереди и некоторый механизм сигнализации (например, AutoResetEvent) для обмена данными с этим потоком, таким образом, вы получаете более чистый интерфейс для вашего аппаратного устройства и вам не нужно беспокоиться о времени и тому подобном в вашем приложении.

person Per    schedule 30.07.2012