Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 31.12.06 21:46
Оценка:
С Новым годом!
Всем добра, удач, шуток, красот.
Уже как-то задавал вопрос, который здесь повторяю. Если есть что-то, что хотя бы косвенно может к нему отностиься, — выскажетесь пожалуйста:

Скажите пожалуйста, какое время определяет св-во ReadTimeout класса SerialPort.
Думал, что это время ожидания ответа. Но простая проверка опровергает.
В коде, приведенном ниже, MessageBox показывает 0. Причем 0 и в том случае, если модем выключен.
Но ведь порт не может знать включен или выключен модем. Он должен ждать 2000mc ответа.
И когда модем включен 0 — это странно. Даже если порт успел быстро получить ответ модема, то откуда он знает что это весь ответ и продолжения оного в течение назначенного времени ожидания не будет? Аналогичный вопрос по WriteTimeout: это время ожидания данных портом (аналогтчный код показывает — нет) или время, в течение которого данные с порта должны быть переданы устройству (модему) или что-то иное?



static SerialPort com = new SerialPort("COM1", 115200, Parity.None, 8, StopBits.One);
private void button1_Click(object sender, EventArgs e)
  {
   if (com.IsOpen) com.Close();
   com.ReadTimeout = 2000;
   com.WriteTimeout = 1400;
   com.DtrEnable = true;
   com.Open();
   Thread.Sleep(1500);
   com.Write("ATZ\r\n");
   Thread.Sleep(500);
   DateTime dt1 = DateTime.Now;
   byte[] bytes = new byte[1000];
   int ReadBytes = com.BytesToRead;
   com.Read(bytes, 0, ReadBytes);  
   TimeSpan ts = DateTime.Now - dt1;
   MessageBox.Show(ts.TotalMilliseconds.ToString());// показывает 0 (даже если модем выключен)
   com.Close();
  }
Re: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 01.01.07 21:42
Оценка: 2 (1)
Здравствуйте, Andrej-V, Вы писали:


AV>Скажите пожалуйста, какое время определяет св-во ReadTimeout класса SerialPort.

AV>Думал, что это время ожидания ответа. Но простая проверка опровергает.
AV>В коде, приведенном ниже, MessageBox показывает 0. Причем 0 и в том случае, если модем выключен.
AV>Но ведь порт не может знать включен или выключен модем.

Почему не может? Для этого как раз есть сигнал DSR, доступный через свойство DsrHolding. По крайней мере, стандарт RS232 предполагает использования этого сигнала для проверки наличия устройства передачи данных и его готовности, эти данные передавать...

С уважением,
Леонид.
Re[2]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 02.01.07 15:43
Оценка:
Здравствуйте, Леонид.
Спасибо за ответ. Один вопрос стал ясен.
С уважением,
Андрей.

--------------------------------------------------

Остаютсяся два независимых друг от друга вопроса (оба вопроса относятся к состоянию, когда модем включен).
1. Как порт определяет, что получен весь ответ (а не часть его). Т.е. как он определяет, что можно позволить программе выполняться не выжидая время записанное в свойстве ReadTimeout.
(Свойство ReadTimeout есть и у Stream, но как оно там работает (интуичит что все данные отправлены или нет) в MSDN, кажется, не написано.)
2. Почему время получения ответа на команду ATZ (команда инициализации модема) — 0. Ведь инициализация — процесс не мгновенный. Thread.Sleep(500);, которое записано после com.Write("ATZ\r\n"); на это время не влияет ( можно закомментировать, — все равно 0).
Re[3]: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 02.01.07 16:33
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:

AV>Остаютсяся два независимых друг от друга вопроса (оба вопроса относятся к состоянию, когда модем включен).

AV>1. Как порт определяет, что получен весь ответ (а не часть его). Т.е. как он определяет, что можно позволить программе выполняться не выжидая время записанное в свойстве ReadTimeout.

Беглый взгляд на код SerialPort посредством рефлектора показал, что он реализован через overlapped i/o при работе на Windows NT и выше. То есть пытается прочесть хоть сколько-нибудь байт из устройства и возвращает их пользователю. Остальные принятые данные кэшируется во внутреннем буфере класса до следующего вызова метода Read.
При этом ReadTimeout определяет, сколько времени класс SerialPort будет ждать хотя бы один байт от устройства, а не все заправшиваемые данные.

AV>2. Почему время получения ответа на команду ATZ (команда инициализации модема) — 0. Ведь инициализация — процесс не мгновенный. Thread.Sleep(500);, которое записано после com.Write("ATZ\r\n"); на это время не влияет ( можно закомментировать, — все равно 0).


Тут тоже все просто, данные поступающие из устройства кэшируются драйвером, независимо от состояния Вашего потока. Т.е. когда ваш поток спал в результате вызова Sleep, драйвер прочитал ответ модема. Модем вполне мог уложиться в 500 миллисекунд. Когда поток проснулся, драйвер сразу же вернул ему ранее прочитанные данные. Время обмена между Вашим потоком и драйвером заметно меньше разрешения таймера, используемого для измерения интервала, потому он и был определен как 0.

Вообще, подозреваю, что данный топик имеет очень отдаленное отношение к .NET, лучше его продолжить в Низкоуровневом программировании...

Успехов,
Леонид.
Re[4]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 02.01.07 18:08
Оценка:
C>Беглый взгляд на код SerialPort посредством рефлектора показал, что он реализован через overlapped i/o при работе на Windows NT и выше. То есть пытается прочесть хоть сколько-нибудь байт из устройства и возвращает их пользователю. Остальные принятые данные кэшируется во внутреннем буфере класса до следующего вызова метода Read.


Спасибо.
А как в NET SerialPort определяет сколько байт прочитать: один, два, десять?
Без этого знания невозможно написать программу обмена данными с портом.


AV>>2. Почему время получения ответа на команду ATZ (команда инициализации модема) — 0. Ведь инициализация — процесс не мгновенный. Thread.Sleep(500);, которое записано после com.Write("ATZ\r\n"); на это время не влияет ( можно закомментировать, — все равно 0).


C>Тут тоже все просто, данные поступающие из устройства кэшируются драйвером, независимо от состояния Вашего потока. Т.е. когда ваш поток спал в результате вызова Sleep, драйвер прочитал ответ модема. Модем вполне мог уложиться в 500 миллисекунд. Когда поток проснулся, драйвер сразу же вернул ему ранее прочитанные данные. Время обмена между Вашим потоком и драйвером заметно меньше разрешения таймера, используемого для измерения интервала, потому он и был определен как 0.



Драйвер модема не гружу (работаю с модемом напрямую через порт). Thread.Sleep(500); — закомментировал. Время получения ответа — 0;
Программка простая. Может попробуете, если есть немного времени и модем?



C>Вообще, подозреваю, что данный топик имеет очень отдаленное отношение к .NET, лучше его продолжить в Низкоуровневом программировании...


???
Так я ж на C# программирую. Вопросы по работе с SerialPort. Вникать в низкоуровнее программирование порта — бросает в дрожь.
Re[5]: Что определяет ReadTimeout SerialPort?
От: pr0ff  
Дата: 02.01.07 19:02
Оценка:
Здравствуйте, Andrej-V, Вы писали:


AV>Спасибо.

AV>А как в NET SerialPort определяет сколько байт прочитать: один, два, десять?
AV>Без этого знания невозможно написать программу обмена данными с портом.

Посмотрите в рефлекторе
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 02.01.07 19:36
Оценка:
Здравствуйте, pr0ff, Вы писали:

P>Посмотрите в рефлекторе


Спасибо, prOff, за ответ профессионала.
Не могли бы вы ткнуть меня — что конкретно в SerialPort посмотреть рефлектором, чтобы получить ответ на мой вопрос.
Re[7]: Что определяет ReadTimeout SerialPort?
От: pr0ff  
Дата: 02.01.07 22:11
Оценка:
Здравствуйте, Andrej-V, Вы писали:

AV>Здравствуйте, pr0ff, Вы писали:


AV>Спасибо, prOff, за ответ профессионала.

AV>Не могли бы вы ткнуть меня — что конкретно в SerialPort посмотреть рефлектором, чтобы получить ответ на мой вопрос.

Начните с метода "Read".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 02.01.07 22:13
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:



AV>Спасибо.

AV>А как в NET SerialPort определяет сколько байт прочитать: один, два, десять?
Думаю, что никак.

AV>Без этого знания невозможно написать программу обмена данными с портом.


Э.. видимо тут имеет место быть неверный протокол обмена. Это знание ненужно и даже вредно. В общем виде, при работе с последовательными устройствами нельзя полагаться на количество принятых данных. Нужно ввести спец. символы в протокол: например 0x1a — конец файла, если протокол символьный и проч.
Ну, или, если иначе совсем никак, читайте данные в цикле, пока не наберете нужное количество..
То есть примерно так:

byte[] buffer = ...
int bytesToRead = ...
int readCounter = 0;
DateTime startTime = DateTime.Now;
while( readCounter < bytesToRead )
{
  if( DateTime.Now - startTime > timeout )
  {
    // завершить цикл по таймауту
  }
  int read = com.Read( buffer, readCounter, bytesToRead - readCounter );
  readCounter += read;
}





AV>Драйвер модема не гружу (работаю с модемом напрямую через порт). Thread.Sleep(500); — закомментировал. Время получения ответа — 0;


А я писал про драйвер последовательного порта, а не модема. Драйвер модема для полседовательного порта — просто INF файл, где прописаны AT последовательности для основных операций с модемом: инициализировать, набрать номер, ответить на вызов и проч.


AV>???

AV>Так я ж на C# программирую. Вопросы по работе с SerialPort. Вникать в низкоуровнее программирование порта — бросает в дрожь.

Ну, если придет лесник и всех разгонит — я не виноват . А, вообще, принципы работы с посл. портом не зависят особо от языка программирования...

Успехов,
Леонид.
Re[8]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 02.01.07 22:43
Оценка:
Здравствуйте, pr0ff, Вы писали:

P>Начните с метода "Read".


Read посмотрел после вашего 1-го ответа. Не могли бы еще более конкретно — где там ответ или подсказка?
Re[6]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 03.01.07 00:24
Оценка:
Здравствуйте, curvex, Вы писали:

AV>>А как в NET SerialPort определяет сколько байт прочитать: один, два, десять?

C>Думаю, что никак.

Я предполагал, что как-то используется какое-то время считывания или считывается определенное кол-во байт. Но или алгоритм более сложный (непонятно зачем) или определяется во время считывания какая-то другая величина (например, заканчивается время обработки сообщения — заканчивается считывание). Но не квантовая же механика пролезла в алгоритмы.
Хотя судя по вашему ответу — это вопрос не практического сорта.

AV>>Без этого знания невозможно написать программу обмена данными с портом.


C>Э.. видимо тут имеет место быть неверный протокол обмена. Это знание ненужно и даже вредно. В общем виде, при работе с последовательными устройствами нельзя полагаться на количество принятых данных. Нужно ввести спец. символы в протокол: например 0x1a — конец файла, если протокол символьный и проч.


Мне непонятны элементапрные вещи.
Я посылаю команду, к примеру CONNECT.
Сколько времени надо читать ответ? И когда ответ придет не может ли он окакзаться, к примеру CONN ( а вот ECT 9600 — просто не дочитаться и while в вашем коде закончиться).
Обработка события DataReceived проблему недополучения всего ответа на посланную команду не решает.

C>Ну, или, если иначе совсем никак, читайте данные в цикле, пока не наберете нужное количество..

C>То есть примерно так:

C>
C>byte[] buffer = ...
C>int bytesToRead = ...
C>int readCounter = 0;
C>DateTime startTime = DateTime.Now;
C>while( readCounter < bytesToRead )
C>{
C>  if( DateTime.Now - startTime > timeout )
C>  {
C>    // завершить цикл по таймауту
C>  }
C>  int read = com.Read( buffer, readCounter, bytesToRead - readCounter );
C>  readCounter += read;
C>}
C>



Тогда может случиться так, что количество byteToRead == 0 — истина, только потому что, не хватило времени (времени выполнения цикла) для заполнения буфера, в которм хранятся считываемые байты (а введем Thread.Sleep(кол-во) в цикл — этот цикл бкдет работать большее количество раз). — Никак без времени считывания не обойтись (т.е. какое кол-во устанавливать в Sleep()?).

AV>>Драйвер модема не гружу (работаю с модемом напрямую через порт). Thread.Sleep(500); — закомментировал. Время получения ответа — 0;


C>А я писал про драйвер последовательного порта, а не модема. Драйвер модема для полседовательного порта — просто INF файл, где прописаны AT последовательности для основных операций с модемом: инициализировать, набрать номер, ответить на вызов и проч.


Понятно. Но ведь ващ ответ предполагал, что Sleep(500). А он 0 (закомментирован).
А лампочки на модеме моргают на ATZ не 0mc.

Вообще-то мне надо обмениваться 64-битными пакетами: послать 64-бита, принять ответ — 64 бита. Не знаю может ли быть разрыв в чтении (сосчитал 3 байта, потом пауза, потом остальные 5 байтов).
Re[9]: Что определяет ReadTimeout SerialPort?
От: pr0ff  
Дата: 03.01.07 08:27
Оценка:
Здравствуйте, Andrej-V, Вы писали:

AV>Здравствуйте, pr0ff, Вы писали:


P>>Начните с метода "Read".


AV>Read посмотрел после вашего 1-го ответа. Не могли бы еще более конкретно — где там ответ или подсказка?

Значит смотрите в используемых там методах. Я разве знаю где именно интересующий Вас код? Я не смотрел код SerialPort
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 03.01.07 09:21
Оценка: 2 (1)
Здравствуйте, Andrej-V, Вы писали:


AV>>>А как в NET SerialPort определяет сколько байт прочитать: один, два, десять?

C>>Думаю, что никак.

AV>Я предполагал, что как-то используется какое-то время считывания или считывается определенное кол-во байт. Но или алгоритм более сложный (непонятно зачем) или определяется во время считывания какая-то другая величина (например, заканчивается время обработки сообщения — заканчивается считывание). Но не квантовая же механика пролезла в алгоритмы.

AV>Хотя судя по вашему ответу — это вопрос не практического сорта.

SerialPort ждет _любое_ отличное от нуля количество байт в течении времени заданного ReadTimeout. Если хотя бы один байт пришел, его и вернет. Если не пришло ни одного байта — кинет TimeoutException.


AV>Мне непонятны элементапрные вещи.

AV>Я посылаю команду, к примеру CONNECT.
AV>Сколько времени надо читать ответ? И когда ответ придет не может ли он окакзаться, к примеру CONN ( а вот ECT 9600 — просто не дочитаться и while в вашем коде закончиться).

А зачем вам что-то ждать? Рассмотрим такой сценарий: вы отправили ATDP1234567 и хотите получить CONNECT. До момента отправки ATDP убедитесь что буфер драйвера и буфер SerialPort не содержит никаких данных. То есть прочитайте все оттуда (например, конец предыдущего ответа модема, который был не полностью принят из-за таймаута) и выкиньте: дальше модем сам по себе данных в командном режиме посылать не будет. Отправьте ATDP. Читайте данные из порта в цикле пока не считаете CONNECT. Если прошло некоторое время, а CONNECT не появился, прекращайте читать данные.
Пусть даже остаток CONNECT придет позже — он будет считаться мусором и будет вычитан и отброшен перед посылкой следующей команды модему.

AV>Тогда может случиться так, что количество byteToRead == 0 — истина, только потому что, не хватило времени (времени выполнения цикла) для заполнения буфера, в которм хранятся считываемые байты (а введем Thread.Sleep(кол-во) в цикл — этот цикл бкдет работать большее количество раз). — Никак без времени считывания не обойтись (т.е. какое кол-во устанавливать в Sleep()?).


Тут надо четко определить семантику события "нехватило времени". Как правило это означает: жизнь не удалась — сообщение не пришло; начнем все сначала, отбрасывая все остатки жизни старой.

AV>>>Драйвер модема не гружу (работаю с модемом напрямую через порт). Thread.Sleep(500); — закомментировал. Время получения ответа — 0;


Разрешение таймера, используемого вами для измерения интервала между запросом или ответом — 20ms. Время передачи одного байт на скорости 9600 — около 1ms. Модем вполне мог успеть проинициализироваться и послать ответ за 20ms.

AV>А лампочки на модеме моргают на ATZ не 0mc.


Вообще, есть такая программка: PortMon.
Показывает байтики передаваемые и принимаемые последовательным портом (точнее его драйвером), команды отправляемые ему приложением и проч. В том числе показывает время этих событий, и, насколько я помню, использует таймер с более высоким разрешением для замера интервалов. Попробуйте ее.
Я все это — к тому, что лампочки — критерий не очень надежный. Самое правильное было бы посмотреть осциллогафом на линиях последовательного порта, но неуверен, что это доступно в Вашем случае.

AV>Вообще-то мне надо обмениваться 64-битными пакетами: послать 64-бита, принять ответ — 64 бита. Не знаю может ли быть разрыв в чтении (сосчитал 3 байта, потом пауза, потом остальные 5 байтов).


Вот для этого, как я уже писал, лучше определять конец пакета не по времени, а по специальному символу — концу или началу пакета. Пока его нет читаете или отбрасываете все как мусор. Пришел — читаете пакет.

Успехов,
Леонид.
Re[8]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 03.01.07 15:06
Оценка:
Здравствуйте, curvex, Вы писали:

C>Здравствуйте, Andrej-V, Вы писали:



AV>>>>А как в NET SerialPort определяет сколько байт прочитать: один, два, десять?

C>>>Думаю, что никак.

AV>>Я предполагал, что как-то используется какое-то время считывания или считывается определенное кол-во байт. Но или алгоритм более сложный (непонятно зачем) или определяется во время считывания какая-то другая величина (например, заканчивается время обработки сообщения — заканчивается считывание). Но не квантовая же механика пролезла в алгоритмы.

AV>>Хотя судя по вашему ответу — это вопрос не практического сорта.

C>SerialPort ждет _любое_ отличное от нуля количество байт в течении времени заданного ReadTimeout. Если хотя бы один байт пришел, его и вернет. Если не пришло ни одного байта — кинет TimeoutException.


Леонид. Я не понимаю. Приходит всегда сначала один байт (потом, возможно, 2-й. 3-й и т.д.).
Значит и считываться должен только один байт. А если несколько, то должен быть алгоритм: сколько байт еще подождать, сколько времени. Но время ReadTimeout не выжидается... Похоже на детскую задачку: сколько байт придет в ответ, если ...(а условие не задано). Тогда должно всегда — один (первый).

Следующая программка демонстрирует что ReadTimeout — время, в течение которого возможно считывание с порта. Здесь, наконец, время не меньше ReadTimeout. Но не понимаю куда девается буква A: в ответе на команду ATZ приходит TZ.


using System;
using System.Text;
using System.IO.Ports;
using System.Threading;

namespace ConsoleApplication5
{
class Program
{
static string RecvString(SerialPort com)
{
byte[] MyArray = new byte[1];
string s = "";
System.Text.ASCIIEncoding oEncoder = new ASCIIEncoding();

try
{
while (com.Read(MyArray, 0, 1) == 1) if (s != "") s += oEncoder.GetString(MyArray); else s += "!";
return s;
}
catch (TimeoutException e)
{
return s;
}
catch (Exception e)
{
s = "";
return s;
}
}
static void Main(string[] args)
{
SerialPort com = new SerialPort("COM1", 115200, Parity.None, 8, StopBits.One);
if (com.IsOpen) com.Close();
com.ReadTimeout = 3000;
com.WriteTimeout = 1400;
com.DtrEnable = true;
com.Open();
Thread.Sleep(1500);
com.Write("ATZ\r\n");
// Thread.Sleep(500);
DateTime dt1 = DateTime.Now;
string s = RecvString(com);
TimeSpan ts = DateTime.Now — dt1;
Console.WriteLine("Ответ: "+s+" Время: "+ts.TotalMilliseconds.ToString());
com.Close();
Console.ReadLine();
}
}
}


C>Вообще, есть такая программка: PortMon.

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


Спасибо, но скачать ее сейчас невозможно: что-то сгорело на АТС, еле-еле с 3- 4 -й попытки на 9600 соединяюсь с провайдером и если успеваю до разрыва связи прочитать свою ветку — уже почти счастье.

Спасибо за ответы.
Re[10]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 03.01.07 15:08
Оценка:
Здравствуйте, pr0ff, Вы писали:

P>Здравствуйте, Andrej-V, Вы писали:


AV>>Здравствуйте, pr0ff, Вы писали:


P>>>Начните с метода "Read".


AV>>Read посмотрел после вашего 1-го ответа. Не могли бы еще более конкретно — где там ответ или подсказка?

P>Значит смотрите в используемых там методах. Я разве знаю где именно интересующий Вас код? Я не смотрел код SerialPort

Я слышал, был святой старец, который не вскрывая писем писал ответы.
Re[9]: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 03.01.07 15:40
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:


C>>SerialPort ждет _любое_ отличное от нуля количество байт в течении времени заданного ReadTimeout. Если хотя бы один байт пришел, его и вернет. Если не пришло ни одного байта — кинет TimeoutException.


AV>Леонид. Я не понимаю. Приходит всегда сначала один байт (потом, возможно, 2-й. 3-й и т.д.).

AV>Значит и считываться должен только один байт.

В порт действительно приходит сначала один байт, потом другой и т.д. Но между портом и классом SerialPort есть еще драйвер последовательного порта (и это — без учета FIFO в чипе самого порта), который эти байты накапливает во внутреннем буфере по мере их поступления.. Когда приложением просит вернуть прочитанные байты, он их ему отдает сколько есть на момент запроса. Про свойство ReadTimeout класса SerialPort драйвер последовательного порта ничего не знает.
Поэтому сколько байт будет возвращено — предсказать невозможно. Это зависит от скорости работы устройства, частоте обращений Вашего приложения к драйверу, загрузки системы, фазы луны и т.д.

AV>Следующая программка демонстрирует что ReadTimeout — время, в течение которого возможно считывание с порта.

Здесь, наконец, время не меньше ReadTimeout.

Не очень понял, что значит "время, в течение которого возможно считывание с порта" и какое время не меньше ReadTimeout?

Вы читаете по одному байту. То есть выбор прост: один или ничего. Пока данные от модема поступают, вы вычитываете их по одному байту. После того как был принят последний байт, метод Read ждет три секунды (ReadTimeout) и кидает TimeoutException, по которомы Вы возвращаете принятые ранее данные в виде строки. Соответственно, время исполнения метода действительно всегда будет больше ReadTimout. Однако, как сами видите, такой подход неэффективен, так как выходить надо не только по таймауту, а по наличию принятого валидного ответа. Таймаут — это, как предохранительный клапан, а не штатный механизм работы.

AV>Но не понимаю куда девается буква A: в ответе на команду ATZ приходит TZ.


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

Успехов,
Леонид.
Re[10]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 03.01.07 18:26
Оценка:
Здравствуйте, curvex, Вы писали:

C>В порт действительно приходит сначала один байт, потом другой и т.д. Но между портом и классом SerialPort есть еще драйвер последовательного порта (и это — без учета FIFO в чипе самого порта), который эти байты накапливает во внутреннем буфере по мере их поступления.. Когда приложением просит вернуть прочитанные байты, он их ему отдает сколько есть на момент запроса. Про свойство ReadTimeout класса SerialPort драйвер последовательного порта ничего не знает.

C>Поэтому сколько байт будет возвращено — предсказать невозможно. Это зависит от скорости работы устройства, частоте обращений Вашего приложения к драйверу, загрузки системы, фазы луны и т.д.

Спасибо, ясно.

C>Не очень понял, что значит "время, в течение которого возможно считывание с порта" и какое время не меньше ReadTimeout?


Я имел в виду, что время показываемое программой не меньше 3000.

C>Вы читаете по одному байту. То есть выбор прост: один или ничего. Пока данные от модема поступают, вы вычитываете их по одному байту. После того как был принят последний байт, метод Read ждет три секунды (ReadTimeout) и кидает TimeoutException


Непонятен парадокс: в первой программе Read() не ждет ReadTimeout, а передает управление программе сразу после считывания байтов из буфера. Во второй ждет время ReadTimeout. (И в первом и во втором случае время выводится.)
И еще одна непонятность. Почему в последнем случае вообще срабатывает TimeoutException, а он действительно срабатывает — я добавил проврку:
catch (TimeoutException e)
{
return s+"TimeoutException";
}
Но ведь в буфере не более 3 байтов (ATZ) и условие проверки цикла должно было его прекратить быстрее 3с?
while (com.Read(MyArray, 0, 1) == 1) if (s != "") s += oEncoder.GetString(MyArray); else s += "!";

PortMon попытаюсь скачать ночью.

С уважением, Андрей.
Re[11]: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 03.01.07 18:53
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:


AV>Непонятен парадокс: в первой программе Read() не ждет ReadTimeout, а передает управление программе сразу после считывания байтов из буфера. Во второй ждет время ReadTimeout. (И в первом и во втором случае время выводится.)


Очень просто: в первой программе было так:

int ReadBytes = com.BytesToRead;
com.Read(bytes, 0, ReadBytes);


То есть Вы запрашивали вернуть некоторое количество байт, скорее всего превышающее один. В результате, SerialPort возвращал хотя бы один байт, то есть условия для возникновения TimeoutException не было.

Во втором случае, Вы просите вернуть один и только один байт:

com.Read(MyArray, 0, 1)


При этом более одного байта метод вернуть не может по определению; а менее одного, то есть ноль байт — тоже, так как это условие для TimeoutException.

Иными словами, условие (com.Read(MyArray, 0, 1) == 1) _всегда_ истинно. То есть выход из цикла происходит не по условию, а по TimeoutException.

AV>И еще одна непонятность. Почему в последнем случае вообще срабатывает TimeoutException, а он действительно срабатывает — я добавил проврку:

AV>catch (TimeoutException e)
AV> {
AV> return s+"TimeoutException";
AV> }
AV>Но ведь в буфере не более 3 байтов (ATZ) и условие проверки цикла должно было его прекратить быстрее 3с?
AV>while (com.Read(MyArray, 0, 1) == 1) if (s != "") s += oEncoder.GetString(MyArray); else s += "!";

См выше.

В общем, надо помнить, следующее:

Метод Read может вернуть любое ненулевое количество байт (конечно, непревышающее значение параметра count).
Если метод не смог получить ни одного байта за время ReadTimout, он не вернет 0, а кинет TimeoutException.
Если, все же нужно избежать исключения, необходимо поставить ReadTimout == 0, но тогда, если на момент вызова метода нет принятых байт, то метод выйдет сразу и цикл будет постоянно крутиться в холостую и кушать процессор.

Успехов,
Леонид.
Re[12]: Что определяет ReadTimeout SerialPort?
От: Andrej-V  
Дата: 03.01.07 22:24
Оценка:
Здравствуйте, curvex, Вы писали:

Леонид, спасибо. Ваш последний ответ здорово все прояснил.
Но все же еще непонятны ответы модема (Курьер Роботикс).
Я заметил следующее. Если запустить программу первый раз, то ответа ATZ вообще нет ( и нет при этом знаков '!', которыми заменяются пустые символы).
Т.е. в этом случае возвращается:
Ответ:
TimeoutException Время: 3315,625
При этом щелкает реле в модеме.(TimeoutException присутствует т.к. дополнил возвращаемую строку)

При повторных запусках возврыщается TZ
Ответ:
!TZ TimeoutException Время: 3315,625
при этом реле не щелкает. Т.е. чего-то первая команда ATZ в модеме изменяет.

Если программу немного изменить:
com.Open();
Thread.Sleep(1500);
com.Write("ATZ\r\n");
Thread.Sleep(1500);
com.Write("ATD555555\r\n");
Console.WriteLine(RecvString(com));
com.Close();

Возвращается :
первый раз:
!TD55555
TimeoutException
Но модем трубку не снимает и номер не набирает. И непонятно куда девается ответ на первую команду (ATZ).
При повторных запусках возвращается:
!TZ
ATD55555
TimeoutException
(трубка по прежнему не снимается и номер не набирается)

PortMon сейчас постараюсь скачать.
Андрей.
Re[13]: Что определяет ReadTimeout SerialPort?
От: curvex Россия  
Дата: 03.01.07 22:55
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:

AV>Но все же еще непонятны ответы модема (Курьер Роботикс).



Тут возможна проблема с готовностью модема принимать данные от драйвера, и готовностью драйвера (или чипа посл.порта) получать данные от модема.
Для решения этой проблемы служит свойство Handshake класса SerialPort. По умолчанию, как написано в MSDN, это свойство установлено в None, то есть драйвер посылает в модем все имеющиеся у него байты невзирая на готовность модема. Поэтому данные могут теряться.
Готовность модема принимать данные от драйвера определяется сигналом RTS. Есть еще сигнал CTS, но уже к стыду своему забыл зачем, вспоминать — лень, ибо поздно уже и спать охота. Но, если интересно, Вы сами можете поискать в инете.
Но пока подробности — и не к чему. Драйвер и даже чип может взять на себя управление этими сигналами, если выставить правильный режим хэндшейкинга. А именно: значение Handshake.RequestToSend. В этом случае драйвер порта, а скорее даже его чип будет сам следить за сигналом RTS и не посылать данных в модем, если он не готов. Это режим аппаратного хендшейкинга. Есть еще программный режим, когда готовность сторон определяется не сигналами на линиях, а символами XON/XOFF вставляемым драйвером в поток данных. На сколько помню, модем можно переключить в один из режимов, но по умолчанию после инциализации, используется, скорее всего, аппаратный хендшейкинг. Лучше уточнить в доке на модем.
В общем, попробуйте установить свойство Handshake в Handshake.RequestToSend.

Успехов,
Леонид.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.