Hmm 0 March 28, 2012 Posted March 28, 2012 · Report post ... классный класс. Да неплохой. Использовал под C++Builder что-бы не нарушать лицензионного соглашения. Quote Share this post Link to post Share on other sites More sharing options...
dm37 0 September 26, 2016 Posted September 26, 2016 (edited) · Report post в архиве cport310 есть файл readme.txt всё (правда по английски) написано а если кратко, то так (на примере Delphi 7): - открываем в Delphi файл cport-3.10\sources\CPortLib7.dpk - в открывшемся окне "Package - CPortLib7.dpk" жмём кнопку "Compile" - закрываем окно "Package - CPortLib7.dpk", но запрос "Сохранить" жмём "Нет" - открываем в Delphi файл cport-3.10\sources\DsgnCPort7.dpk - в открывшемся окне "Package - DsgnCPort7.dpk" жмём кнопку "Compile", потом "Install" - закрываем окно "Package - DsgnCPort7.dpk", но запрос "Сохранить" жмём "Нет" - проверяем на вкладке компонентов наличие вкладки "CPortLib" - все файлы cport которые будет требовать компилятор копируем из cport-3.10\sources\ в C:\Program Files\Borland\Delphi7\Projects\Bpl\, как правило это *.dcu, *.dfm, *.pas, CPort.inc, CPortImg.res вроде всё Edited September 26, 2016 by dm37 Quote Share this post Link to post Share on other sites More sharing options...
paskal 1 January 28, 2019 Posted January 28, 2019 · Report post Добрый день! Пишу программу для асинхронного приема в ком порт. Прием в целом идет успешно, но возникает глюк при смене порта. То есть при асинхронном ожидании приема, порт закрывается, открывается другой, создается новый поток. Ну в общем все действия которые были с предыдущим портом. В этот момент и возникает дефект. Эксперименты и отладка показали что проблема возникла от того что поток висит в несигнальном состоянии после вызова WaitForSingleObject. Из за этого поток не завершается, и по цепочке идут другие ошибки. Итак вопрос. Как можно принудительно завершить ожидание по WaitForSingleObject? Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 22 January 29, 2019 Posted January 29, 2019 · Report post 10 часов назад, paskal сказал: Итак вопрос. Как можно принудительно завершить ожидание по WaitForSingleObject? Заменить WaitForSingleObject на WaitForMultipleObjects. В список ожидаемых объектов добавить свой event, его сигналить при необходимости завершить работу потока. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 309 January 29, 2019 Posted January 29, 2019 · Report post 22 часа назад, paskal сказал: Итак вопрос. Как можно принудительно завершить ожидание по WaitForSingleObject? Послать ему event конечно же. А вы чего ожидали? Ещё можно таймаут установить. Quote Share this post Link to post Share on other sites More sharing options...
paskal 1 January 29, 2019 Posted January 29, 2019 · Report post 3 hours ago, jcxz said: Послать ему event конечно же. А вы чего ожидали? Ну я и посылал через SetEvent. Ничего не произошло. И я поискал информацию - выходит и не должно. Пока поток спит в WaitForSingleObject, сигнальное состояние нельзя установить. Заколдованный круг. Quote Share this post Link to post Share on other sites More sharing options...
paskal 1 January 29, 2019 Posted January 29, 2019 · Report post 15 hours ago, AHTOXA said: Заменить WaitForSingleObject на WaitForMultipleObjects. В список ожидаемых объектов добавить свой event, его сигналить при необходимости завершить работу потока. А можно подробнее как завершать поток с использованием WaitForMultipleObjects ? Quote Share this post Link to post Share on other sites More sharing options...
V_G 22 January 30, 2019 Posted January 30, 2019 · Report post Я делал из MFC ручками без WaitForMultipleObjects и аналогичных функций: 1. Заводил глобальный указатель на переменную lpvNeedReceive - флаг управления потоком, № Com-порта (инициировал lpvNeedReceive при открытии порта). 2. В потоке приема данных заводил цикл while(*(UINT *)lpvNeedReceive != 0), в котором делаю WaitCommEvent - ожидание одного из событий EV_RXCHAR|EV_TXEMPTY|EV_BREAK. 3. По EV_RXCHAR принимаю информацию обычным образом. 4. Если нужно закрыть порт и приемный поток, в основном потоке делаю *lpvNeedReceive = 0, отправляю в порт ничего не значащий нулевой байт и жду изменения *lpvNeedReceive. 5. Приемный поток выходит из WaitCommEvent и из цикла по п.2, закрывает компорт и в конце своей работы устанавливает *lpvNeedReceive = 0xFF. 6. Основной поток закрывает приемный поток Quote Share this post Link to post Share on other sites More sharing options...
jcxz 309 January 30, 2019 Posted January 30, 2019 · Report post 10 часов назад, paskal сказал: Ну я и посылал через SetEvent. Ничего не произошло. И я поискал информацию - выходит и не должно. Пока поток спит в WaitForSingleObject, сигнальное состояние нельзя установить. Вы сами то поняли смысл того что написали? По вашему выходит что WaitForSingleObject вообще нельзя использовать. Если поток ждёт event-а в WaitForSingleObject, то естественно он должен переходить в активное состояние после того как кто-то сделает SetEvent для этого объекта. Или истечёт таймаут WaitForSingleObject. Ищите где накосячили. 1 час назад, V_G сказал: отправляю в порт ничего не значащий нулевой байт и жду изменения *lpvNeedReceive. Зачем такие кривые костыли? Достаточно просто установить сигнальное состояние для event-а вручную и всё. Quote Share this post Link to post Share on other sites More sharing options...
V_G 22 January 30, 2019 Posted January 30, 2019 · Report post 28 минут назад, jcxz сказал: Зачем такие кривые костыли? Достаточно просто установить сигнальное состояние для event-а вручную и всё. Согласен, но софт компорта писался лет 20 назад (почти сразу же, как появилась многопоточность) и с тех пор особо не менялся, бо работает. Я и сейчас-то не все виндовые функции знаю наизусть, а тогда - и подавно. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 22 January 30, 2019 Posted January 30, 2019 · Report post 10 часов назад, paskal сказал: А можно подробнее как завершать поток с использованием WaitForMultipleObjects ? Создайте ещё один Event: HANDLE terminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL); Замените свой WaitForSingleObject(oldEvent, ...) на HANDLE events[] = {oldEvent, terminateEvent}; WaitForMultipleObjects(2, events,...); И вы сможете в любой момент вывести поток из ожидания, взведя terminateEvent. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 309 January 30, 2019 Posted January 30, 2019 · Report post 24 минуты назад, V_G сказал: Согласен, но софт компорта писался лет 20 назад (почти сразу же, как появилась многопоточность) и с тех пор особо не менялся, бо работает. Я и сейчас-то не все виндовые функции знаю наизусть, а тогда - и подавно. Тоже писалось ровно 10 лет назад, использовалось во множестве проектов: Спойлер // Receiver thread //--------------------------------------------------------------------------- void __fastcall TCommRxThread::Main() { DWORD i, ii, j; do { EnterCriticalSection(&cs); terminate = amount = 0; LeaveCriticalSection(&cs); if (purge) { purge = false; SetEvent(evPurge); } SetEvent(hServiceEvent); while (1) { j = 0; do { ReadFile(hComm, buf + posIObuf + j, bufSize - j, &i, &ovr); if (!terminate) ii = GetOverlappedResult(hComm, &ovr, &i, true); if (terminate) break; if (!ii) { if (OnError) Synchronize(OnError); i = 0; } j += i; } while (!j || (j < bufSize && amount)); WaitForSingleObject(hServiceEvent, INFINITE); if (terminate) break; EnterCriticalSection(&cs); amount = j; posServBuf = posIObuf; posIObuf ^= bufSize; LeaveCriticalSection(&cs); if (OnReady) Synchronize(OnReady); } PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR); } while (purge); } uint __fastcall TCommRxThread::Read(char *data, uint size) { EnterCriticalSection(&cs); if (size >= amount) { SetEvent(hServiceEvent); size = amount; } memcpy(data, buf + posServBuf, size); posServBuf += size; amount -= size; LeaveCriticalSection(&cs); return size; } void __fastcall TCommRxThread::Purge() { if (terminate) return; purge = true; EnterCriticalSection(&cs); Terminate(); LeaveCriticalSection(&cs); WaitForSingleObject(evPurge, INFINITE); } void __fastcall TCommThread::Terminate() { terminate = true; SetEvent(hServiceEvent); SetEvent(ovr.hEvent); } class TCommRxThread : public TCommThread { ... }; Quote Share this post Link to post Share on other sites More sharing options...
klod 0 October 7, 2022 Posted October 7, 2022 · Report post Всем добрых суток ! У меня проблема приема данных по СОМ порту. Данные выдаются пакетом из устройства в порт ПК каждые 100 мс размером 2500 байт. Но происходит потеря данных, вернее последовательность данных при чтении буфера порта нарушается, скажем так, последний номер пакета был с номером 2000, а при следующем чтении порта начинается не 2001, а ,например, 2020. Настройка порта следующая: 8 бит; Контроль четности - нет; Число стоп бит - 1; Скорость обмена -460800; Таймауты по умолчанию, кроме MAXWORD все нули. Размер буфера порта 4096, увеличивал до 15000. В программе сначала использовал библиотеку Async32, пробовал делать свой поток с функциями API (ReadFile), тут результат еще хуже, чтение производится, то 14000 байт, то 45 байт, что приводит к потере. Чтение происходит по событию RXchar. Выкладываю код в потоке. procedure MyThread.execute; var S: string; i:integer; begin //inherited; OverRead.hEvent:=CreateEvent(nil,True,True,nil); while not MyThr.Terminated do begin WaitCommEvent(FHandle,Mask,@OverRead); signal:=WaitForSingleObject(OverRead.hEvent,infinite); if(signal=Wait_Object_0) then begin if GetOverlappedResult(FHandle,OverRead,Temp,true) then begin if((Mask and EV_RXchar)<>0) then begin ClearCommError(FHandle,Temp,@ComStat); Btr:=ComStat.cbInQue; if Btr<>0 then begin ReadFile(FHandle,Buffer,SizeOf(Buffer1),Temp,@OverRead); end; end; end; end; Еще один вариант. Использовал библиотеку API для устройств FTDI. Функция в потоке. Function Drive:Boolean; var B:Byte; Sgn,RR,BT : DWORD; CS : TComStat; i:integer; ReadOL : TOverLapped; begin while not FReadThread.Terminated do begin FillChar(ReadOL,SizeOf(ReadOL),0); ReadOL.hEvent:=CreateEvent(nil,True,True,nil); FT_W32_ReadFile(FHandle,B,1,RR,@ReadOL); Sgn:=WaitForSingleObject(ReadOL.hEvent,INFINITE); Result:=False; if (Sgn=WAIT_OBJECT_0) then begin if GetOverlappedResult(FHandle,ReadOL,BT,False) then begin PutS(inp,B); // очередной байт сообщения end; end; FT_W32_CloseHandle(ReadOL.hEvent); end; end; Здесь картина несколько иная. Если читаю в буфер, то прием хоть и фиксированный, но потери такие же как описал выше. А если читаю по одному байту, то читается как надо, но постоянно до определенного момента (около 4000 пакетов принимаются как надо), потом идут потери данных, вероятно буфер драйвера все-же переполняется. Хотелось бы узнать, реально читать данные при такой скорости и настройке без потерь или в Windows это дело гиблое? И есть ли еще инструменты читать данные без потерь? Пожалуйста, помогите, буду признателен за любую помощь Quote Share this post Link to post Share on other sites More sharing options...
jcxz 309 October 7, 2022 Posted October 7, 2022 · Report post У вас какая-то каша в коде... Вызывать нужно ReadFile(), а затем - GetOverlappedResult(). А не наоборот. Советую прочитать описание WinAPI. А всякие WaitCommEvent(), ClearCommError(), WaitForSingleObject() вообще не понятно с какого рожна приплетены? Это же поток читающий символы из UART. Вот это он и должен делать. 1 час назад, klod сказал: И есть ли еще инструменты читать данные без потерь? Инструмент только один: внимательное чтение документации на WinAPI. Quote Share this post Link to post Share on other sites More sharing options...
k155la3 27 October 7, 2022 Posted October 7, 2022 · Report post 3 часа назад, klod сказал: . . . . Данные выдаются пакетом из устройства в порт ПК каждые 100 мс размером 2500 байт. Но происходит потеря данных . . . . Скорость обмена -460800; Таймауты по умолчанию, кроме MAXWORD все нули. . . . Хотелось бы узнать, реально читать данные при такой скорости и настройке без потерь или в Windows это дело гиблое? И есть ли еще инструменты читать данные без потерь? Попробуйте поработать с таймаутами, для этого размер буфера поставьте заведомо больше ваших 2500, например 50000, тогда функция будет отрабатывать не по заполнению буфера, а по отработке таймаута (они должны соотв-ть длительности пакета и паузы между ними). Их там (таймаутов) задается 3 (насколько помню). Это работало для небольших скоростей, до 115200. Насколько эффективно это, и будет ли работать для 460800 сказать не могу. Отладьте работу на низкой скорости, затем пробуйте на высокой. Скорость достаточно высокая, но драйвер порта должен обеспечивать получение данных. Вопрос в правильной его настройке и своевременном считывании данных из буфера драйвера. Инфорамция к размышлению: See also SetCommTimeouts function, etc https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommtimeouts -------------- COMMTIMEOUTS Communications Functions Communications Resources GetCommTimeouts SetCommTimeouts ReadFile ReadFileEx WriteFile WriteFileEx Структура DCB Quote Share this post Link to post Share on other sites More sharing options...