Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Обратно COMM-порт  (Прочитано 12700 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« : 20-07-2006 05:54 » 

Время от времени приходиться работать с COMM-портом по этому решил написать библиотеку для работы с ним. Надоело всегда переписовать код.

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

Использую примерно следующий код:
for( ; ; )
{
   printf("FOR Start\n");
   if( !WaitCommEvent(hPort,&dwEvtMask,&ov) )
   {
      DWORD error;

      error = GetLastError();
      printf("WaitCommEvent return FALSE\n");
      
      if( error == ERROR_IO_PENDING )
      {
         printf("GetLastError return ERROR_IO_PENDING\n");
      }
      else
      {
         printf("GetLastError return %u\n",error);
      }
      GetOverlappedResult(hPort,&ov,&temp,TRUE);
   }
   ReadFile(hPort,buff,15,&temp,&ov);
   if( ov.InternalHigh )
   {
      printf("Read port char = %u\n",ov.InternalHigh);
      buff[ov.InternalHigh] = 0;
      printf("buff = %s\n",buff);
         
      if( buff[0] == 'Q' ) return;
   }
   else printf("Read port char = 0\n");
   printf("FOR end\n\n");
}


Если я посылаю один символ, тогда все ОК:
FOR Start
WaitCommEvent return FALSE
GetLastError return ERROR_IO_PENDING
Read port char = 1
buff = e
FOR end


Если посылаю четыре символа, инициализируется считывание из порта (как и положенно) но тут же срабатывает следующее считывание из порта (хотя он уже пустой), а ReadFile говорит что считано НУЛЬ символов (буфер пустой).
FOR Start
WaitCommEvent return FALSE
GetLastError return ERROR_IO_PENDING
Read port char = 4
buff = 1111
FOR end
FOR Start
WaitCommEvent return FALSE
GetLastError return ERROR_IO_PENDING
Read port char = 0
FOR end


И еще одна странность, если я посылаю например 25 символов то ReadFile считывает только по 14 символов (вот тут я подозреваю вступает в игру мое железо) но НУЛЕВОЙ буффер всеравно проскакивает между посылками.
FOR Start
WaitCommEvent return FALSE
GetLastError return ERROR_IO_PENDING
Read port char = 14
buff = cccccccc000000
FOR end
FOR Start
WaitCommEvent return FALSE
GetLastError return ERROR_IO_PENDING
Read port char = 0
FOR end
FOR Start
WaitCommEvent return FALSE
GetLastError return ERROR_IO_PENDING
Read port char = 14
buff = 00000011111111
FOR end


Меня больше всего волнует считываемый ReadFile буффер из COMM-порта, максимальный размер его 14 байт, это связанно с железом или так работает Windows?

* read_port.zip (1.33 Кб - загружено 861 раз.)
« Последнее редактирование: 14-12-2007 14:46 от Алексей1153++ » Записан
acc15
Гость
« Ответ #1 : 21-07-2006 00:51 » 

1. InternalHigh
Цитата
Reserved for operating system use. This member, which specifies the length of the data transferred, is valid when the GetOverlappedResult function returns TRUE.
У тебя даже не вижу проверки что GetOvpResult возвращает TRUE... Да и вообще это использовать не надо...

Используй  lpNumberOfBytesRead (у тебя переменная temp)
Цитата
[out] A pointer to the variable that receives the number of bytes read.
2.
Код:
if( ov.InternalHigh )
{
  printf("Read port char = %u\n",ov.InternalHigh);
  buff[ov.InternalHigh] = 0;
  printf("buff = %s\n",buff);

       
  if( buff[0] == 'Q' ) return;
}
else printf("Read port char = 0\n");
Превращается в:
Код:
printf("Read port char = %u\n",temp);
if (temp>0 && temp < 100)
{
  buff[temp] = 0;
  printf("buff = %s\n",buff);
     
  if( buff[0] == 'Q' ) return;
}
3.
Цитата
И еще одна странность, если я посылаю например 25 символов то ReadFile считывает только по 14 символов (вот тут я подозреваю вступает в игру мое железо) но НУЛЕВОЙ буффер всеравно проскакивает между посылками.
Ты сам написал чтоб считывалось 15 символов
ReadFile(hPort,buff,15,&temp,&ov);

4. Самое главное...
ReadFile - тоже становится асинхронной, с чего ты взял что он всегда возращает TRUE? Короче
Цитата
If hFile is opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the read operation starts at the offset that is specified in the OVERLAPPED structure, and ReadFile may return before the read operation is complete. In this scenario, ReadFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING, which allows the calling process to continue while the read operation completes. The event specified in the OVERLAPPED structure is set to the signaled state when the read operation is complete, and then the caller must adjust the position of the file pointer.

5. Возможно также такое что размер внутр. буфера был равен 14, отсюда такие ошибки и потери данных... При инициализации порта нужно указать требуемые размеры буферов при помощи SetupComm(); т.е. к примеру
void init_port(void)
{
  ...
  SetupComm(hPort,1024,1024);
  ...
}

6. Если тебе нужно узнать сколько байт информации хранится на данный момент в буфере (т.е. то что ещё не было считано ReadFile, но уже считано драйвером из порта) используй ClearCommError(); (в структуре COMSTAT поле cbInQue)

Железо тут абсолютно не причем (я имею ввиду компьютер, а не подключаемое устройство).
« Последнее редактирование: 14-12-2007 14:15 от Алексей1153++ » Записан
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 21-07-2006 05:46 » 

Цитата
У тебя даже не вижу проверки что GetOvpResult возвращает TRUE... Да и вообще это использовать не надо...
Это сделанно для упрошения приведенного кода.
Функция GetOverlappedResult используется что бы перевести поток в состояние покоя до поступления данных в порт (т.к. заранее не известно когда будут поступать данные).

Цитата
Используй  lpNumberOfBytesRead (у тебя переменная temp)
Я открываю порт с флагом FILE_FLAG_OVERLAPPED поэтому функция ReadFile всю информацию о прочитанных байтах возвращает через структуру OVERLAPPED, а по адрессу lpNumberOfBytesRead просто записывается НУЛЬ (в lpNumberOfBytesRead ножно даже NULL записывать, но для совместимости с Win95 я этого не делаю).

Цитата
Ты сам написал чтоб считывалось 15 символов
ReadFile(hPort,buff,15,&temp,&ov);
Размер передоваемого буффера значения не имет (покрайней мере на моей машине), если он меньше 14 то заполняется по его размеру, если больше только по 14 байт. По данной пречине я и прикрепил тестовый пример (read_port.zip) чтобы попробовали на своей машине и посмотрели по сколько байт извлекается из буффера порта.

Цитата
Возможно также такое что размер внутр. буфера был равен 14, отсюда такие ошибки и потери данных...
В том то и дело, что потерь данных нет, только иногда проскакивает между входными данными, буфер приема НУЛЕВОГО размера.

Цитата
При инициализации порта нужно указать требуемые размеры буферов при помощи SetupComm()
Я тоже сначало думал, что этим способом можно изменить размер входного буфера. Но функция GetCommProperties через структуру COMMPROP сообщила, что мой драйвер порта не поддерживает данный способ
Цитата
dwMaxTxQueue
Specifies the maximum size, in bytes, of the driver's internal output buffer. A value of zero indicates that no maximum value is imposed by the serial provider.
dwMaxRxQueue
Specifies the maximum size, in bytes, of the driver's internal input buffer. A value of zero indicates that no maximum value is imposed by the serial provider.
Да и вообще, функция SetupComm носит рекомендательный характер и драйвер может просто откланить эти данные. Короче, данный способ у меня не дал результатов.

Цитата
Если тебе нужно узнать сколько байт информации хранится на данный момент в буфере (т.е. то что ещё не было считано ReadFile, но уже считано драйвером из порта) используй ClearCommError(); (в структуре COMSTAT поле cbInQue)
Вот это интересно, но в моем случае когда максимальное количество байт возврашаемых comm-портом равным 14, нет смысла ее использовать.

Я поэтому и прекрепил тестовый пример, что бы погонять его и посмотреть поведение системы на разных машинах. Кстати, на работе машина ведет себя аналогично.
« Последнее редактирование: 14-12-2007 14:48 от Алексей1153++ » Записан
Alf
Гость
« Ответ #3 : 21-07-2006 07:09 » 

Уж больно подозрительная цифра - 14. Весьма напоминает размер внутреннего буфера микросхемы 16550:



Думаю, нужно копать в этом направлении.

* Com.gif (12 Кб - загружено 4359 раз.)
Записан
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 21-07-2006 07:32 » 

Да, вот это уже похоже на правду, ведь в основном у микроконтроллеров используется UART а потом через микросхему ( типа MAXIM(max232) ) сигнал переводиться в RS-232 и на оборот.

Может кто подскажет, как программно узнать размер этого буффера и способы изминения его?

( А нужно ли это  Здесь была моя ладья... )
Записан
Alf
Гость
« Ответ #5 : 21-07-2006 07:52 » new

( А нужно ли это  Здесь была моя ладья... )

IMHO - совершенно ни к чему.

Буфер FIFO в UART 16550A и совместимых нужен, чтобы следующий принятый байт не затирал предыдущий, если по каким-то причинам его не успели считать. Больше 14 байт его сделать все равно не получится, это аппаратный предел. Делать меньше не вижу смысла, растет риск потери данных.

С COM-портами давненько уж не приходилось работать, деталей не помню. Но помнится, что этот самый буфер никоим образом мне не мешал.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines