Работа с COM портом - C++

Подключаем наши девайсы к компьютеру. Обсуждаются: порты, протоколы, драйвера, языки программирования и т.д.
Ответить
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

СЦБист писал(а):

Код: Выделить всё

GetOverlappedResult(handle, &Overlap, &temp, true) 
И какое число было в temp? Ситуация дописывания в буффер после вызова Write и до завершения передачи исключена? Не может так быть, что вы на самом деле заказали [поспешили, ага] отсылку строки длиной 176 байт, но "за время пути собака смогла подрасти" на 10 байт (другой поток подгадил, к примеру - они это любят) и пост-мортем вы видите не то, что должно быть по вашему убеждению? Оттрассируйте длину строки на момент передачи. Проверьте этот-же код на RS232 порту другого типа - FTDI, CP2101, PL2303, честный RS232 - чтобы исключить проблемы в системных драйверах. На той стороне что видно - "обрез" или все данные?
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

в temp к-во байт которые были переданы, а именно 186.

получается приемник тормозит ?

у меня ПК сам выдает и сам же эти байты принимает. :shock:
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

СЦБист писал(а):получается приемник тормозит ?
Вы пытаетесь синхронизировать приём по событию завершения передачи? Ну тут последние байты могут быть ещё вообще даже не "в линии" а в буфферах порта. Да и будучи переданными, кмк, у них есть целая вечность до того как доберутся до вашего приёмного буффера и вас известят о сём событии. Синхронизировать надо по событию завершения приёма. Но там судя по всему у вас есть свои нюансы. ;) А если длина пакета недетерминирована - читайте по байту, подсовывая Read-у каждый раз инкрементированный указатель в буффере приёма пока не встретится символ-терминатор. Нету терминатора - отсылайте strlen(buffer) + 1 и ждите появления в принимаемом потоке нуля. После чего быстренько обрабатываете пакет, возвращаете указатель чтения на начало буффера и вновь заряжаете Read.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

Нашел в сети этот код чтения
  • Код: Выделить всё

    //---------------------------------------------------------------------------
    
    #define BUFSIZE 255     //ёмкость буфера
    
    unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE]; //приёмный и передающий буферы
    
    //---------------------------------------------------------------------------
    
    HANDLE COMport;		//дескриптор порта
    
    //структура OVERLAPPED необходима для асинхронных операций, при этом для операции чтения и записи
    //нужно объявить разные структуры
    //эти структуры необходимо объявить глобально, иначе программа не будет работать правильно
    OVERLAPPED overlapped;		//будем использовать для операций чтения (см. поток ReadThread)
    OVERLAPPED overlappedwr;       	//будем использовать для операций записи (см. поток WriteThread)
    //---------------------------------------------------------------------------
    
    //главная функция потока, реализует приём байтов из COM-порта
    {
     COMSTAT comstat;		//структура текущего состояния порта, в данной программе используется
    				//для определения количества принятых в порт байтов
     DWORD btr, temp, mask, signal;	//переменная temp используется в качестве заглушки
    
     //создать сигнальный объект-событие для асинхронных операций
     overlapped.hEvent = CreateEvent(NULL, true, true, NULL);
    
     //установить маску на срабатывание по событию приёма байта в порт
     SetCommMask(COMport, EV_RXCHAR);           		
     while(условие)	//пока поток не будет прерван, выполняем цикл
      {
       //ожидать события приёма байта (это и есть перекрываемая операция)
       WaitCommEvent(COMport, &mask, &overlapped);
    
       signal = WaitForSingleObject(overlapped.hEvent, INFINITE);	//приостановить поток до прихода байта
       if(signal == WAIT_OBJECT_0)				        //если событие прихода байта произошло
        {
         if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась
    								//перекрываемая операция WaitCommEvent
          if((mask & EV_RXCHAR)!=0)				//если произошло именно событие прихода байта
           {
            ClearCommError(COMport, &temp, &comstat);		//нужно заполнить структуру COMSTAT
            btr = comstat.cbInQue;                          	//и получить из неё количество принятых байтов
            if(btr)                         			//если действительно есть байты для чтения
            {
             ReadFile(COMport, bufrd, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
            }
           }
        }
      }
     CloseHandle(overlapped.hEvent);		//перед выходом из потока закрыть объект-событие
    }
    
    //---------------------------------------------------------------------------
зачем после

WaitCommEvent(COMport, &mask, &overlapped);

нужна

signal = WaitForSingleObject(overlapped.hEvent, INFINITE);

разве она идет не после

ReadFile(COMport, bufrd, btr, &temp, &overlapped);
Реклама
Эиком - электронные компоненты и радиодетали
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

СЦБист писал(а):Нашел в сети этот код чтения
А это разве не то же самое, на что тут в первых ответах ссылку давали? Там после кода идёт пару страниц разжёвывания каждой строчки.
СЦБист писал(а):зачем после

WaitCommEvent(COMport, &mask, &overlapped);

нужна

signal = WaitForSingleObject(overlapped.hEvent, INFINITE);

разве она идет не после

ReadFile(COMport, bufrd, btr, &temp, &overlapped);
Автора спрашивать надо - по мне так атавизм от предыдуших попыток поработать в блокируюшем режиме. Вообще смысл использования OVERLAPPED режима в том, что мы заказали операцию с портом и пошли заниматься своими делами, потом вернулись проверили событие завершения - т.е. даже лишних потоков заводить не надо - всё в одном. А вот этих самых "делов" может быть всё что угодно - а если сразу суспендим исполнение в WaitFor*Object*(..., INFINITE) после запроса записи/чтения - к чему заморочки с OVERLAPPED? Открываем в блокирующем режиме и получаем то же самое.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

лично я склоняюсь к тому что

signal = WaitForSingleObject(overlapped.hEvent, INFINITE);

должно идти после

ReadFile(COMport, bufrd, btr, &temp, &overlapped);


как в примере с операцией записи.

_____ :o

правда ли что WaitCommEvent(handle, &mask, &Overlap_1);

сбрасывает Overlap_1.hEvent в не сигнальное состояние.
__________________
Реклама
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение Myp3ik »

Так при записи мы пишем в файловый поток и ждем сигнального события что данные ушли и можно писать новые.
При чтении же все наоборот, мы ждем сигнала о том что в буфере есть данные и читаем иx.
Иван Сусанин - первый полупроводник :solder:
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

для надежности после

ReadFile(COMport, buffer, btr, &temp, &overlapped); //прочитать байты из порта в буфер программы

поставил

signal = WaitForSingleObject(overlapped.hEvent, INFINITE);

так как и операция чтения у нас асинхронная.


повторюсь


правда ли что WaitCommEvent(handle, &mask, &Overlap_1);

сбрасывает Overlap_1.hEvent в не сигнальное состояние.
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение Myp3ik »

цитата из руководства по моей ссылке
В данном случае перекрываемую операцию активирует функция WaitCommEvent. Она запускает ожидание события порта, заданного маской, и, если событие не наступает немедленно, передаёт управление обратно программе и возвращает FALSE, а система устанавливает объект-событие в несигнальное состояние.
Иван Сусанин - первый полупроводник :solder:
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

и тест тоже показывает что WaitCommEvent сбрасывает overlapped.hEvent в не сигнальное

состояние. а WaitForSingleObject ждет.

____________

что скажите что после

ReadFile(COMport, buffer, btr, &temp, &overlapped);

поставил

WaitForSingleObject(overlapped.hEvent, INFINITE);

чтение тоже ведь асинхронное. думаю не помешает. :music:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

СЦБист писал(а): signal = WaitForSingleObject(overlapped.hEvent, INFINITE);

должно идти после

ReadFile(COMport, bufrd, btr, &temp, &overlapped);
Не должно. Данный конкретный вызов Wait* в цитируемом коде относится не к Read а к WaitCommEvent. Read там вообще не использует overlapped возможности - тупо читает столько байт, сколько имеется в очереди.
СЦБист писал(а): правда ли что WaitCommEvent(handle, &mask, &Overlap_1);

сбрасывает Overlap_1.hEvent в не сигнальное состояние.
"If the overlapped operation cannot be completed immediately, the function returns FALSE and the GetLastError function returns ERROR_IO_PENDING, indicating that the operation is executing in the background. When this happens, the system sets the hEvent member of the OVERLAPPED structure to the not-signaled state before WaitCommEvent returns, and then it sets it to the signaled state when one of the specified events or an error occurs. The calling process can use one of the wait functions to determine the event object's state and then use the GetOverlappedResult function to determine the results of the WaitCommEvent operation. "

Т.е. если операция ещё не завершена - то система выставит событие в несигнальное состояние. И [система] включит его как только заказанное событие возникнет. Т.е. как следует из контекста - сбрасывается оно только для того чтобы иметь возможность поведать миру о наступлении события про которое спросили посредством WaitCommEvent.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

СЦБист писал(а): что скажите что после

ReadFile(COMport, buffer, btr, &temp, &overlapped);

поставил

WaitForSingleObject(overlapped.hEvent, INFINITE);

чтение тоже ведь асинхронное. думаю не помешает.
В более идеальном мире чем тот, что окружает нас - совершенно излишняя предосторожность - потому как перед чтением мы осведомляемся о количестве наличиных в очереди байт - т.е. блокировка не возможна. Но в качестве эдакого ASSERT-а - да, не помешает. :)
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

вот именно ReadFile тоже сбрасывает событие.

а устанавливает лишь после чтения.

так что

WaitForSingleObject не помешает.

...


будет у меня два WaitForSingleObject

одно после WaitCommEvent другое после ReadFile
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение Myp3ik »

а смысл. ведь у нас событие в сигнальном состоянии и WaitForSingleObject по идее просто не сработает. или как оно у Вас ?
Иван Сусанин - первый полупроводник :solder:
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

В общем вот мой проект класса.

Посмотрите что не так и сразу мне говорите.
Вложения
COM.cpp
(9.05 КБ) 277 скачиваний
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

СЦБист писал(а):Посмотрите что не так.
Для копирования строчек с контролем размера есть стандартная strncpy. В нынешней реализации если попытаетесь записать ровно 1000 байт - вылетите за пределы массива и - либо подгадите нулём buffer_write, либо наползёте на голову структуры read.overlapped.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

Вы наверное не поняли сути моего класса.

У меня с контроллера приходит посылка размером 100 байт и это четко прописано.

стандартная strncpy мне не подходит , так как мне надо копировать определенное число байт без

терминала.

Я хочу знать что глобально не так. :oops:

_____________________

Изменил поток чтения. ReadFile вызываю , когда в буфере приема именно 100 байт. :o

Код: Выделить всё


unsigned __stdcall ReadThread(void *lpParam)
{
	ClassCOM::DataCom &data = *(ClassCOM::DataCom *)lpParam; 

	OVERLAPPED &overlapped = data.overlapped;
	HANDLE COMport = data.COMport;
	char *buffer_read = data.buffer; 
	HANDLE hEvent = data.hEvent;

	int counter = 0;

	COMSTAT comstat;		
	DWORD btr, temp, mask, signal;	
	
	SetCommMask(COMport, EV_RXCHAR);  //установить маску        
	
	while(1)				    
	{
		WaitCommEvent(COMport, &mask, &overlapped);               	
		
		signal = WaitForSingleObject(overlapped.hEvent, INFINITE);	
		
		if(signal == WAIT_OBJECT_0)				       
		{
			if(GetOverlappedResult(COMport, &overlapped, &temp, true))
				if((mask & EV_RXCHAR)!=0)					
				{
					ClearCommError(COMport, &temp, &comstat);		
					btr = comstat.cbInQue;                          	
					
					if (btr >= 100) 
					{
						ReadFile(COMport, buffer_read, btr, &temp, &overlapped);    
						
						signal = WaitForSingleObject(overlapped.hEvent, INFINITE);
								
						if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlapped, &temp, true)))
						{
							WaitForSingleObject(hEvent, INFINITE); //начало критического участка
									
							data.flag = true; //установить флаг чтения
									
							SetEvent(hEvent); //конец критического участка
						}
					}
					
				}
		}
	}
}
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение Myp3ik »

На C# через WinAPI делал чтение так:

Код: Выделить всё

private static void ReadThreadFunc()
        {
            _nativeOvRd.EventHandle = CreateEvent(IntPtr.Zero, true, true, null);
            _nativeOvWr.EventHandle = CreateEvent(IntPtr.Zero, true, true, null);

            SetCommMask(_hPortHanle, EvRxChar);

            _readingThreadDisable = false;

            while (!_readingThreadDisable)
            {
                uint mask;
                // Запускаем ожидание события прихода данных
                WaitCommEvent(_hPortHanle, out mask, GetNativeOvPtr(_nativeOvRd));

                // Приостанавливаем поток пока объект-событие не перейдет в сигнальное состояние
                // по приходу данных в порт
                var signal = WaitForSingleObject(_nativeOvRd.EventHandle, Infinite);

                if (_readingThreadDisable) break;

                uint temp;
                // Проверяем корректность события вызвавшего возобновление работы потока
                if (signal != WaitObject0 || !GetOverlappedResult(_hPortHanle, ref _nativeOvRd, out temp, true) || (mask & EvRxChar) == 0) continue;
                
                ComStat comstat;
                uint flags;
                // Считываем количество байт в приемном буфере
                ClearCommError(_hPortHanle, out flags, out comstat);
                var bytesNum = comstat.cbInQue;

                if (bytesNum <= 0) continue;
                var dataBuffer = new byte[bytesNum];

                // Считываем данные из приемного буфера
                if (!ReadFile(_hPortHanle, dataBuffer, bytesNum, out temp, ref _nativeOvRd)) continue;

                CanProcessing.PacketProcessing(dataBuffer);
            }

            // Закрываем объект-событие
            CloseHandle(_nativeOvRd.EventHandle);
        }
В результате сделал через встроенный класс SerialPort, который по сути обёртка над WinAPI. Получилось намного компактнее и надежней.
Иван Сусанин - первый полупроводник :solder:
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1337
Зарегистрирован: Сб июн 09, 2012 02:14:11
Откуда: ХАРЬКОВ

Сообщение СЦБист »

Myp3ik писал(а):На C# через WinAPI делал чтение так:

.

с шарпом увы не в кентах. :twisted:

______________________

Вот еще не поточная версия класса. Поточный вариант сильно жрет процессор.
Вложения
Class.cpp
(5.46 КБ) 260 скачиваний
Мучитель микросхем
Аватара пользователя
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Сообщение Myp3ik »

Если поточный вариант забирает 1 поток процессора даже когда не передаются данные, тогда WaitForSingleObject не работает.
Иван Сусанин - первый полупроводник :solder:
Ответить

Вернуться в «Интеграция с ПК»