Folge dem Video um zu sehen, wie unsere Website als Web-App auf dem Startbildschirm installiert werden kann.
Anmerkung: Diese Funktion ist in einigen Browsern möglicherweise nicht verfügbar.
bool OpenPort()
{
if ( m_hPort != INVALID_HANDLE_VALUE )
{
return false;
}
char szPortName[MAX_PATH];
dh::Log( "Opening Port (%s)", m_ParameterList.GetParam( "ZVT.COM.Port" ).c_str() );
wsprintf( szPortName, "\\\\.\\COM%d", GR::Convert::ToU32( m_ParameterList.GetParam( "ZVT.COM.Port" ) ) );
//wsprintf( szPortName, "COM%d:", m_wPort );
m_hPort = CreateFile( szPortName,
GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
0, // share mode exclusive-access
NULL, // pointer to security descriptor
OPEN_EXISTING, // how to create
FILE_FLAG_OVERLAPPED, // file attributes
NULL ); // handle to file with attributes to copy
if ( m_hPort == INVALID_HANDLE_VALUE )
{
// TODO - GetLastError
// ERROR_ACCESS_DENIED (5).
// Similarly if you by mistake opened a COM port that doesn't exist , you would get ERROR_FILE_NOT_FOUND
dh::Log( "Couldn't open port %d", GR::Convert::ToU32( m_ParameterList.GetParam( "ZVT.COM.Port" ) ) );
return false;
}
m_hEventWaitDataReceived = CreateEvent( NULL, TRUE, FALSE, NULL );
m_hEventDataWritten = CreateEvent( NULL, FALSE, FALSE, NULL );
memset( &m_ovWrite, 0, sizeof( m_ovWrite ) );
m_ovWrite.hEvent = m_hEventDataWritten;
memset( &m_ovRead, 0, sizeof( m_ovRead ) );
if ( !::SetCommMask( m_hPort, EV_RXCHAR ) )//| EV_TXEMPTY ) )
{
dh::Log( "CSerialCommHelper : Error setting com mask. %x", GetLastError() );
ClosePort();
return false;
}
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if ( !SetCommTimeouts( m_hPort, &timeouts ) )
{
dh::Log( "CSerialCommHelper : Error setting time-outs. %x", GetLastError() );
ClosePort();
return false;
}
m_hEventCloseWorkerThread = CreateEvent( NULL, TRUE, FALSE, NULL );
DWORD dwThreadID = 0;
m_hWorkerThread = CreateThread( NULL, 0, WorkerThreadHelper, (LPVOID)this, 0, &dwThreadID );
if ( m_hWorkerThread == NULL )
{
dh::Log( "Failed to create worker thread" );
ClosePort();
return false;
}
if ( !StartThread() )
{
ClosePort();
dh::Log( "StartThread Failed" );
return false;
}
return true;
}
void ClosePort()
{
dh::Log( "CLosePOrt" );
SetEvent( m_hEventCloseWorkerThread );
// ist ein Eigenbau für die Klassen-eigene Thread-Instanz
ShutDown( 250 );
dh::Log( "closed" );
if ( m_hEventCloseWorkerThread )
{
CloseHandle( m_hEventCloseWorkerThread );
m_hEventCloseWorkerThread = NULL;
}
if ( m_hEventTaskArrived )
{
CloseHandle( m_hEventTaskArrived );
m_hEventTaskArrived = NULL;
}
if ( m_hEventWaitDataReceived )
{
CloseHandle( m_hEventWaitDataReceived );
m_hEventWaitDataReceived = NULL;
}
if ( m_hEventDataReceived )
{
CloseHandle( m_hEventDataReceived );
m_hEventDataReceived = NULL;
}
if ( m_hEventDataWritten )
{
CloseHandle( m_hEventDataWritten );
m_hEventDataWritten = NULL;
}
if ( m_hPort == INVALID_HANDLE_VALUE )
{
return;
}
CloseHandle( m_hPort );
m_hPort = INVALID_HANDLE_VALUE;
dh::Log( "close done" );
}
ResultTextIDs WaitForResult()
{
HANDLE hEventGroup[2];
hEventGroup[0] = m_hEventCloseWorkerThread;
hEventGroup[1] = m_hEventWaitDataReceived;
while ( true )
{
// TODO - Timeout konfigurieren
DWORD dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, m_dwResultTimeout );
if ( dwResult == WAIT_OBJECT_0 )
{
// Ende
CancelIo( m_hPort );
SetEvent( m_hEventCloseWorkerThread );
return RES_ABORT_DUE_SHUTDOWN;
}
else if ( dwResult == WAIT_OBJECT_0 + 1 )
{
// Daten empfangen
ResetEvent( m_hEventWaitDataReceived );
}
else if ( dwResult == WAIT_TIMEOUT )
{
dh::Log( "WaitForResult - Timeout" );
return RES_CONNECTION_TIMEOUT;
}
else
{
dh::Log( "WaitForResult - Result %d", dwResult );
}
}
return RES_INTERNAL_ERROR;
}
// die Klassen-Eigene Thread-Run-Funktion
DWORD Run()
{
// Set up overlapped structure fields.
dh::Log( "COM Thread started" );
m_hEventDataReceived = CreateEvent( NULL, FALSE, FALSE, NULL );
memset( &m_ovRead, 0, sizeof( m_ovRead ) );
m_ovRead.Offset = 0;
m_ovRead.OffsetHigh = 0;
m_ovRead.hEvent = m_hEventDataReceived;
HANDLE hEventGroup[2];
hEventGroup[0] = m_hEventDataReceived;
hEventGroup[1] = m_hCloseEvent;
unsigned char ucLocalBuffer[2048];
DWORD dwLocalBytesRead;
DWORD dwStartTicks = 0;
DWORD dwLocalBufferOffset = 0;
bool bDataSent = false;
CByteBuffer bbIncoming;
// Setup-Vorgang fortsetzen im Thread, damit der User nicht so lange warten muß
SetDCB( 9600, 8, 0, 2 );
// 9600,n,8,2
if( !SetCommState( m_hPort, &m_DCB ) )
{
ClosePort();
dh::Log( "SetCommState failed" );
return 1;
}
HANDLE hEventCom = CreateEvent( NULL, TRUE, FALSE, NULL );
OVERLAPPED ovCom;
memset( &ovCom, 0, sizeof( ovCom ) );
ovCom.hEvent = hEventCom;
// HaveToShutDown prüft, ob ShutDown für den Thread aufgerufen worden ist
while ( !HaveToShutDown() )
{
DWORD dwEventMask = 0;
// Event an Com-Schnittstelle übergeben
//dh::Log( "WaitCommEvent..." );
if ( !WaitCommEvent( m_hPort, &dwEventMask, &ovCom ) )
{
DWORD dwError = GetLastError();
if ( dwError != ERROR_IO_PENDING )
{
//dh::Log( "WaitCommEvent error %x", GetLastError() );
return 1;
}
}
//dh::Log( "WaitCommEvent done" );
// jetzt auf eines der beiden Events warten
hEventGroup[0] = ovCom.hEvent;
DWORD dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, INFINITE );
//dh::Log( "WaitForMultipleObjects returned %d", dwResult );
if ( dwResult == WAIT_OBJECT_0 + 1 )
{
// Ende, Close-Event wieder setzen
dh::Log( "Close-Event" );
SetEvent( m_hCloseEvent );
break;
}
hEventGroup[0] = m_hEventDataReceived;
int iResult = ReadFile( m_hPort, ucLocalBuffer, 512, &dwLocalBytesRead, &m_ovRead );
//dh::Log( "ReadFile returned %d - %d Bytes read", iResult, dwLocalBytesRead );
if ( iResult )
{
//dh::Log( "Received %d Bytes directly", dwLocalBytesRead );
if ( dwLocalBytesRead )
{
//dh::Log( "ReadFile %d bytes read (pos2)", dwLocalBytesRead );
EnterCriticalSection( &m_csIncomingData );
bbIncoming.AppendData( ucLocalBuffer, dwLocalBytesRead );
GR::u32 dwBytesUsed = ReceiveData( bbIncoming );
bbIncoming.TruncateFront( dwBytesUsed );
LeaveCriticalSection( &m_csIncomingData );
// es kamen Daten an
//dh::Log( "Received %d Bytes\n", dwLocalBytesRead );
}
}
else if ( !iResult )
{
// Deal with the error code.
DWORD dwError = GetLastError();
switch ( dwError )
{
case ERROR_HANDLE_EOF:
{
// WCode to handle the end of the file
// during the call to ReadFile
}
break;
case ERROR_IO_PENDING:
{
//dh::Log( "IO pending" );
// Asynchronous I/O is still in progress
// Check on the results of the asynchronous read.
DWORD dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, INFINITE );
//dh::Log( "WaitForMultipleObjects returned %d", dwResult );
if ( dwResult == WAIT_OBJECT_0 )
{
//dh::Log( "Data read" );
BOOL bResult = GetOverlappedResult( m_hPort, &m_ovRead, &dwLocalBytesRead, TRUE );
// If there was a problem
if ( !bResult )
{
// Deal with the error code.
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// We have reached the end of
// the file during asynchronous
// operation.
}
break;
// Deal with other error cases.
} //end switch (dwError = GetLastError())
}
else
{
if ( dwLocalBytesRead )
{
//dh::Log( "ReadFile %d bytes read (pos2)", dwLocalBytesRead );
EnterCriticalSection( &m_csIncomingData );
bbIncoming.AppendData( ucLocalBuffer, dwLocalBytesRead );
GR::u32 dwBytesUsed = ReceiveData( bbIncoming );
bbIncoming.TruncateFront( dwBytesUsed );
LeaveCriticalSection( &m_csIncomingData );
// es kamen Daten an
//dh::Log( "Received %d Bytes\n", dwLocalBytesRead );
}
}
}
else if ( dwResult == WAIT_OBJECT_0 + 1 )
{
dh::Log( "Close Event set -> CancelIO" );
CancelIo( m_hPort );
dh::Log( "done" );
// Event wieder setzen
SetEvent( m_hCloseEvent );
goto leave_loop;
break;
}
}
break;
}
}
}
leave_loop:;
dh::Log( "COM: Left Read Thread" );
return 0;
}
DWORD WorkerThread()
{
dh::Log( "WorkerThread started" );
HANDLE hEventGroup[2];
hEventGroup[0] = m_hEventCloseWorkerThread;
hEventGroup[1] = m_hEventTaskArrived;
dh::Log( "Event %x/%x", m_hCloseEvent, m_hEventTaskArrived );
while ( true )
{
// TODO - auf Schliessen oder neues-Item-Event warten!
dh::Log( "WorkerThread Wait..." );
DWORD dwResult = WaitForMultipleObjects( 2, hEventGroup, FALSE, INFINITE );
dh::Log( "-done %d", dwResult );
if ( dwResult == WAIT_OBJECT_0 )
{
// Ende
dh::Log( "WorkerThread: Close Event received" );
SetEvent( m_hEventCloseWorkerThread );
break;
}
else if ( dwResult == WAIT_OBJECT_0 + 1 )
{
ResetEvent( m_hEventTaskArrived );
// sind noch Tasks vorhanden, dann Event wieder setzen
EnterCriticalSection( &m_csListAccess );
if ( !m_listTasks.empty() )
{
SetEvent( m_hEventTaskArrived );
}
LeaveCriticalSection( &m_csListAccess );
}
else
{
dh::Log( "WorkerThread: Fehler bei WaitForMultipleObjects %d/%x", dwResult, GetLastError() );
}
}
dh::Log( "Worker Thread shut down" );
return 0;
}