?
Hallo liebe Forianer,
ich wünsche Euch vorab ein schönes WE und bitte, bitte erst später schlagen ob des trivialen Charakters dieses Posts. Aber der o.g. Link geht nicht mehr und Google hilft mir gar nicht.
Schon mal vielen Dank fürs Weiterlesen!
Im nachfolgenden Source kapselt eine Klasse CComPort als "Server" eine RS232. Der Mechanismus steckt in einer Dll. Instanzen der Klasse werden in Threads ausgeführt.
Im nachfolgenden Source ist folgendes gewünscht:
1. Eine Übertragung wird mit WriteCom gestartet.
2. Wenn das Schreiben fertig ist, soll es in WriteDone weitergehen. Das klappt.
3. WriteDone soll dann auf die Ausführung im Controller und dessen Antwort mittels ReadDone warten, um diese Antwort zu verarbeiten. Das klappt nicht.
4. Stackende
ReadDone hinkt immer ein Übertragung hinterher, und ich weiss nicht warum.
Die erste Übertragung hat immer 995 (ERROR_OPERATION_ABORTED).
Ich bin für jede Idee dankbar! Links, Brain-debugging, etc...
Liebe Grüße
Lars
Debugger:
completion write success. 0 10
timeout
completion read error. 995 0
completion write success. 0 10
completion read success. 0 10
Source:
// ComPort.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "string.h"
#include "ComPort.h"
//-----------------------------------------------------
// mutex for access control
HANDLE g_hAccessCom = NULL;
DWORD g_dwAccessTimeout = 2000;
char g_szAccessName[16] = {"ComAccessMutex"};
//-----------------------------------------------------
// process id at position index in gs_tProcReg
DWORD g_dwProcIndex = 0;
//-----------------------------------------------------
//
OVERLAPPED g_ovl = {0};
//-----------------------------------------------------
// current instance the worker is assigned to
CComPort *g_lpInstance = NULL;
DWORD g_dwComCount = 0;
//-----------------------------------------------------
// shared information
#pragma data_seg(".gCom")
DWORD gs_dwOwnerId = 0;
HANDLE gs_hCom = INVALID_HANDLE_VALUE;
DWORD gs_dwProcCount = 0;
TProcRegistry gs_tProcReg = {0};
#pragma data_seg()
#pragma comment(linker, "/SECTION:.gCom,RWS")
unsigned char g_buffer[10] = {0};
//-----------------------------------------------------
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (gs_dwProcCount > (MAX_PROCS-1) ) return false;
g_hAccessCom = OpenMutex(SYNCHRONIZE,false,g_szAccessName);
if (!g_hAccessCom)
{
g_hAccessCom = CreateMutex(NULL,false,g_szAccessName);
if (!g_hAccessCom)
{
return false;
}
}
gs_dwProcCount++;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
if (g_hAccessCom)
{
CloseHandle(g_hAccessCom);
g_hAccessCom = NULL;
}
gs_dwProcCount--;
break;
}
return true;
}
//*****************************************************
// callback function is entered when WriteCom operation
// has finished with normally or by error
//*****************************************************
VOID CALLBACK ReadDone(DWORD dwError,DWORD dwTransferred,OVERLAPPED *ovl)
{
DWORD ret = 0;
if (dwError)
{
qDebug(QString("completion read error. %1 %2").arg(dwError).arg(dwTransferred));
ret = CancelIo(gs_hCom);
// ret = ClearCommError(gs_hCom,&dwError,NULL);
// ret = PurgeComm(gs_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
}
else
{
qDebug(QString("completion read success. %1 %2").arg(dwError).arg(dwTransferred));
}
}
VOID CALLBACK WriteDone(DWORD dwError,DWORD dwTransferred,OVERLAPPED *ovl)
{
DWORD length = dwTransferred;
DWORD ret;
if (dwError)
{
qDebug(QString("completion write error. %1 %2").arg(dwError).arg(dwTransferred));
LeaveCom();
}
else
{
qDebug(QString("completion write success. %1 %2").arg(dwError).arg(dwTransferred));
g_ovl.Internal = 0;
g_ovl.InternalHigh = 0;
g_ovl.Offset = 0;
g_ovl.OffsetHigh = 0;
g_ovl.hEvent = NULL;
if ( !ReadFileEx(gs_hCom,(void*)g_buffer,length,&g_ovl,ReadDone) )
{
ret = GetLastError();
}
// SignalObjectAndWait(gs_hCom,gs_hCom,INFINITE,true); Phänomen: Der Hint läuft, der compiler nicht ...? Alte scheisse hier!!!
/*
// Reports dwTransferred correctly, but no dwError
if (WAIT_TIMEOUT == WaitForSingleObjectEx(gs_hCom,INFINITE,true) )
{
qDebug("timeout");
ret = ClearCommError(gs_hCom,&dwError,NULL);
}
*/
// Reports dwError correctly, but has one cycle delay
if ( !SleepEx(0,true) )
{
qDebug("timeout");
ret = CancelIo(gs_hCom);
// ret = ClearCommError(gs_hCom,&dwError,NULL);
// ret = PurgeComm(gs_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
// ret = GetOverlappedResult(gs_hCom,&g_ovl,&dwTransferred,true);
}
}
}
//*****************************************************
// process local functions
//*****************************************************
bool ReadCom(void*& buffer,DWORD & length)
{
return true;
}
//---------------------------------------------------
bool WriteCom(void* buffer,DWORD length,CComPort* instance)
{
DWORD ret;
HANDLE hOwner = NULL;
if ( !EnterCom(ACCESS_TIMEOUT) )
{
return false;
}
// is gs_hCom in this process-scope?
if ( gs_dwOwnerId != gs_tProcReg.id[g_dwProcIndex] ) // no
{
hOwner = OpenProcess(PROCESS_DUP_HANDLE,false,gs_dwOwnerId);
if (!hOwner)
{
LeaveCom();
return false;
}
else
{
// try to transfer gs_hCom into this process
if ( !DuplicateHandle( hOwner,
gs_hCom,
GetCurrentProcess(),
&gs_hCom,
DUPLICATE_SAME_ACCESS,
false,
DUPLICATE_CLOSE_SOURCE) )
{
CloseHandle(hOwner);
LeaveCom();
return false;
}
CloseHandle(hOwner);
}
// now it is
gs_dwOwnerId = gs_tProcReg.id[g_dwProcIndex];
}
g_lpInstance = instance;
g_ovl.Internal = 0;
g_ovl.InternalHigh = 0;
g_ovl.Offset = 0;
g_ovl.OffsetHigh = 0;
g_ovl.hEvent = NULL;
if ( !WriteFileEx(gs_hCom,buffer,length,&g_ovl,WriteDone) )
{
ret = GetLastError();
LeaveCom();
return false;
}
FlushFileBuffers(gs_hCom);
if ( !SleepEx(0,true))
{
qDebug("timeout write");
}
return true;
}
//------------------------------------------------------
// Function inserts proc-id into registry, if id > 0.
// CCom-ctor calls function with id > 0.
//
// When id == 0, the function searches an valid id (>0),
// duplicates gs_hCom into the process' scope and
// sets this id as the new owner of gs_hCom.
// CCom-dtor call this function with id = 0, when the last
// instance of CCom closes in a process.
//
// Function must be encapsulated by EnterCom()/LeaveCom()!
bool RestoreCom(DWORD id)
{
HANDLE newOwner = NULL;
DWORD i;
if (id) // ctor
{
for (i=0;i<MAX_PROCS;i++)
{
if (!gs_tProcReg.id[i]) // a value of "0" (zero) indicates a free location
{
gs_tProcReg.id[i] = id;
g_dwProcIndex = i;
break;
}
}
}
else // dtor
{
for (i=0;i<MAX_PROCS;i++) //find any valid id that is not my id
{
if ( gs_tProcReg.id[i] && (i != g_dwProcIndex) )
{
newOwner = OpenProcess(PROCESS_DUP_HANDLE,false,gs_tProcReg.id[i]);
if (!newOwner)
{
return false;
}
if ( !DuplicateHandle( GetCurrentProcess(),
gs_hCom,
newOwner,
&gs_hCom,
DUPLICATE_SAME_ACCESS,
false,
DUPLICATE_CLOSE_SOURCE) )
{
CloseHandle(newOwner);
return false;
}
CloseHandle(newOwner);
gs_dwOwnerId = gs_tProcReg.id[i];
gs_tProcReg.id[g_dwProcIndex] = 0;
break;
}
}
}
if (i == MAX_PROCS)
{
return false;
}
else
{
return true;
}
}
//------------------------------------------------------
// function does process global, initial settings.
//
// EnterCom()/LeaveCom() must be called before/after
// calling this function!
bool OpenCom(void)
{
COMMCONFIG cc;
COMMTIMEOUTS cto;
// COMMPROP cp; // only needed for old chips. 16450 uart or higher assumed
char com[10] = {""};
DWORD dwSize;
DWORD dwError;
DWORD ret = 0;
int i;
// determine, if rs232-port is available and get handle
for (i=MIN_COM_PORT;i<=MAX_COM_PORT;i++)
{
wsprintf(com,"\\\\.\\com%d",i);
gs_hCom = CreateFile( com,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (gs_hCom != INVALID_HANDLE_VALUE)
{
cc.dwSize = sizeof(COMMCONFIG);
cc.dcb.DCBlength = sizeof(DCB);
if (!GetCommConfig(gs_hCom,&cc,&dwSize))
{
return false;
}
if (cc.dwProviderSubType == PST_RS232)
{
// analyze COMMPROP cp here, if old uart is used
break; //ok, assume handle is RS232 with all needed features
}
}
}
// no RS232 port found?
if (gs_hCom == INVALID_HANDLE_VALUE)
{
return false;
}
//COMMCONFIG settings
cc.dcb.BaudRate = CBR_9600;
cc.dcb.ByteSize = 8;
cc.dcb.EofChar = '\0';
cc.dcb.ErrorChar = '\0';
cc.dcb.EvtChar = '\0';
cc.dcb.fAbortOnError = true;
cc.dcb.fBinary = true;
cc.dcb.fDsrSensitivity = false;
cc.dcb.fDtrControl = DTR_CONTROL_DISABLE;
cc.dcb.fErrorChar = false;
cc.dcb.fInX = false;
cc.dcb.fNull = false;
cc.dcb.fOutX = false;
cc.dcb.fOutxCtsFlow = false;
cc.dcb.fOutxDsrFlow = false;
cc.dcb.fParity = false;
cc.dcb.fRtsControl = RTS_CONTROL_DISABLE;
cc.dcb.fTXContinueOnXoff = true;
cc.dcb.Parity = NOPARITY;
cc.dcb.StopBits = ONESTOPBIT;
cc.dcb.XoffChar = '\0';
cc.dcb.XoffLim = 0;
cc.dcb.XonChar = '\0';
cc.dcb.XonLim = 0;
if (!SetCommConfig(gs_hCom,&cc,sizeof(COMMCONFIG)))
{
return false;
}
//COMMTIMEOUTS settings
cto.ReadIntervalTimeout = (DWORD)( (1/cc.dcb.BaudRate) * 10 + 2);
cto.ReadTotalTimeoutConstant = 100;
cto.ReadTotalTimeoutMultiplier = 100;
cto.WriteTotalTimeoutConstant = 100;
cto.WriteTotalTimeoutMultiplier = 100;
if (!SetCommTimeouts(gs_hCom,&cto))
{
return false;
}
//abort pending communications and clean buffers
if (!PurgeComm(gs_hCom, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR))
{
return false;
}
/*
// reset port errors
if ( !CancelIo(gs_hCom) )
{
return false;
}
if ( !ClearCommError(gs_hCom,&dwError,NULL) )
{
return false;
}
*/
// the process calling this function gets initial ownership and
// provides process-id for duplicating gs_hCom to other process-scopes
gs_dwOwnerId = gs_tProcReg.id[g_dwProcIndex];
// all successfully done
return true;
}
//---------------------------------------------------
void CloseCom(void)
{
if (gs_hCom != INVALID_HANDLE_VALUE)
{
CloseHandle(gs_hCom);
gs_hCom = INVALID_HANDLE_VALUE;
}
}
//---------------------------------------------------
// functions enter or leave the mutex g_hAccessCom
bool EnterCom(DWORD timeout)
{
if (WAIT_TIMEOUT == WaitForSingleObject(g_hAccessCom,timeout) )
{
return false;
}
else
{
return true;
}
}
bool LeaveCom(void)
{
return ReleaseMutex(g_hAccessCom);
}
//******************************************************
// interfaceclass CComPort encapsulates local functions
//******************************************************
CComPort::CComPort(void)
{
// if this instance is the first instance generated in process
if (!g_dwComCount)
{
// get procid and save it in registration
if ( EnterCom(ACCESS_TIMEOUT) )
{
RestoreCom( GetCurrentProcessId() );
LeaveCom();
}
}
//Increment instance counter
g_dwComCount++;
// if this instance was generated by the first dll-attaching process
if ( EnterCom(ACCESS_TIMEOUT) )
{
if ( (gs_dwProcCount<=1) && (gs_hCom == INVALID_HANDLE_VALUE) )
{
OpenCom();
}
LeaveCom();
}
}
//-----------------------------------------------------
CComPort::~CComPort(void)
{
g_dwComCount--; //Decrement instance counter
if (!g_dwComCount) // was last instance in process?
{
if ( EnterCom(ACCESS_TIMEOUT) )
{
if (gs_dwProcCount == 1) //was last process attached to dll?
{
CloseCom();
}
else
{
//not the last process but the owner of gs_hCom?
if (gs_dwOwnerId == gs_tProcReg.id[g_dwProcIndex] )
{
RestoreCom(0); // move gs_hCom to other process
}
}
LeaveCom();
}
}
}
//-----------------------------------------------------
bool CComPort::setCurrent(unsigned __int32 current)
{
return true;
}
//-----------------------------------------------------
unsigned __int32 CComPort::current(void)
{
unsigned __int32 curr = 0;
return curr;
}
//-----------------------------------------------------
bool CComPort::setVoltage(unsigned __int32 voltage)
{
return true;
}
//-----------------------------------------------------
unsigned __int32 CComPort::voltage(void)
{
unsigned __int32 volt = 0;
return volt;
}
//-----------------------------------------------------
unsigned __int32 CComPort::status(void)
{
unsigned __int32 state = 0;
return state;
}
//-----------------------------------------------------
unsigned __int32 CComPort::warmup(void)
{
unsigned __int32 step = 0;
return step;
}
//-----------------------------------------------------
unsigned __int32 CComPort::conditioning(void)
{
unsigned __int32 step = 0;
return step;
}
//-----------------------------------------------------
QString CComPort::version(void)
{
QString ver = "";
return ver;
}
//-----------------------------------------------------
bool CComPort::xray(bool on)
{
return true;
}
//-----------------------------------------------------
unsigned __int8 CComPort::readMem(unsigned __int16 address)
{
unsigned __int8 value = 0;
return value;
}
//-----------------------------------------------------
bool CComPort::writeMem(unsigned __int16 address,unsigned __int8 value)
{
return true;
}
//-----------------------------------------------------
bool CComPort::testWrite(unsigned char * buffer,int size)
{
return WriteCom((void*) buffer,(DWORD) size,this);
}