Все работает отлично — но только если на компе не крутят еще какие то задачи
особенно если на компе кто то начинает лазить по инет то тут же начинаются сбои
наиболее частый сбой состоит в том что пропадает первый байт получаемых данных —
ну а дальше конечно весь обмен нарушается так как неверно начинают расшифровываться принимаемые пакеты
Вопрос — можно сделать нечто похожее на асинхронные сокеты?
или
может есть какие то готовые классы для этого ?
скорее всего как то надо использовать FILE_FLAG_OVERLAPPED вместо OPEN_EXISTING
если кто нибудь может хорошо объяснить или помочь написать нужный код
то очень большая просьба написать
Эдуард
25.11.03 13:15: Перенесено модератором из 'C/C++' — ПК
Re: как организовать асинхронную работу через rs-232?
Hello, EandG!
You wrote on Tue, 25 Nov 2003 00:53:51 GMT:
E> ...... E> dwToWrite=8; //посыдаем 8-байтовую команду E> expectLengthOfLine=12; //ждем 12-байтовый ответ
E> PurgeComm(port,PURGE_TXCLEAR); E> PurgeComm(port,PURGE_RXCLEAR);
E> WriteFile(port, ask, dwToWrite, &dwWritten, NULL); E> ReadFile(port, reply, expectLengthOfLine, NULL); E> ......
Вот это: ReadFile(port, reply, expectLengthOfLine, NULL); просто не должно скомпилироваться — там еще один параметр должен быть. Покажи настоящий код, особенно что ты делаешь с 4'м параметром.
E> Все работает отлично — но только если на компе не крутят еще какие то E> задачи
E> особенно если на компе кто то начинает лазить по инет то тут же E> начинаются сбои наиболее частый сбой состоит в том что пропадает первый E> байт получаемых данных -ну а дальше конечно весь обмен нарушается так E> как неверно начинают расшифровываться принимаемые пакеты
E> Вопрос — можно сделать нечто похожее на асинхронные сокеты?
Можно, но вряд ли необходимо.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: как организовать асинхронную работу через rs-232?
Здравствуйте, EandG, Вы писали:
EG>Проблема с пар портом — очень большая просьба помочь кто хорошо разбирается
EG>дело вот в чем EG>открываем порт как показано ниже
EG>port=CreateFile(m_port,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
port = CreateFile(sPort, GENERIC_READ| GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
FILE_FLAG_OVERLAPPED — по моему это и есть асинхронная передача данных
Сам на данный момент СОММ занимаюсь
Re: как организовать асинхронную работу через rs-232?
Здравствуйте, EandG, Вы писали:
EG>Проблема с пар портом — очень большая просьба помочь кто хорошо разбирается
Примерно пол года назад написал класс для асинхронной работы с СОММ портом, но отладить его не удалось, т.к. мы от СОММ порта отказались. Я тебе исходник дам, как пример асинхронной работы с СОММ портом, но ещё раз предупреждаю — класс не отлажен, скорей всего (90%) работать не будет.
///////////////////////// h ////////////////////////////////////
// Моя благодарность Николаю Меркину aka Кодт.
// http://www.rsdn.ru/Forum/Message.aspx?mid=130252#130252
// IS_DEBUG - булева константа, истинна если собирается DEBUG-версия#ifndef IS_DEBUG
#if defined(DEBUG) || defined(_DEBUG) // проверяем оба признака#define IS_DEBUG true
#else
#define IS_DEBUG false
#endif
#endif// DEBUG_ONLY - префикс оператора, который выполнится только в DEBUG-версии
// синтаксис - аналогичен составному оператору while()#ifndef DEBUG_ONLY
#define DEBUG_ONLY if(!(IS_DEBUG)) {} else// такая конструкция нужна, чтобы не конфликтовать с внешним if#endif// аналогично ему - RELEASE_ONLY
// хотя зачем он может пригодиться - не знаю; пусть будет.#ifndef RELEASE_ONLY
#define RELEASE_ONLY if(IS_DEBUG) {} else
#endif
#define COMM_THREAD_WAIT 1000
class CComm
{
public:
typedef void (__stdcall *CompleteWrite)(DWORD);
typedef void (__stdcall *CompleteRead)(BYTE*, DWORD);
public:
CComm (CompleteWrite = NULL, CompleteRead = NULL);
virtual ~CComm ();
DWORD InitCommPort (LPCTSTR/*имя comm порта*/ = _TEXT("COM1"), DWORD/*размер входной очереди*/ = 300,
DWORD/*размер выходной очереди*/ = 300, DCB* /*Указатель на структуру DCB*/ = NULL,
DWORD/*флаги, если 0 то используется входящая структура полностью, если -1 то игнорируется полностью, если выставлены биты, то используется частично*/ = -1,
DWORD/*значение маски*/ = 0, BOOL/*флаг маски, если true то выставляется*/ = FALSE,
COMMTIMEOUTS* /*Указатель на структуру*/ = NULL, BYTE/*флаги, то же что и для DCB*/ = -1);
BOOL BeginReadWriteComm (DWORD);
BOOL EndReadWriteComm (void);
BOOL SendComm (BYTE*, DWORD);
BOOL IsInit (void) const { return m_fInit; }
public:
enum FLAGS_FOR_DCB
{
DCBlength = 1,
BaudRate = 2,
fBinary = 4,
fParity = 8,
fOutxCtsFlow = 16,
fOutxDsrFlow = 32,
fDtrControl = 64,
fDsrSensitivity = 128,
fTXContinueOnXoff = 256,
fOutX = 512,
fInX = 1024,
fErrorChar = 2048,
fNull = 4096,
fRtsControl = 8192,
fAbortOnError = 16384,
XonLim = 32768,
XoffLim = 65536,
ByteSize = 131072,
Parity = 262144,
StopBits = 524288,
XonChar = 1048576,
XoffChar = 2097152,
ErrorChar = 4194304,
EofChar = 8388608,
EvtChar = 16777216
} m_FlagsForDCB;
enum FLAGS_FOR_TIMEOUT
{
ReadIntervalTimeout = 1,
ReadTotalTimeoutMultiplier = 2,
ReadTotalTimeoutConstant = 4,
WriteTotalTimeoutMultiplier = 8,
WriteTotalTimeoutConstant = 16
} m_FlagsForTimeOut;
private:
static UINT __stdcall WINAPI ThreadFuncCOMM (LPVOID);
static void __cdecl Trace (LPCTSTR lpszFormat, ...)
{
va_list args;
va_start(args, lpszFormat);
int nBuf;
TCHAR szBuffer[512];
nBuf = _vsntprintf (szBuffer, sizeof(szBuffer) / sizeof(TCHAR), lpszFormat, args);
assert (nBuf < sizeof(szBuffer));
OutputDebugString (szBuffer);
va_end(args);
}
private:
typedef struct tagThread
{
tagThread (CompleteWrite p1, CompleteRead p2)
: m_ReadBytes (1), CallWrite (p1), CallRead (p2)
{
m_hComm = NULL;
m_hThread = NULL;
m_hExit = NULL;
memset (&m_oRead, 0, sizeof (OVERLAPPED));
memset (&m_oWrite, 0, sizeof (OVERLAPPED));
}
~tagThread ()
{
Reset ();
if (m_hComm)
{
CloseHandle (m_hComm);
m_hComm = NULL;
}
}
BOOL Reset ()
{
BOOL ret = TRUE;
DWORD res = 0;
if (m_hThread)
{
GetExitCodeThread (m_hThread, &res);
if (res == STILL_ACTIVE)
{
assert (m_hExit);
SetEvent (m_hExit);
res = WaitForSingleObject (m_hThread, COMM_THREAD_WAIT);
if (res == WAIT_TIMEOUT || res == WAIT_FAILED)
{
assert (0);
::TerminateThread (m_hThread, -1);
ret = FALSE;
}
}
CloseHandle (m_hThread);
m_hThread = NULL;
}
if (m_hExit)
{
CloseHandle (m_hExit);
m_hExit = NULL;
}
if (m_oRead.hEvent)
CloseHandle (m_oRead.hEvent);
memset (&m_oRead, 0, sizeof (OVERLAPPED));
if (m_oWrite.hEvent)
CloseHandle (m_oWrite.hEvent);
memset (&m_oWrite, 0, sizeof (OVERLAPPED));
return ret;
}
HANDLE m_hComm;
HANDLE m_hExit;
HANDLE m_hThread;
OVERLAPPED m_oRead;
OVERLAPPED m_oWrite;
DWORD m_ReadBytes;
CompleteWrite CallWrite;
CompleteRead CallRead;
} THREAD;
THREAD m_Thread;
HANDLE m_hEvent;
DCB m_ComConfig;
// COMMPROP m_ComProp;
COMMTIMEOUTS m_ComTime;
BOOL m_fInit;
};
///////////////////////// cpp ////////////////////////////////////#include"stdafx.h"#include"CommPort.h"// My static function
UINT __stdcall CComm::ThreadFuncCOMM (LPVOID pv)
{
UINT ret = 0;
DWORD res = 0;
HANDLE h[3];
DWORD rw = 0;
BYTE* pBuf = NULL;
__try
{
CComm::THREAD* pS = (CComm::THREAD*)pv;
DEBUG_ONLY Trace (_TEXT("\nStart thread COMM."));
if (!(pBuf = new BYTE[pS -> m_ReadBytes]))
__leave;
h[0] = pS -> m_hExit;
h[1] = pS -> m_oRead.hEvent;
h[2] = pS -> m_oWrite.hEvent;
DWORD err = ::ReadFile (pS -> m_hComm, &pBuf, pS -> m_ReadBytes, &rw, &pS -> m_oRead);
while ((res = WaitForMultipleObjects (3, h, FALSE, INFINITE)) != 0)
{
switch (res)
{
case WAIT_OBJECT_0:
__leave;
break;
case WAIT_OBJECT_0 + 1:
if (pS -> CallRead)
pS -> CallRead (pBuf, rw);
::ReadFile (pS -> m_hComm, &pBuf, pS -> m_ReadBytes, &rw, &pS -> m_oRead);
break;
case WAIT_OBJECT_0 + 2:
if (pS -> CallWrite)
{
DWORD resWrite = 0;
::GetOverlappedResult (pS -> m_hComm, &pS -> m_oWrite, &resWrite, TRUE);
DEBUG_ONLY if (!resWrite)
DEBUG_ONLY Trace (_TEXT("\nОшибка передачи данных."));
pS -> CallWrite (resWrite);
}
break;
case WAIT_TIMEOUT:
case WAIT_FAILED:
assert (0);
ret = -1;
__leave;
break;
default:
assert (0);
ret = -1;
__leave;
break;
}
}
}
__finally
{
if (pBuf)
delete[] pBuf;
}
DEBUG_ONLY Trace (_TEXT("\nStop thread COMM."));
return ret;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CComm::CComm (CompleteWrite p1, CompleteRead p2)
: m_fInit (TRUE), m_Thread (p1, p2)
{
}
CComm::~CComm()
{
}
DWORD CComm::InitCommPort (LPCTSTR/*имя comm порта*/ name,
DWORD/*размер входной очереди*/ InQ,
DWORD/*размер выходной очереди*/ OutQ,
DCB* /*Указатель на структуру DCB*/ pDCB,
DWORD/*флаги, если 0 то используется входящая структура полностью, если -1 то игнорируется полностью, если выставлены биты, то используется частично*/ FlagsDCB,
DWORD/*значение маски*/ Mask,
BOOL/*флаг маски, если true то выставляется*/FlagMask,
COMMTIMEOUTS* /*Указатель на структуру*/ pTimeOut,
BYTE/*флаги, то же что и для DCB*/ FlagsTimeOut)
{
int i = 0;
m_Thread.Reset ();
if (m_Thread.m_hComm)
{
CloseHandle (m_Thread.m_hComm);
m_Thread.m_hComm = NULL;
}
m_fInit = FALSE;
m_Thread.m_hComm = ::CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (m_Thread.m_hComm == INVALID_HANDLE_VALUE)
{
DEBUG_ONLY Trace (_TEXT("\nНевозможно открыть порт."));
return ::GetLastError ();
}
if (!::SetupComm (m_Thread.m_hComm, InQ, OutQ))
{
DEBUG_ONLY Trace (_TEXT("\nНеверные установки."));
return ::GetLastError ();
}
if (!FlagsDCB)
{
assert (pDCB);
m_ComConfig = *pDCB;
}
else
{
if (!::GetCommState (m_Thread.m_hComm, &m_ComConfig))
{
DEBUG_ONLY Trace (_TEXT("\nВнутренняя ошибка."));
return ::GetLastError ();
}
if (FlagsDCB <= 0x1FFFFFF)
{
assert (pDCB);
m_ComConfig.DCBlength = sizeof (DCB);
for (i = 0; i < 25 && FlagsDCB; FlagsDCB >>= 1, ++i)
{
if (FlagsDCB & 1)
{
switch (i)
{
case 1:
m_ComConfig.BaudRate = pDCB -> BaudRate;
break;
case 2:
m_ComConfig.fBinary = pDCB -> fBinary;
break;
case 3:
m_ComConfig.fParity = pDCB -> Parity;
break;
case 4:
m_ComConfig.fOutxCtsFlow = pDCB -> fOutxCtsFlow;
break;
case 5:
m_ComConfig.fOutxDsrFlow = pDCB -> fOutxDsrFlow;
break;
case 6:
m_ComConfig.fDtrControl = pDCB -> fDtrControl;
break;
case 7:
m_ComConfig.fDsrSensitivity = pDCB -> fDsrSensitivity;
break;
case 8:
m_ComConfig.fTXContinueOnXoff = pDCB -> fTXContinueOnXoff;
break;
case 9:
m_ComConfig.fOutX = pDCB -> fOutX;
break;
case 10:
m_ComConfig.fInX = pDCB -> fInX;
break;
case 11:
m_ComConfig.fErrorChar = pDCB -> fErrorChar;
break;
case 12:
m_ComConfig.fNull = pDCB -> fNull;
break;
case 13:
m_ComConfig.fRtsControl = pDCB -> fRtsControl;
break;
case 14:
m_ComConfig.fAbortOnError = pDCB -> fAbortOnError;
break;
case 15:
m_ComConfig.XonLim = pDCB -> XonLim;
break;
case 16:
m_ComConfig.XoffLim = pDCB -> XoffLim;
break;
case 17:
m_ComConfig.ByteSize = pDCB -> ByteSize;
break;
case 18:
m_ComConfig.Parity = pDCB -> Parity;
break;
case 19:
m_ComConfig.StopBits = pDCB -> StopBits;
break;
case 20:
m_ComConfig.XonChar = pDCB -> XonChar;
break;
case 21:
m_ComConfig.XoffChar = pDCB -> XoffChar;
break;
case 22:
m_ComConfig.ErrorChar = pDCB -> ErrorChar;
break;
case 23:
m_ComConfig.EofChar = pDCB -> EofChar;
break;
case 24:
m_ComConfig.EvtChar = pDCB -> EvtChar;
break;
default:
assert (0);
}
}
}
}
}
if(!::SetCommState (m_Thread.m_hComm, &m_ComConfig))
{
DEBUG_ONLY Trace (_TEXT("\nНевозможно инициализировать порт."));
return ::GetLastError ();
}
if (FlagMask)
{
if (!SetCommMask (m_Thread.m_hComm, Mask))
{
DEBUG_ONLY Trace (_TEXT("\nНе могу наложить маску."));
return ::GetLastError ();
}
}
if (!FlagsTimeOut)
{
assert (pTimeOut);
m_ComTime = *pTimeOut;
}
else
{
if (!GetCommTimeouts (m_Thread.m_hComm, &m_ComTime))
{
DEBUG_ONLY Trace (_TEXT("\nВнутренняя ошибка."));
return ::GetLastError ();
}
if (FlagsTimeOut <= 0x1F)
{
assert (pTimeOut);
for (i = 0; i < 5 && FlagsTimeOut; FlagsTimeOut >>= 1, ++i)
{
if (FlagsTimeOut & 1)
{
switch (i)
{
case 0:
m_ComTime.ReadIntervalTimeout = pTimeOut -> ReadIntervalTimeout;
break;
case 1:
m_ComTime.ReadTotalTimeoutMultiplier = pTimeOut -> ReadTotalTimeoutMultiplier;
break;
case 2:
m_ComTime.ReadTotalTimeoutConstant = pTimeOut -> ReadTotalTimeoutConstant;
break;
case 3:
m_ComTime.WriteTotalTimeoutMultiplier = pTimeOut -> WriteTotalTimeoutMultiplier;
break;
case 4:
m_ComTime.WriteTotalTimeoutConstant = pTimeOut -> WriteTotalTimeoutConstant;
break;
default:
assert (0);
}
}
}
}
}
if (!SetCommTimeouts (m_Thread.m_hComm, &m_ComTime))
{
DEBUG_ONLY Trace (_TEXT("\nНевозможно установить TimeOut."));
return ::GetLastError ();
}
m_fInit = TRUE;
return 0;
}
BOOL CComm::BeginReadWriteComm (DWORD sb)
{
UINT id = 0;
assert (m_fInit);
assert (!m_Thread.m_hThread);
m_Thread.m_ReadBytes = sb;
m_Thread.m_oWrite.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
m_Thread.m_oRead.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
m_Thread.m_hExit = CreateEvent (NULL, TRUE, FALSE, NULL);
m_Thread.m_hThread = (HANDLE)_beginthreadex (NULL, 0, ThreadFuncCOMM, (LPVOID)&m_Thread, 0, &id);
if(!m_Thread.m_hThread)
{
DEBUG_ONLY Trace (_TEXT("\nНевозможно запустить нить."));
return FALSE;
}
return TRUE;
}
BOOL CComm::EndReadWriteComm ()
{
assert (m_fInit);
assert (m_Thread.m_hThread);
return m_Thread.Reset ();
}
BOOL CComm::SendComm (BYTE* p, DWORD sz)
{
DWORD ret = 0;
assert (m_fInit);
assert (m_Thread.m_hThread);
::WriteFile (m_Thread.m_hComm, p, sz, &ret, &m_Thread.m_oWrite);
if (::GetLastError () == ERROR_IO_PENDING)
return TRUE;
return FALSE;
}
Suum cuique (лат.)
Re: как организовать асинхронную работу через rs-232?
От:
Аноним
Дата:
25.11.03 14:03
Оценка:
WM_TIMER вообще не стоит использовать для критических операций, его генерация имеет чуть ли не самый низкий приоритет в системе.
Я бы порекомендовал в Вашем случае использовать асинхронный ввод-вывод:
— в CreateFile передать флаг FILE_FLAG_OVERLAPPED
— для чтения/записи использовать (разные) структуры OVERLAPPED
Сам ввод-вывод выполнять в отдельной нитке, которая будет просыпаться по событию, указанному в структуре OVERLAPPED.
К сожалению, у меня сейчас нет времени на подробности. Если Вы не имели дела с асинхр. в/в, см. в MSDN: Windows Base Services -> Files and I/O -> Storage Overview -> File Management -> Reading and Writing Asynchronously
Re[2]: как организовать асинхронную работу через rs-232?
Здравствуйте, Sergey, Вы писали:
S>Вот это: ReadFile(port, reply, expectLengthOfLine, NULL); просто не должно скомпилироваться — там еще один параметр должен быть. Покажи настоящий код, особенно что ты делаешь с 4'м параметром.
Абсолютно верное замечание — параметров конечно 5 — код такой
смахнул лишнее случайно когда убирал &overlapped_write из текста и ставил NULL
а проект могу хоть весь прислать — там вначале письма еще опечатка — послед. порт а паралелльный — поздно было башка трещала — и вообще первый пост — виноват
S>Можно, но вряд ли необходимо.
если знаете как, то если это долго рассказывать то я готов хоть позвонить
потому что когда то была похожая проблема с сокетами и после использования асинхронных сокетов все проблемы исчезли
но если можете подсказать и решение без "асинхронности" то признательность будет не меньшей — пока не понятен даже механизм почему пропадают байты при приеме и особенно часто первый байт — если на компе вертится что то еще особенно лазаине по инет
Прога работает сутками если она на компе одна — но если полазить вовремя ее работы по инет то заставить прогу потерять байты при приеме можно за минуту
Eduard
Re[2]: как организовать асинхронную работу через rs-232?
Hello, EandG!
You wrote on Tue, 25 Nov 2003 17:18:49 GMT:
E> Абсолютно верное замечание — параметров конечно 5 — код такой
E> WriteFile(port, ask, dwToWrite, &dwWritten, NULL); E> ReadFile(port, reply, expectLengthOfLine, &dwRead, NULL);
Ну так что с dwRead дальше делаешь? Всегда ли оно совпадает с expectLengthOfLine?
E> а проект могу хоть весь прислать
Не надо.
E> — там вначале письма еще опечатка — послед. порт а паралелльный —
Насчет параллельного не понял.
S>> Можно, но вряд ли необходимо.
E> если знаете как, то если это долго рассказывать то я готов хоть
Ну там просто вариантов возможна целая куча.
E> позвонить потому что когда то была похожая проблема с сокетами и после E> использования асинхронных сокетов все проблемы исчезли
Да примерно так же, как с сокетами. Наверно проще всего будет так — запускаешь отдельный поток, делаешь в нем буфер на 12 байт (или какая там у тебя длина посылки), пишешь полученные байты в буфер, как буфер заполнился — декодируешь ответ и передаешь его главному потоку. Если посылки переменной длины, буфер удобнее всего делать кольцевой. Количество байт, доступных для чтения, берешь не из expectLengthOfLine, а смотришь, сколько байт сидят во входной очереди с помощью ClearCommError и ровно столько читаешь (не помню, почему я именно так делал — но работало безупречно).
E> но если можете подсказать и решение без "асинхронности" то E> признательность будет не меньшей — пока не понятен даже механизм почему E> пропадают байты при приеме и особенно часто первый байт — если на компе E> вертится что то еще особенно лазаине по инет
E> Прога работает сутками если она на компе одна — но если полазить вовремя E> ее работы по инет то заставить прогу потерять байты при приеме можно за E> минуту
Ну пока предположение такое — dwRead возвращает меньше, чем expectLengthOfLine, поскольку на загруженной машине посылки начинают приходить кусками. Ну и ошибки всяческие проверять не помешает — перед каждым чтением и записью в порт. При frame error порт закрыть/открыть.
Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.