update esppilight lib
content of the library is not filtered on 433mhz only
This commit is contained in:
1 parent
a275e48ee1
commit
67dd7ac078
1030 files changed
+203335
-116
No files matched your search
@@ -0,0 +1,410 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SerialControllerImpl.cpp
|
||||
//
|
||||
// Windows Implementation of the cross-platform serial port
|
||||
//
|
||||
// Copyright (c) 2010 Jason Frazier <frazierjason@gmail.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "../../Defs.h"
|
||||
#include "SerialControllerImpl.h"
|
||||
|
||||
#include "../Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
DWORD WINAPI SerialReadThreadEntryPoint( void* _context );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::SerialControllerImpl>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
SerialControllerImpl::SerialControllerImpl
|
||||
(
|
||||
SerialController* _owner
|
||||
):
|
||||
m_owner( _owner )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::~SerialControllerImpl>
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
SerialControllerImpl::~SerialControllerImpl
|
||||
(
|
||||
)
|
||||
{
|
||||
CloseHandle( m_hSerialController );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::Open>
|
||||
// Open the serial port
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SerialControllerImpl::Open
|
||||
(
|
||||
)
|
||||
{
|
||||
// Try to init the serial port
|
||||
if( !Init( 1 ) )
|
||||
{
|
||||
// Failed. We bail to allow the app a chance to take over, rather than retry
|
||||
// automatically. Automatic retries only occur after a successful init.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create an event to trigger exiting the read thread
|
||||
m_hExit = ::CreateEvent( NULL, TRUE, FALSE, NULL );
|
||||
|
||||
// Start the read thread
|
||||
m_hThread = ::CreateThread( NULL, 0, SerialReadThreadEntryPoint, this, CREATE_SUSPENDED, NULL );
|
||||
::ResumeThread( m_hThread );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::Close>
|
||||
// Close the serial port
|
||||
//-----------------------------------------------------------------------------
|
||||
void SerialControllerImpl::Close
|
||||
(
|
||||
)
|
||||
{
|
||||
::SetEvent( m_hExit );
|
||||
::WaitForSingleObject( m_hThread, INFINITE );
|
||||
|
||||
CloseHandle( m_hThread );
|
||||
m_hThread = INVALID_HANDLE_VALUE;
|
||||
|
||||
CloseHandle( m_hExit );
|
||||
m_hExit = INVALID_HANDLE_VALUE;
|
||||
|
||||
CloseHandle( m_hSerialController );
|
||||
m_hSerialController = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialReadThreadEntryPoint>
|
||||
// Entry point of the thread for receiving data from the serial port
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD WINAPI SerialReadThreadEntryPoint
|
||||
(
|
||||
void* _context
|
||||
)
|
||||
{
|
||||
SerialControllerImpl* impl = (SerialControllerImpl*)_context;
|
||||
if( impl )
|
||||
{
|
||||
impl->ReadThreadProc();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::ReadThreadProc>
|
||||
// Handle receiving data
|
||||
//-----------------------------------------------------------------------------
|
||||
void SerialControllerImpl::ReadThreadProc
|
||||
(
|
||||
)
|
||||
{
|
||||
uint32 attempts = 0;
|
||||
while( true )
|
||||
{
|
||||
// Init must have been called successfully during Open, so we
|
||||
// don't do it again until the end of the loop
|
||||
if( INVALID_HANDLE_VALUE != m_hSerialController )
|
||||
{
|
||||
// Enter read loop. Call will only return if
|
||||
// an exit is requested or an error occurs
|
||||
Read();
|
||||
|
||||
// Reset the attempts, so we get a rapid retry for temporary errors
|
||||
attempts = 0;
|
||||
}
|
||||
|
||||
if( attempts < 25 )
|
||||
{
|
||||
// Retry every 5 seconds for the first two minutes...
|
||||
if( WAIT_OBJECT_0 == ::WaitForSingleObject( m_hExit, 5000 ) )
|
||||
{
|
||||
// Exit signalled.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...retry every 30 seconds after that
|
||||
if( WAIT_OBJECT_0 == ::WaitForSingleObject( m_hExit, 30000 ) )
|
||||
{
|
||||
// Exit signalled.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Init( ++attempts );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::Init>
|
||||
// Initialize the serial port
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SerialControllerImpl::Init
|
||||
(
|
||||
uint32 const _attempts
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, " Trying to open serial port %s (Attempt %d)", m_owner->m_serialControllerName.c_str(), _attempts );
|
||||
|
||||
m_hSerialController = CreateFileA( m_owner->m_serialControllerName.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL );
|
||||
|
||||
if( INVALID_HANDLE_VALUE == m_hSerialController )
|
||||
{
|
||||
//Error
|
||||
Log::Write( LogLevel_Error, "ERROR: Cannot open serial port %s. Error code %d\n", m_owner->m_serialControllerName.c_str(), GetLastError() );
|
||||
goto SerialOpenFailure;
|
||||
}
|
||||
|
||||
// Configure the serial device parameters
|
||||
// Build on the current configuration
|
||||
DCB dcb;
|
||||
if( !GetCommState( m_hSerialController, &dcb ) )
|
||||
{
|
||||
//Error. Clean up and exit
|
||||
Log::Write( LogLevel_Error, "ERROR: Failed to read serial port state" );
|
||||
goto SerialOpenFailure;
|
||||
}
|
||||
|
||||
// Fill in the Device Control Block
|
||||
dcb.BaudRate = (DWORD)m_owner->m_baud;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = (BYTE)m_owner->m_parity;
|
||||
dcb.StopBits = (BYTE)m_owner->m_stopBits;
|
||||
|
||||
if( !SetCommState( m_hSerialController, &dcb) )
|
||||
{
|
||||
//Error. Clean up and exit
|
||||
Log::Write( LogLevel_Error, "ERROR: Failed to set serial port state" );
|
||||
goto SerialOpenFailure;
|
||||
}
|
||||
|
||||
// Set the timeouts for the serial port
|
||||
COMMTIMEOUTS commTimeouts;
|
||||
commTimeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
commTimeouts.ReadTotalTimeoutConstant = 0;
|
||||
commTimeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
commTimeouts.WriteTotalTimeoutConstant = 0;
|
||||
commTimeouts.WriteTotalTimeoutMultiplier = 0;
|
||||
if( !SetCommTimeouts( m_hSerialController, &commTimeouts ) )
|
||||
{
|
||||
// Error. Clean up and exit
|
||||
Log::Write( LogLevel_Error, "ERROR: Failed to set serial port timeouts" );
|
||||
goto SerialOpenFailure;
|
||||
}
|
||||
|
||||
// Set the serial port to signal when data is received
|
||||
if( !SetCommMask( m_hSerialController, EV_RXCHAR ) )
|
||||
{
|
||||
//Error. Clean up and exit
|
||||
Log::Write( LogLevel_Info, "ERROR: Failed to set serial port mask" );
|
||||
goto SerialOpenFailure;
|
||||
}
|
||||
|
||||
// Clear any residual data from the serial port
|
||||
PurgeComm( m_hSerialController, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR );
|
||||
|
||||
// Open successful
|
||||
Log::Write( LogLevel_Info, " Serial port %s opened (attempt %d)", m_owner->m_serialControllerName.c_str(), _attempts );
|
||||
return true;
|
||||
|
||||
SerialOpenFailure:
|
||||
Log::Write( LogLevel_Info, "ERROR: Failed to open serial port %s (attempt %d)", m_owner->m_serialControllerName.c_str(), _attempts );
|
||||
CloseHandle( m_hSerialController );
|
||||
m_hSerialController = INVALID_HANDLE_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::Read>
|
||||
// Read data from the serial port
|
||||
//-----------------------------------------------------------------------------
|
||||
void SerialControllerImpl::Read
|
||||
(
|
||||
)
|
||||
{
|
||||
uint8 buffer[256];
|
||||
|
||||
OVERLAPPED overlapped;
|
||||
memset( &overlapped, 0, sizeof(overlapped) );
|
||||
overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||||
|
||||
while( true )
|
||||
{
|
||||
// Try to read all available data from the serial port
|
||||
DWORD bytesRead = 0;
|
||||
do
|
||||
{
|
||||
if( ::ReadFile( m_hSerialController, buffer, 256, NULL, &overlapped ) )
|
||||
{
|
||||
// Read completed
|
||||
GetOverlappedResult( m_hSerialController, &overlapped, &bytesRead, TRUE );
|
||||
|
||||
// Copy to the stream buffer
|
||||
if( bytesRead > 0 )
|
||||
m_owner->Put( buffer, bytesRead );
|
||||
}
|
||||
else
|
||||
{
|
||||
//Wait for the read to complete
|
||||
if( ERROR_IO_PENDING == GetLastError() )
|
||||
{
|
||||
// Wait for the read to complete or the
|
||||
// signal that this thread should exit.
|
||||
HANDLE handles[2];
|
||||
handles[0] = overlapped.hEvent;
|
||||
handles[1] = m_hExit;
|
||||
DWORD res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
|
||||
|
||||
if( (WAIT_OBJECT_0+1) == res )
|
||||
{
|
||||
// Exit signalled. Cancel the read.
|
||||
goto exitRead;
|
||||
}
|
||||
|
||||
if( WAIT_TIMEOUT == res )
|
||||
{
|
||||
// Timed out - should never happen
|
||||
goto exitRead;
|
||||
}
|
||||
|
||||
// Read completed
|
||||
GetOverlappedResult( m_hSerialController, &overlapped, &bytesRead, TRUE );
|
||||
|
||||
// Copy to the stream buffer
|
||||
if( bytesRead > 0 )
|
||||
m_owner->Put( buffer, bytesRead );
|
||||
}
|
||||
else
|
||||
{
|
||||
// An error has occurred
|
||||
goto exitRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
while( bytesRead > 0 );
|
||||
|
||||
// Clear the event
|
||||
ResetEvent( overlapped.hEvent );
|
||||
|
||||
// Nothing available to read, so wait for the next rx char event
|
||||
DWORD dwEvtMask;
|
||||
if( !WaitCommEvent( m_hSerialController, &dwEvtMask, &overlapped ) )
|
||||
{
|
||||
if( ERROR_IO_PENDING == GetLastError() )
|
||||
{
|
||||
// Wait for either some data to arrive or
|
||||
// the signal that this thread should exit.
|
||||
HANDLE handles[2];
|
||||
handles[0] = overlapped.hEvent;
|
||||
handles[1] = m_hExit;
|
||||
|
||||
DWORD res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
|
||||
|
||||
if( (WAIT_OBJECT_0+1) == res )
|
||||
{
|
||||
// Exit signalled. Prevent WaitCommEvent from corrupting the
|
||||
// stack by forcing it to exit.
|
||||
goto exitRead;
|
||||
}
|
||||
|
||||
if( WAIT_TIMEOUT == res )
|
||||
{
|
||||
// Timed out - should never happen
|
||||
goto exitRead;
|
||||
}
|
||||
|
||||
GetOverlappedResult( m_hSerialController, &overlapped, &bytesRead, TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the event
|
||||
ResetEvent( overlapped.hEvent );
|
||||
|
||||
// Loop back to the top to read the waiting data
|
||||
}
|
||||
|
||||
exitRead:
|
||||
// Exit event has been signalled, or an error has occurred
|
||||
SetCommMask( m_hSerialController, 0 );
|
||||
CancelIo( m_hSerialController );
|
||||
CloseHandle( overlapped.hEvent );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SerialControllerImpl::Write>
|
||||
// Send data to the serial port
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 SerialControllerImpl::Write
|
||||
(
|
||||
uint8* _buffer,
|
||||
uint32 _length
|
||||
)
|
||||
{
|
||||
if( INVALID_HANDLE_VALUE == m_hSerialController )
|
||||
{
|
||||
//Error
|
||||
Log::Write( LogLevel_Error, "ERROR: Serial port must be opened before writing\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write the data
|
||||
OVERLAPPED overlapped;
|
||||
memset( &overlapped, 0, sizeof(overlapped) );
|
||||
overlapped.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||||
|
||||
DWORD bytesWritten;
|
||||
if( !::WriteFile( m_hSerialController, _buffer, _length, &bytesWritten, &overlapped ) )
|
||||
{
|
||||
//Wait for the write to complete
|
||||
if( ERROR_IO_PENDING == GetLastError() )
|
||||
{
|
||||
GetOverlappedResult( m_hSerialController, &overlapped, &bytesWritten, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Error, "ERROR: Serial port write (0x%.8x)", GetLastError() );
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle( overlapped.hEvent );
|
||||
return (uint32)bytesWritten;
|
||||
}
|
||||
Reference in new issue
Block a user