diff --git a/.gitignore b/.gitignore index 8c4f3b3..4cc8857 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ Project/Objects +Window Tool/TimeSet/.vs/TimeSet/v15/ipch +*.db +*.zip +Window Tool/TimeSet/TimeSet/Debug diff --git a/Window Tool/TimeSet/.vs/TimeSet/v15/.suo b/Window Tool/TimeSet/.vs/TimeSet/v15/.suo new file mode 100644 index 0000000..6e6ba91 Binary files /dev/null and b/Window Tool/TimeSet/.vs/TimeSet/v15/.suo differ diff --git a/Window Tool/TimeSet/Debug/TimeSet.exe b/Window Tool/TimeSet/Debug/TimeSet.exe new file mode 100644 index 0000000..55a8041 Binary files /dev/null and b/Window Tool/TimeSet/Debug/TimeSet.exe differ diff --git a/Window Tool/TimeSet/Debug/TimeSet.ilk b/Window Tool/TimeSet/Debug/TimeSet.ilk new file mode 100644 index 0000000..c05de5f Binary files /dev/null and b/Window Tool/TimeSet/Debug/TimeSet.ilk differ diff --git a/Window Tool/TimeSet/Debug/TimeSet.pdb b/Window Tool/TimeSet/Debug/TimeSet.pdb new file mode 100644 index 0000000..1ef21bb Binary files /dev/null and b/Window Tool/TimeSet/Debug/TimeSet.pdb differ diff --git a/Window Tool/TimeSet/TimeSet.sln b/Window Tool/TimeSet/TimeSet.sln new file mode 100644 index 0000000..764e2a7 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.1401 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TimeSet", "TimeSet\TimeSet.vcxproj", "{12662F45-5722-45B9-8C02-2863C436C1F6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12662F45-5722-45B9-8C02-2863C436C1F6}.Debug|x64.ActiveCfg = Debug|x64 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Debug|x64.Build.0 = Debug|x64 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Debug|x86.ActiveCfg = Debug|Win32 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Debug|x86.Build.0 = Debug|Win32 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Release|x64.ActiveCfg = Release|x64 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Release|x64.Build.0 = Release|x64 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Release|x86.ActiveCfg = Release|Win32 + {12662F45-5722-45B9-8C02-2863C436C1F6}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A2480CF4-9A89-4EA6-9387-EA6A5BBCAD06} + EndGlobalSection +EndGlobal diff --git a/Window Tool/TimeSet/TimeSet/Serial.cpp b/Window Tool/TimeSet/TimeSet/Serial.cpp new file mode 100644 index 0000000..22c8c9f --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/Serial.cpp @@ -0,0 +1,1431 @@ +// Serial.cpp - Implementation of the CSerial class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +////////////////////////////////////////////////////////////////////// +// Include the standard header files + + +#include +#include +#include + + +////////////////////////////////////////////////////////////////////// +// Include module headerfile +#include "pch.h" +#include "Serial.h" + + +////////////////////////////////////////////////////////////////////// +// Disable warning C4127: conditional expression is constant, which +// is generated when using the _RPTF and _ASSERTE macros. + +#pragma warning(disable: 4127) + + +////////////////////////////////////////////////////////////////////// +// Enable debug memory manager + +#ifdef _DEBUG + +#ifdef THIS_FILE +#undef THIS_FILE +#endif + +static const char THIS_FILE[] = __FILE__; +#define new DEBUG_NEW + +#endif + + +////////////////////////////////////////////////////////////////////// +// Helper methods + +inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const +{ +#ifdef SERIAL_NO_OVERLAPPED + + // Check if an overlapped structure has been specified + if (lpOverlapped || (dwTimeout != INFINITE)) + { + // Quit application + ::MessageBox(0,_T("Overlapped I/O and time-outs are not supported, when overlapped I/O is disabled."),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL); + ::DebugBreak(); + ::ExitProcess(0xFFFFFFF); + } + +#endif + +#ifdef SERIAL_NO_CANCELIO + + // Check if 0 or INFINITE time-out has been specified, because + // the communication I/O cannot be cancelled. + if ((dwTimeout != 0) && (dwTimeout != INFINITE)) + { + // Quit application + ::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL); + ::DebugBreak(); + ::ExitProcess(0xFFFFFFF); + } + +#endif // SERIAL_NO_CANCELIO + + // Avoid warnings + (void) dwTimeout; + (void) lpOverlapped; +} + +inline BOOL CSerial::CancelCommIo (void) +{ +#ifdef SERIAL_NO_CANCELIO + // CancelIo shouldn't have been called at this point + ::DebugBreak(); + return FALSE; +#else + + // Cancel the I/O request + return ::CancelIo(m_hFile); + +#endif // SERIAL_NO_CANCELIO +} + + +////////////////////////////////////////////////////////////////////// +// Code + +CSerial::CSerial () + : m_lLastError(ERROR_SUCCESS) + , m_hFile(0) + , m_eEvent(EEventNone) + , m_dwEventMask(0) +#ifndef SERIAL_NO_OVERLAPPED + , m_hevtOverlapped(0) +#endif +{ +} + +CSerial::~CSerial () +{ + // If the device is already closed, + // then we don't need to do anything. + if (m_hFile) + { + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n"); + + // Close implicitly + Close(); + } +} + +CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice) +{ + // Try to open the device + HANDLE hFile = ::CreateFile(lpszDevice, + GENERIC_READ|GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + 0, + 0); + + // Check if we could open the device + if (hFile == INVALID_HANDLE_VALUE) + { + // Display error + switch (::GetLastError()) + { + case ERROR_FILE_NOT_FOUND: + // The specified COM-port does not exist + return EPortNotAvailable; + + case ERROR_ACCESS_DENIED: + // The specified COM-port is in use + return EPortInUse; + + default: + // Something else is wrong + return EPortUnknownError; + } + } + + // Close handle + ::CloseHandle(hFile); + + // Port is available + return EPortAvailable; +} + +LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the port isn't already opened + if (m_hFile) + { + m_lLastError = ERROR_ALREADY_INITIALIZED; + _RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n"); + return m_lLastError; + } + + // Open the device + + m_hFile = ::CreateFile(lpszDevice, + GENERIC_READ|GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + fOverlapped ? FILE_FLAG_OVERLAPPED : 0, + 0); + + + if (m_hFile == INVALID_HANDLE_VALUE) + { + // Reset file handle + m_hFile = 0; + + // Display error + m_lLastError = ::GetLastError(); + _RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n"); + return m_lLastError; + } + +#ifndef SERIAL_NO_OVERLAPPED + // We cannot have an event handle yet + _ASSERTE(m_hevtOverlapped == 0); + + // Create the event handle for internal overlapped operations (manual reset) + if (fOverlapped) + { + m_hevtOverlapped = ::CreateEvent(0,true,false,0); + if (m_hevtOverlapped == 0) + { + // Obtain the error information + m_lLastError = ::GetLastError(); + _RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n"); + + // Close the port + ::CloseHandle(m_hFile); + m_hFile = 0; + + // Return the error + return m_lLastError; + } + } +#else + + // Overlapped flag shouldn't be specified + _ASSERTE(!fOverlapped); + +#endif + + // Setup the COM-port + if (dwInQueue || dwOutQueue) + { + // Make sure the queue-sizes are reasonable sized. Win9X systems crash + // if the input queue-size is zero. Both queues need to be at least + // 16 bytes large. + _ASSERTE(dwInQueue >= 16); + _ASSERTE(dwOutQueue >= 16); + + if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue)) + { + // Display a warning + long lLastError = ::GetLastError(); + _RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n"); + + // Close the port + Close(); + + // Save last error from SetupComm + m_lLastError = lLastError; + return m_lLastError; + } + } + + // Setup the default communication mask + SetMask(); + + // Non-blocking reads is default + SetupReadTimeouts(EReadTimeoutNonblocking); + + // Setup the device for default settings + COMMCONFIG commConfig = {0}; + DWORD dwSize = sizeof(commConfig); + commConfig.dwSize = dwSize; + if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize)) + { + // Set the default communication configuration + if (!::SetCommConfig(m_hFile,&commConfig,dwSize)) + { + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n"); + } + } + else + { + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n"); + } + + // Return successful + return m_lLastError; +} + +LONG CSerial::Close (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // If the device is already closed, + // then we don't need to do anything. + if (m_hFile == 0) + { + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n"); + return m_lLastError; + } + +#ifndef SERIAL_NO_OVERLAPPED + // Free event handle + if (m_hevtOverlapped) + { + ::CloseHandle(m_hevtOverlapped); + m_hevtOverlapped = 0; + } +#endif + + // Close COM port + ::CloseHandle(m_hFile); + m_hFile = 0; + + // Return successful + return m_lLastError; +} + +LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n"); + return m_lLastError; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = :: GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n"); + return m_lLastError; + } + + // Set the new data + dcb.BaudRate = DWORD(eBaudrate); + dcb.ByteSize = BYTE(eDataBits); + dcb.Parity = BYTE(eParity); + dcb.StopBits = BYTE(eStopBits); + + // Determine if parity is used + dcb.fParity = (eParity != EParNone); + + // Set the new DCB structure + if (!::SetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n"); + return m_lLastError; + } + + // Return successful + return m_lLastError; +} + +LONG CSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n"); + return m_lLastError; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n"); + return m_lLastError; + } + + // Set the new event character + dcb.EvtChar = char(bEventChar); + + // Adjust the event mask, to make sure the event will be received + if (fAdjustMask) + { + // Enable 'receive event character' event. Note that this + // will generate an EEventNone if there is an asynchronous + // WaitCommEvent pending. + SetMask(GetEventMask() | EEventRcvEv); + } + + // Set the new DCB structure + if (!::SetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n"); + return m_lLastError; + } + + // Return successful + return m_lLastError; +} + +LONG CSerial::SetMask (DWORD dwEventMask) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n"); + return m_lLastError; + } + + // Set the new mask. Note that this will generate an EEventNone + // if there is an asynchronous WaitCommEvent pending. + if (!::SetCommMask(m_hFile,dwEventMask)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n"); + return m_lLastError; + } + + // Save event mask and return successful + m_dwEventMask = dwEventMask; + return m_lLastError; +} + +LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) +{ + // Check if time-outs are supported + CheckRequirements(lpOverlapped,dwTimeout); + + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n"); + return m_lLastError; + } + +#ifndef SERIAL_NO_OVERLAPPED + + // Check if an overlapped structure has been specified + if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE))) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_FUNCTION; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n"); + return m_lLastError; + } + + // Wait for the event to happen + OVERLAPPED ovInternal; + if (!lpOverlapped && m_hevtOverlapped) + { + // Setup our own overlapped structure + memset(&ovInternal,0,sizeof(ovInternal)); + ovInternal.hEvent = m_hevtOverlapped; + + // Use our internal overlapped structure + lpOverlapped = &ovInternal; + } + + // Make sure the overlapped structure isn't busy + _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped)); + + // Wait for the COM event + if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped)) + { + // Set the internal error code + long lLastError = ::GetLastError(); + + // Overlapped operation in progress is not an actual error + if (lLastError != ERROR_IO_PENDING) + { + // Save the error + m_lLastError = lLastError; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n"); + return m_lLastError; + } + + // We need to block if the client didn't specify an overlapped structure + if (lpOverlapped == &ovInternal) + { + // Wait for the overlapped operation to complete + switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)) + { + case WAIT_OBJECT_0: + // The overlapped operation has completed + break; + + case WAIT_TIMEOUT: + // Cancel the I/O operation + CancelCommIo(); + + // The operation timed out. Set the internal error code and quit + m_lLastError = ERROR_TIMEOUT; + return m_lLastError; + + default: + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait until COM event has arrived\n"); + return m_lLastError; + } + } + } + else + { + // The operation completed immediatly. Just to be sure + // we'll set the overlapped structure's event handle. + if (lpOverlapped) + ::SetEvent(lpOverlapped->hEvent); + } +#else + + // Wait for the COM event + if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),0)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n"); + return m_lLastError; + } + +#endif + + // Return successfully + return m_lLastError; +} + + +LONG CSerial::SetupHandshaking (EHandshake eHandshake) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Device is not opened\n"); + return m_lLastError; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to obtain DCB information\n"); + return m_lLastError; + } + + // Set the handshaking flags + switch (eHandshake) + { + case EHandshakeOff: + dcb.fOutxCtsFlow = false; // Disable CTS monitoring + dcb.fOutxDsrFlow = false; // Disable DSR monitoring + dcb.fDtrControl = DTR_CONTROL_DISABLE; // Disable DTR monitoring + dcb.fOutX = false; // Disable XON/XOFF for transmission + dcb.fInX = false; // Disable XON/XOFF for receiving + dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send) + break; + + case EHandshakeHardware: + dcb.fOutxCtsFlow = true; // Enable CTS monitoring + dcb.fOutxDsrFlow = true; // Enable DSR monitoring + dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; // Enable DTR handshaking + dcb.fOutX = false; // Disable XON/XOFF for transmission + dcb.fInX = false; // Disable XON/XOFF for receiving + dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTS handshaking + break; + + case EHandshakeSoftware: + dcb.fOutxCtsFlow = false; // Disable CTS (Clear To Send) + dcb.fOutxDsrFlow = false; // Disable DSR (Data Set Ready) + dcb.fDtrControl = DTR_CONTROL_DISABLE; // Disable DTR (Data Terminal Ready) + dcb.fOutX = true; // Enable XON/XOFF for transmission + dcb.fInX = true; // Enable XON/XOFF for receiving + dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send) + break; + + default: + // This shouldn't be possible + _ASSERTE(false); + m_lLastError = E_INVALIDARG; + return m_lLastError; + } + + // Set the new DCB structure + if (!::SetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to set DCB information\n"); + return m_lLastError; + } + + // Return successful + return m_lLastError; +} + +LONG CSerial::SetupReadTimeouts (EReadTimeout eReadTimeout) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Device is not opened\n"); + return m_lLastError; + } + + // Determine the time-outs + COMMTIMEOUTS cto; + if (!::GetCommTimeouts(m_hFile,&cto)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to obtain timeout information\n"); + return m_lLastError; + } + + // Set the new timeouts + switch (eReadTimeout) + { + case EReadTimeoutBlocking: + cto.ReadIntervalTimeout = 0; + cto.ReadTotalTimeoutConstant = 0; + cto.ReadTotalTimeoutMultiplier = 0; + break; + case EReadTimeoutNonblocking: + cto.ReadIntervalTimeout = MAXDWORD; + cto.ReadTotalTimeoutConstant = 0; + cto.ReadTotalTimeoutMultiplier = 0; + break; + default: + // This shouldn't be possible + _ASSERTE(false); + m_lLastError = E_INVALIDARG; + return m_lLastError; + } + + // Set the new DCB structure + if (!::SetCommTimeouts(m_hFile,&cto)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n"); + return m_lLastError; + } + + // Return successful + return m_lLastError; +} + +CSerial::EBaudrate CSerial::GetBaudrate (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Device is not opened\n"); + return EBaudUnknown; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Unable to obtain DCB information\n"); + return EBaudUnknown; + } + + // Return the appropriate baudrate + return EBaudrate(dcb.BaudRate); +} + +CSerial::EDataBits CSerial::GetDataBits (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetDataBits - Device is not opened\n"); + return EDataUnknown; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetDataBits - Unable to obtain DCB information\n"); + return EDataUnknown; + } + + // Return the appropriate bytesize + return EDataBits(dcb.ByteSize); +} + +CSerial::EParity CSerial::GetParity (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetParity - Device is not opened\n"); + return EParUnknown; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetParity - Unable to obtain DCB information\n"); + return EParUnknown; + } + + // Check if parity is used + if (!dcb.fParity) + { + // No parity + return EParNone; + } + + // Return the appropriate parity setting + return EParity(dcb.Parity); +} + +CSerial::EStopBits CSerial::GetStopBits (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetStopBits - Device is not opened\n"); + return EStopUnknown; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetStopBits - Unable to obtain DCB information\n"); + return EStopUnknown; + } + + // Return the appropriate stopbits + return EStopBits(dcb.StopBits); +} + +DWORD CSerial::GetEventMask (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetEventMask - Device is not opened\n"); + return 0; + } + + // Return the event mask + return m_dwEventMask; +} + +BYTE CSerial::GetEventChar (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetEventChar - Device is not opened\n"); + return 0; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetEventChar - Unable to obtain DCB information\n"); + return 0; + } + + // Set the new event character + return BYTE(dcb.EvtChar); +} + +CSerial::EHandshake CSerial::GetHandshaking (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Device is not opened\n"); + return EHandshakeUnknown; + } + + // Obtain the DCB structure for the device + CDCB dcb; + if (!::GetCommState(m_hFile,&dcb)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Unable to obtain DCB information\n"); + return EHandshakeUnknown; + } + + // Check if hardware handshaking is being used + if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE)) + return EHandshakeHardware; + + // Check if software handshaking is being used + if (dcb.fOutX && dcb.fInX) + return EHandshakeSoftware; + + // No handshaking is being used + return EHandshakeOff; +} + +LONG CSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) +{ + // Check if time-outs are supported + CheckRequirements(lpOverlapped,dwTimeout); + + // Overlapped operation should specify the pdwWritten variable + _ASSERTE(!lpOverlapped || pdwWritten); + + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Use our own variable for read count + DWORD dwWritten; + if (pdwWritten == 0) + { + pdwWritten = &dwWritten; + } + + // Reset the number of bytes written + *pdwWritten = 0; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Write - Device is not opened\n"); + return m_lLastError; + } + +#ifndef SERIAL_NO_OVERLAPPED + + // Check if an overlapped structure has been specified + if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE))) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_FUNCTION; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped I/O is disabled, specified parameters are illegal.\n"); + return m_lLastError; + } + + // Wait for the event to happen + OVERLAPPED ovInternal; + if (!lpOverlapped && m_hevtOverlapped) + { + // Setup our own overlapped structure + memset(&ovInternal,0,sizeof(ovInternal)); + ovInternal.hEvent = m_hevtOverlapped; + + // Use our internal overlapped structure + lpOverlapped = &ovInternal; + } + + // Make sure the overlapped structure isn't busy + _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped)); + + // Write the data + if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped)) + { + // Set the internal error code + long lLastError = ::GetLastError(); + + // Overlapped operation in progress is not an actual error + if (lLastError != ERROR_IO_PENDING) + { + // Save the error + m_lLastError = lLastError; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n"); + return m_lLastError; + } + + // We need to block if the client didn't specify an overlapped structure + if (lpOverlapped == &ovInternal) + { + // Wait for the overlapped operation to complete + switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)) + { + case WAIT_OBJECT_0: + // The overlapped operation has completed + if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped completed without result\n"); + return m_lLastError; + } + break; + + case WAIT_TIMEOUT: + // Cancel the I/O operation + CancelCommIo(); + + // The operation timed out. Set the internal error code and quit + m_lLastError = ERROR_TIMEOUT; + return m_lLastError; + + default: + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Write - Unable to wait until data has been sent\n"); + return m_lLastError; + } + } + } + else + { + // The operation completed immediatly. Just to be sure + // we'll set the overlapped structure's event handle. + if (lpOverlapped) + ::SetEvent(lpOverlapped->hEvent); + } + +#else + + // Write the data + if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,0)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n"); + return m_lLastError; + } + +#endif + + // Return successfully + return m_lLastError; +} + +LONG CSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) +{ + // Check if time-outs are supported + CheckRequirements(lpOverlapped,dwTimeout); + + // Determine the length of the string + return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout); +} + +LONG CSerial::Read (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) +{ + // Check if time-outs are supported + CheckRequirements(lpOverlapped,dwTimeout); + + // Overlapped operation should specify the pdwRead variable + _ASSERTE(!lpOverlapped || pdwRead); + + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Use our own variable for read count + DWORD dwRead; + if (pdwRead == 0) + { + pdwRead = &dwRead; + } + + // Reset the number of bytes read + *pdwRead = 0; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Read - Device is not opened\n"); + return m_lLastError; + } + +#ifdef _DEBUG + // The debug version fills the entire data structure with + // 0xDC bytes, to catch buffer errors as soon as possible. + memset(pData,0xDC,iLen); +#endif + +#ifndef SERIAL_NO_OVERLAPPED + + // Check if an overlapped structure has been specified + if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE))) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_FUNCTION; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped I/O is disabled, specified parameters are illegal.\n"); + return m_lLastError; + } + + // Wait for the event to happen + OVERLAPPED ovInternal; + if (lpOverlapped == 0) + { + // Setup our own overlapped structure + memset(&ovInternal,0,sizeof(ovInternal)); + ovInternal.hEvent = m_hevtOverlapped; + + // Use our internal overlapped structure + lpOverlapped = &ovInternal; + } + + // Make sure the overlapped structure isn't busy + _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped)); + + // Read the data + if (!::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped)) + { + // Set the internal error code + long lLastError = ::GetLastError(); + + // Overlapped operation in progress is not an actual error + if (lLastError != ERROR_IO_PENDING) + { + // Save the error + m_lLastError = lLastError; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n"); + return m_lLastError; + } + + // We need to block if the client didn't specify an overlapped structure + if (lpOverlapped == &ovInternal) + { + // Wait for the overlapped operation to complete + switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)) + { + case WAIT_OBJECT_0: + // The overlapped operation has completed + if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped completed without result\n"); + return m_lLastError; + } + break; + + case WAIT_TIMEOUT: + // Cancel the I/O operation + CancelCommIo(); + + // The operation timed out. Set the internal error code and quit + m_lLastError = ERROR_TIMEOUT; + return m_lLastError; + + default: + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Read - Unable to wait until data has been read\n"); + return m_lLastError; + } + } + } + else + { + // The operation completed immediatly. Just to be sure + // we'll set the overlapped structure's event handle. + if (lpOverlapped) + ::SetEvent(lpOverlapped->hEvent); + } + +#else + + // Read the data + if (!::ReadFile(m_hFile,pData,iLen,pdwRead,0)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n"); + return m_lLastError; + } + +#endif + + // Return successfully + return m_lLastError; +} + +LONG CSerial::Purge() +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Purge - Device is not opened\n"); + return m_lLastError; + } + + if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + _RPTF0(_CRT_WARN,"CSerial::Purge - Overlapped completed without result\n"); + } + + // Return successfully + return m_lLastError; +} + +LONG CSerial::Break (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::Break - Device is not opened\n"); + return m_lLastError; + } + + // Set the RS-232 port in break mode for a little while + ::SetCommBreak(m_hFile); + ::Sleep(100); + ::ClearCommBreak(m_hFile); + + // Return successfully + return m_lLastError; +} + +CSerial::EEvent CSerial::GetEventType (void) +{ +#ifdef _DEBUG + // Check if the event is within the mask + if ((m_eEvent & m_dwEventMask) == 0) + _RPTF2(_CRT_WARN,"CSerial::GetEventType - Event %08Xh not within mask %08Xh.\n", m_eEvent, m_dwEventMask); +#endif + + // Obtain the event (mask unwanted events out) + EEvent eEvent = EEvent(m_eEvent & m_dwEventMask); + + // Reset internal event type + m_eEvent = EEventNone; + + // Return the current cause + return eEvent; +} + +CSerial::EError CSerial::GetError (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Check if the device is open + if (m_hFile == 0) + { + // Set the internal error code + m_lLastError = ERROR_INVALID_HANDLE; + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetError - Device is not opened\n"); + return EErrorUnknown; + } + + // Obtain COM status + DWORD dwErrors = 0; + if (!::ClearCommError(m_hFile,&dwErrors,0)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerial::GetError - Unable to obtain COM status\n"); + return EErrorUnknown; + } + + // Return the error + return EError(dwErrors); +} + +bool CSerial::GetCTS (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Obtain the modem status + DWORD dwModemStat = 0; + if (!::GetCommModemStatus(m_hFile,&dwModemStat)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetCTS - Unable to obtain the modem status\n"); + return false; + } + + // Determine if CTS is on + return (dwModemStat & MS_CTS_ON) != 0; +} + +bool CSerial::GetDSR (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Obtain the modem status + DWORD dwModemStat = 0; + if (!::GetCommModemStatus(m_hFile,&dwModemStat)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetDSR - Unable to obtain the modem status\n"); + return false; + } + + // Determine if DSR is on + return (dwModemStat & MS_DSR_ON) != 0; +} + +bool CSerial::GetRing (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Obtain the modem status + DWORD dwModemStat = 0; + if (!::GetCommModemStatus(m_hFile,&dwModemStat)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetRing - Unable to obtain the modem status"); + return false; + } + + // Determine if Ring is on + return (dwModemStat & MS_RING_ON) != 0; +} + +bool CSerial::GetRLSD (void) +{ + // Reset error state + m_lLastError = ERROR_SUCCESS; + + // Obtain the modem status + DWORD dwModemStat = 0; + if (!::GetCommModemStatus(m_hFile,&dwModemStat)) + { + // Obtain the error code + m_lLastError = ::GetLastError(); + + // Display a warning + _RPTF0(_CRT_WARN,"CSerial::GetRLSD - Unable to obtain the modem status"); + return false; + } + + // Determine if RLSD is on + return (dwModemStat & MS_RLSD_ON) != 0; +} diff --git a/Window Tool/TimeSet/TimeSet/Serial.h b/Window Tool/TimeSet/TimeSet/Serial.h new file mode 100644 index 0000000..c4d1879 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/Serial.h @@ -0,0 +1,367 @@ +// Serial.h - Definition of the CSerial class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#ifndef __SERIAL_H +#define __SERIAL_H + + +////////////////////////////////////////////////////////////////////// +// The SERIAL_DEFAULT_OVERLAPPED defines if the default open mode uses +// overlapped I/O. When overlapped I/O is available (normal Win32 +// platforms) it uses overlapped I/O. Windows CE doesn't allow the use +// of overlapped I/O, so it is disabled there by default. + +#ifndef SERIAL_DEFAULT_OVERLAPPED +#ifndef SERIAL_NO_OVERLAPPED +#define SERIAL_DEFAULT_OVERLAPPED true +#else +#define SERIAL_DEFAULT_OVERLAPPED false +#endif +#endif + + +////////////////////////////////////////////////////////////////////// +// +// CSerial - Win32 wrapper for serial communications +// +// Serial communication often causes a lot of problems. This class +// tries to supply an easy to use interface to deal with serial +// devices. +// +// The class is actually pretty ease to use. You only need to open +// the COM-port, where you need to specify the basic serial +// communication parameters. You can also choose to setup handshaking +// and read timeout behaviour. +// +// The following serial classes are available: +// +// CSerial - Serial communication support. +// CSerialEx - Serial communication with listener thread for events +// CSerialSync - Serial communication with synchronized event handler +// CSerialWnd - Asynchronous serial support, which uses the Win32 +// message queue for event notification. +// CSerialMFC - Preferred class to use in MFC-based GUI windows. +// +// +// Pros: +// ----- +// - Easy to use (hides a lot of nasty Win32 stuff) +// - Fully ANSI and Unicode aware +// +// Cons: +// ----- +// - Little less flexibility then native Win32 API, however you can +// use this API at the same time for features which are missing +// from this class. +// - Incompatible with Windows 95 or Windows NT v3.51 (or earlier), +// because CancelIo isn't support on these platforms. Define the +// SERIAL_NO_CANCELIO macro for support of these platforms as +// well. When this macro is defined, then only time-out values of +// 0 or INFINITE are valid. +// +// +// Copyright (C) 1999-2003 Ramon de Klein +// (Ramon.de.Klein@ict.nl) + +class CSerial +{ +// Class enumerations +public: + // Communication event + typedef enum + { + EEventUnknown = -1, // Unknown event + EEventNone = 0, // Event trigged without cause + EEventBreak = EV_BREAK, // A break was detected on input + EEventCTS = EV_CTS, // The CTS signal changed state + EEventDSR = EV_DSR, // The DSR signal changed state + EEventError = EV_ERR, // A line-status error occurred + EEventRing = EV_RING, // A ring indicator was detected + EEventRLSD = EV_RLSD, // The RLSD signal changed state + EEventRecv = EV_RXCHAR, // Data is received on input + EEventRcvEv = EV_RXFLAG, // Event character was received on input + EEventSend = EV_TXEMPTY, // Last character on output was sent + EEventPrinterError = EV_PERR, // Printer error occured + EEventRx80Full = EV_RX80FULL, // Receive buffer is 80 percent full + EEventProviderEvt1 = EV_EVENT1, // Provider specific event 1 + EEventProviderEvt2 = EV_EVENT2, // Provider specific event 2 + } + EEvent; + + // Baudrate + typedef enum + { + EBaudUnknown = -1, // Unknown + EBaud110 = CBR_110, // 110 bits/sec + EBaud300 = CBR_300, // 300 bits/sec + EBaud600 = CBR_600, // 600 bits/sec + EBaud1200 = CBR_1200, // 1200 bits/sec + EBaud2400 = CBR_2400, // 2400 bits/sec + EBaud4800 = CBR_4800, // 4800 bits/sec + EBaud9600 = CBR_9600, // 9600 bits/sec + EBaud14400 = CBR_14400, // 14400 bits/sec + EBaud19200 = CBR_19200, // 19200 bits/sec (default) + EBaud38400 = CBR_38400, // 38400 bits/sec + EBaud56000 = CBR_56000, // 56000 bits/sec + EBaud57600 = CBR_57600, // 57600 bits/sec + EBaud115200 = CBR_115200, // 115200 bits/sec + EBaud128000 = CBR_128000, // 128000 bits/sec + EBaud256000 = CBR_256000, // 256000 bits/sec + } + EBaudrate; + + // Data bits (5-8) + typedef enum + { + EDataUnknown = -1, // Unknown + EData5 = 5, // 5 bits per byte + EData6 = 6, // 6 bits per byte + EData7 = 7, // 7 bits per byte + EData8 = 8 // 8 bits per byte (default) + } + EDataBits; + + // Parity scheme + typedef enum + { + EParUnknown = -1, // Unknown + EParNone = NOPARITY, // No parity (default) + EParOdd = ODDPARITY, // Odd parity + EParEven = EVENPARITY, // Even parity + EParMark = MARKPARITY, // Mark parity + EParSpace = SPACEPARITY // Space parity + } + EParity; + + // Stop bits + typedef enum + { + EStopUnknown = -1, // Unknown + EStop1 = ONESTOPBIT, // 1 stopbit (default) + EStop1_5 = ONE5STOPBITS,// 1.5 stopbit + EStop2 = TWOSTOPBITS // 2 stopbits + } + EStopBits; + + // Handshaking + typedef enum + { + EHandshakeUnknown = -1, // Unknown + EHandshakeOff = 0, // No handshaking + EHandshakeHardware = 1, // Hardware handshaking (RTS/CTS) + EHandshakeSoftware = 2 // Software handshaking (XON/XOFF) + } + EHandshake; + + // Timeout settings + typedef enum + { + EReadTimeoutUnknown = -1, // Unknown + EReadTimeoutNonblocking = 0, // Always return immediately + EReadTimeoutBlocking = 1 // Block until everything is retrieved + } + EReadTimeout; + + // Communication errors + typedef enum + { + EErrorUnknown = 0, // Unknown + EErrorBreak = CE_BREAK, // Break condition detected + EErrorFrame = CE_FRAME, // Framing error + EErrorIOE = CE_IOE, // I/O device error + EErrorMode = CE_MODE, // Unsupported mode + EErrorOverrun = CE_OVERRUN, // Character buffer overrun, next byte is lost + EErrorRxOver = CE_RXOVER, // Input buffer overflow, byte lost + EErrorParity = CE_RXPARITY,// Input parity error + EErrorTxFull = CE_TXFULL // Output buffer full + } + EError; + + // Port availability + typedef enum + { + EPortUnknownError = -1, // Unknown error occurred + EPortAvailable = 0, // Port is available + EPortNotAvailable = 1, // Port is not present + EPortInUse = 2 // Port is in use + + } + EPort; + +// Construction +public: + CSerial(); + virtual ~CSerial(); + +// Operations +public: + // Check if particular COM-port is available (static method). + static EPort CheckPort (LPCTSTR lpszDevice); + + // Open the serial communications for a particular COM port. You + // need to use the full devicename (i.e. "COM1") to open the port. + // It's possible to specify the size of the input/output queues. + virtual LONG Open (LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0, bool fOverlapped = SERIAL_DEFAULT_OVERLAPPED); + + // Close the serial port. + virtual LONG Close (void); + + // Setup the communication settings such as baudrate, databits, + // parity and stopbits. The default settings are applied when the + // device has been opened. Call this function if these settings do + // not apply for your application. If you prefer to use integers + // instead of the enumerated types then just cast the integer to + // the required type. So the following two initializations are + // equivalent: + // + // Setup(EBaud9600,EData8,EParNone,EStop1) + // + // or + // + // Setup(EBaudrate(9600),EDataBits(8),EParity(NOPARITY),EStopBits(ONESTOPBIT)) + // + // In the latter case, the types are not validated. So make sure + // that you specify the appropriate values. + virtual LONG Setup (EBaudrate eBaudrate = EBaud9600, + EDataBits eDataBits = EData8, + EParity eParity = EParNone, + EStopBits eStopBits = EStop1); + + // Set/clear the event character. When this byte is being received + // on the serial port then the EEventRcvEv event is signalled, + // when the mask has been set appropriately. If the fAdjustMask flag + // has been set, then the event mask is automatically adjusted. + virtual LONG SetEventChar (BYTE bEventChar, bool fAdjustMask = true); + + // Set the event mask, which indicates what events should be + // monitored. The WaitEvent method can only monitor events that + // have been enabled. The default setting only monitors the + // error events and data events. An application may choose to + // monitor CTS. DSR, RLSD, etc as well. + virtual LONG SetMask (DWORD dwMask = EEventBreak|EEventError|EEventRecv); + + // The WaitEvent method waits for one of the events that are + // enabled (see SetMask). + virtual LONG WaitEvent (LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); + + // Setup the handshaking protocol. There are three forms of + // handshaking: + // + // 1) No handshaking, so data is always send even if the receiver + // cannot handle the data anymore. This can lead to data loss, + // when the sender is able to transmit data faster then the + // receiver can handle. + // 2) Hardware handshaking, where the RTS/CTS lines are used to + // indicate if data can be sent. This mode requires that both + // ports and the cable support hardware handshaking. Hardware + // handshaking is the most reliable and efficient form of + // handshaking available, but is hardware dependant. + // 3) Software handshaking, where the XON/XOFF characters are used + // to throttle the data. A major drawback of this method is that + // these characters cannot be used for data anymore. + virtual LONG SetupHandshaking (EHandshake eHandshake); + + // Read operations can be blocking or non-blocking. You can use + // this method to setup wether to use blocking or non-blocking + // reads. Non-blocking reads is the default, which is required + // for most applications. + // + // 1) Blocking reads, which will cause the 'Read' method to block + // until the requested number of bytes have been read. This is + // useful if you know how many data you will receive. + // 2) Non-blocking reads, which will read as many bytes into your + // buffer and returns almost immediately. This is often the + // preferred setting. + virtual LONG SetupReadTimeouts (EReadTimeout eReadTimeout); + + // Obtain communication settings + virtual EBaudrate GetBaudrate (void); + virtual EDataBits GetDataBits (void); + virtual EParity GetParity (void); + virtual EStopBits GetStopBits (void); + virtual EHandshake GetHandshaking (void); + virtual DWORD GetEventMask (void); + virtual BYTE GetEventChar (void); + + // Write data to the serial port. Note that we are only able to + // send ANSI strings, because it probably doesn't make sense to + // transmit Unicode strings to an application. + virtual LONG Write (const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); + virtual LONG Write (LPCSTR pString, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); + + // Read data from the serial port. Refer to the description of + // the 'SetupReadTimeouts' for an explanation about (non) blocking + // reads and how to use this. + virtual LONG Read (void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); + + // Send a break + LONG Break (void); + + // Determine what caused the event to trigger + EEvent GetEventType (void); + + // Obtain the error + EError GetError (void); + + // Obtain the COMM and event handle + HANDLE GetCommHandle (void) { return m_hFile; } + + // Check if com-port is opened + bool IsOpen (void) const { return (m_hFile != 0); } + + // Obtain last error status + LONG GetLastError (void) const { return m_lLastError; } + + // Obtain CTS/DSR/RING/RLSD settings + bool GetCTS (void); + bool GetDSR (void); + bool GetRing (void); + bool GetRLSD (void); + + // Purge all buffers + LONG Purge (void); + +protected: + // Internal helper class which wraps DCB structure + class CDCB : public DCB + { + public: + CDCB() { DCBlength = sizeof(DCB); } + }; + +// Attributes +protected: + LONG m_lLastError; // Last serial error + HANDLE m_hFile; // File handle + EEvent m_eEvent; // Event type + DWORD m_dwEventMask; // Event mask + +#ifndef SERIAL_NO_OVERLAPPED + HANDLE m_hevtOverlapped; // Event handle for internal overlapped operations +#endif + +protected: + // Check the requirements + void CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const; + + // CancelIo wrapper (for Win95 compatibility) + BOOL CancelCommIo (void); +}; + +#endif // __SERIAL_H diff --git a/Window Tool/TimeSet/TimeSet/SerialEx.cpp b/Window Tool/TimeSet/TimeSet/SerialEx.cpp new file mode 100644 index 0000000..213f195 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/SerialEx.cpp @@ -0,0 +1,277 @@ +// SerialEx.cpp - Implementation of the CSerialEx class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +////////////////////////////////////////////////////////////////////// +// Include the standard header files + + +#include +#include +#include + + +////////////////////////////////////////////////////////////////////// +// Include module headerfile +#include "pch.h" +#include "SerialEx.h" + + +////////////////////////////////////////////////////////////////////// +// Disable warning C4127: conditional expression is constant, which +// is generated when using the _RPTF and _ASSERTE macros. + +#pragma warning(disable: 4127) + + +////////////////////////////////////////////////////////////////////// +// Enable debug memory manager + +#ifdef _DEBUG + +#ifdef THIS_FILE +#undef THIS_FILE +#endif + +static const char THIS_FILE[] = __FILE__; +#define new DEBUG_NEW + +#endif + + +////////////////////////////////////////////////////////////////////// +// Code + +CSerialEx::CSerialEx() + : m_fStopping(false) + , m_hThread(0) +#ifndef SERIAL_NO_OVERLAPPED + , m_hevtOverlappedWorkerThread(0) +#endif +{ +} + +CSerialEx::~CSerialEx() +{ + // Check if the thread handle is still there. If so, then we + // didn't close the serial port. We cannot depend on the + // CSerial destructor, because if it calls Close then it + // won't call our overridden Close. + if (m_hThread) + { + // Display a warning + _RPTF0(_CRT_WARN, "CSerialEx::~CSerialEx - Serial port not closed\n"); + + // Close implicitly + Close(); + } +} + +LONG CSerialEx::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fStartListener) +{ + // Call the base class first + long lLastError = CSerial::Open(lpszDevice,dwInQueue,dwOutQueue,SERIAL_DEFAULT_OVERLAPPED); + if (lLastError != ERROR_SUCCESS) + return lLastError; + +#ifndef SERIAL_NO_OVERLAPPED + // Create an event that is used for the workerthread. The globally + // used event is used by the main-thread and cannot be reused + // for this thread. + m_hevtOverlappedWorkerThread = ::CreateEvent(0,true,false,0); + if (m_hevtOverlappedWorkerThread == 0) + { + // Obtain the error information + m_lLastError = ::GetLastError(); + _RPTF0(_CRT_WARN,"CSerialEx::Open - Unable to create event\n"); + + // Close the serial port again + CSerial::Close(); + + // Return the error + return m_lLastError; + } +#endif + + + // Start the listener thread (only on request) + if (fStartListener) + { + lLastError = StartListener(); + if (lLastError != ERROR_SUCCESS) + return lLastError; + } + + // Return the error + return m_lLastError; +} + +LONG CSerialEx::Close (void) +{ + // Stop listener thread (wait until it ends) + //StopListener(INFINITE); + StopListener(100); + +#ifndef SERIAL_NO_OVERLAPPED + // Free event handle + if (m_hevtOverlappedWorkerThread) + { + ::CloseHandle(m_hevtOverlappedWorkerThread); + m_hevtOverlappedWorkerThread = 0; + + } +#endif + + // Call the base class + return CSerial::Close(); +} + +LONG CSerialEx::StartListener (void) +{ + // Check if the watcher thread was already running + if (m_hThread == 0) + { + // Make sure the thread has stopped + _ASSERTE(!m_fStopping); + + // Start the watcher thread + DWORD dwThreadId = 0; + m_hThread = ::CreateThread(0,0,ThreadProc,LPVOID(this),0,&dwThreadId); + if (m_hThread == 0) + { + // Display a warning + _RPTF0(_CRT_WARN, "CSerialEx::StartListener - Unable to start COMM watcher thread\n"); + + // Set the error code and exit + m_lLastError = ::GetLastError(); + return m_lLastError; + } + } + + // Return the error + m_lLastError = ERROR_SUCCESS; + return m_lLastError; +} + +LONG CSerialEx::StopListener (DWORD dwTimeout) +{ + // Check if the thread is running + if (m_hThread) + { + // Set the flag that the thread must be stopped + m_fStopping = true; + + // Cancel the pending WaitEvent, but we won't do this using + // CancelIo. This would break Win95 compatibility and some + // USB serial dongles cannot handle CancelIo correctly. By + // setting the event mask again, the call will also be + // completed before the thread exits. + SetMask(GetEventMask()); + + // Wait until the watcher thread has stopped + ::WaitForSingleObject(m_hThread,dwTimeout); + + // The thread has stopped + m_fStopping = false; + + // Close handle to the thread + ::CloseHandle(m_hThread); + m_hThread = 0; + } + + // Return the error + m_lLastError = ERROR_SUCCESS; + return m_lLastError; +} + +DWORD WINAPI CSerialEx::ThreadProc (LPVOID lpArg) +{ + // Route the method to the actual object + CSerialEx* pThis = reinterpret_cast(lpArg); + return pThis->ThreadProc(); +} + +DWORD CSerialEx::ThreadProc (void) +{ + // Use overlapped structure + LPOVERLAPPED lpOverlapped = 0; + + // Keep looping + do + { +#ifndef SERIAL_NO_OVERLAPPED + // Reset the event handle + ::ResetEvent(m_hevtOverlappedWorkerThread); + + // Initialize the overlapped structure + OVERLAPPED ovInternal = {0}; + ovInternal.hEvent = m_hevtOverlappedWorkerThread; + + // Start the WaitEvent (use our own overlapped structure) + if (WaitEvent(&ovInternal) != ERROR_SUCCESS) + return m_lLastError; + + // Wait for the overlapped operation to complete + if (::WaitForSingleObject(m_hevtOverlappedWorkerThread,INFINITE) != WAIT_OBJECT_0) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN,"CSerialEx::ThreadProc - Unable to wait until COM event has arrived\n"); + return m_lLastError; + } +#else + // Start the WaitEvent (don't need to specify an overlapped structure) + if (WaitEvent() != ERROR_SUCCESS) + return m_lLastError; +#endif + + // Wait until one of the events happens + if (!m_fStopping) + { + // Determine the event + EEvent eEvent = GetEventType(); + + // Obtain the error status during this event + DWORD dwErrors = 0; + if (!::ClearCommError(m_hFile,&dwErrors,0)) + { + // Set the internal error code + m_lLastError = ::GetLastError(); + + // Issue an error and quit + _RPTF0(_CRT_WARN, "CSerialEx::ThreadProc - Unable to obtain COM status\n"); + } + + // Convert the error + EError eError = EError(dwErrors); + + // There was a COMM event, which needs handling. We'll call the + // event handler. We can receive a "zero" event, when the + // mask or event character has been set. We won't pass this + // down to the window. + if (eEvent) + OnEvent(eEvent,eError); + } + } + while (!m_fStopping); + + // Bye bye + return 0; +} \ No newline at end of file diff --git a/Window Tool/TimeSet/TimeSet/SerialEx.h b/Window Tool/TimeSet/TimeSet/SerialEx.h new file mode 100644 index 0000000..001ae44 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/SerialEx.h @@ -0,0 +1,118 @@ +// SerialEx.h - Definition of the CSerialEx class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#ifndef __SERIAL_EX_H +#define __SERIAL_EX_H + + +////////////////////////////////////////////////////////////////////// +// Include CSerial base class + +#include "Serial.h" + + +////////////////////////////////////////////////////////////////////// +// +// CSerialEx - Win32 message-based wrapper for serial communications +// +// A lot of MS-Windows GUI based programs use a central message +// loop, so the application cannot block to wait for objects. This +// make serial communication difficult, because it isn't event +// driven using a message queue. This class makes the CSerial based +// classes suitable for use with such a messagequeue. Whenever +// an event occurs on the serial port, a user-defined message will +// be sent to a user-defined window. It can then use the standard +// message dispatching to handle the event. +// +// Pros: +// ----- +// - Easy to use +// - Fully ANSI and Unicode aware +// - Integrates easily in GUI applications and is intuitive to +// use for GUI application programmers +// +// Cons: +// ----- +// - Uses a thread for each COM-port, which has been opened. +// - More overhead, due to thread switching and message queues. +// - Requires a window, but that's probably why you're using +// this class. +// +// Copyright (C) 1999-2003 Ramon de Klein +// (Ramon.de.Klein@ict.nl) + +class CSerialEx : public CSerial +{ +// Construction +public: + CSerialEx(); + virtual ~CSerialEx(); + +// Operations +public: + // Open the serial communications for a particular COM port. You + // need to use the full devicename (i.e. "COM1") to open the port. + virtual LONG Open (LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0, bool fStartListener = false); + + // Close the serial port. + virtual LONG Close (void); + + // Start the listener thread + virtual LONG StartListener (void); + + // Stop the listener thread. Because the other thread might be + // busy processing data it might take a while, so you can specify + // a time-out. + virtual LONG StopListener (DWORD dwTimeout = INFINITE); + +protected: + // Each opened COM-port uses its own specific thread, which will + // wait for one of the events to happen. When an event happens, + // then the client window is send a message informing about the + // event. + static DWORD WINAPI ThreadProc (LPVOID lpArg); + DWORD ThreadProc (void); + + // Event handler + virtual void OnEvent (EEvent eEvent, EError eError) = 0; + +protected: + // The WaitEvent method is being used by this class internally + // and shouldn't be used by client applications. Client + // application should monior the messages. + using CSerial::WaitEvent; + + // The event-type is send in the WPARAM of the message and + // the GetEventType method returns the wrong data, so we'll + // hide this method for client applications to avoid problems. + using CSerial::GetEventType; + using CSerial::GetError; + +protected: + // Internal attributes + bool m_fStopping; + HANDLE m_hThread; + +#ifndef SERIAL_NO_OVERLAPPED + // Handle for overlapped operations in worker-thread + HANDLE m_hevtOverlappedWorkerThread; +#endif +}; + +#endif // __SERIAL_EX_H diff --git a/Window Tool/TimeSet/TimeSet/SerialMFC.h b/Window Tool/TimeSet/TimeSet/SerialMFC.h new file mode 100644 index 0000000..93df430 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/SerialMFC.h @@ -0,0 +1,135 @@ +// SerialMFC.h - Definition of the CSerialMFC class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#ifndef __SERIAL_MFC_H +#define __SERIAL_MFC_H + + +////////////////////////////////////////////////////////////////////// +// Include CSerialWnd base class + +#include "SerialWnd.h" + + +////////////////////////////////////////////////////////////////////// +// Make sure that MFC is already loaded +// +// We don't include it here, because MFC based applications typically +// use a precompiled header file. + +#ifndef __AFXWIN_H__ +#error "CWnd class isn't included (include AFXWIN.H)" +#endif + + +////////////////////////////////////////////////////////////////////// +// +// CSerialMFC - MFC wrapper for serial communication handling +// +// CSerialMFC is a very thing wrapper around the CSerialWnd class, +// which makes it more suitable for use in MFC-based applications. +// Unfortenately, the MFC framework isn't very flexible when it comes +// to adding custom message handlers. We cannot add our own types to +// the message handlers, but we're stuck to use 32-bit integers. +// +// Add the following entry to the window's message map to make sure +// that MFC calls your handler, when a serial message comes in. +// +// DECLARE_MESSAGE_MAP(CMyClass,CWnd) +// ... +// ON_WM_SERIAL(OnSerialMsg) +// ... +// END_MESSAGE_MAP() +// +// A typical handler could look like this: +// +// afx_msg LRESULT CMyClass::OnSerialMsg (WPARAM wParam, LPARAM lParam) +// { +// CSerial::EEvent eEvent = CSerial::EEvent(LOWORD(wParam)); +// CSerial::EError eError = CSerial::EError(HIWORD(wParam)); +// +// // lParam: User-defined 32-bit integer (type LPARAM) +// switch (eEvent) +// { +// case CSerialMFC::EEventRecv: +// // TODO: Read data from the port +// break; +// ... +// } +// +// // Return successful +// return 0; +// } +// +// +// Pros: +// ----- +// - Easy to use +// - Fully ANSI and Unicode aware +// - Integrates seamless in MFC applications +// +// Cons: +// ----- +// - No more then CSerialWnd, except that you need MFC +// +// Copyright (C) 1999-2003 Ramon de Klein +// (Ramon.de.Klein@ict.nl) + +class CSerialMFC : public CSerialWnd +{ +// Operations +public: + // Open the serial communications for a particular COM port. You + // need to use the full devicename (i.e. "COM1") to open the port. + virtual LONG Open (LPCTSTR lpszDevice, CWnd* pwndDest, UINT nComMsg = WM_NULL, LPARAM lParam = 0, DWORD dwInQueue = 0, DWORD dwOutQueue = 0) + { + + CString strTemp = _T("\\\\.\\"); + strTemp += lpszDevice; + return CSerialWnd::Open(strTemp.GetBuffer(0), pwndDest->GetSafeHwnd(), nComMsg, lParam, dwInQueue, dwOutQueue); + + + + + + + //return CSerialWnd::Open(lpszDevice, pwndDest->GetSafeHwnd(), nComMsg, lParam, dwInQueue, dwOutQueue); + } +}; + + +////////////////////////////////////////////////////////////////////// +// Message map macro for the default COM message + +#define ON_WM_SERIAL(memberFxn) \ + ON_REGISTERED_MESSAGE(CSerialMFC::mg_nDefaultComMsg,memberFxn) + + +////////////////////////////////////////////////////////////////////// +// Don't link to the default runtime libraries, because this will +// give a warning during link-time. + +#ifdef _DEBUG +#pragma comment(linker,"/nodefaultlib:LIBCD") +#else +#pragma comment(linker,"/nodefaultlib:LIBC") +#endif + + +#endif // __SERIAL_MFC_H diff --git a/Window Tool/TimeSet/TimeSet/SerialWnd.cpp b/Window Tool/TimeSet/TimeSet/SerialWnd.cpp new file mode 100644 index 0000000..bd54730 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/SerialWnd.cpp @@ -0,0 +1,131 @@ +// SerialWnd.cpp - Implementation of the CSerialWnd class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +////////////////////////////////////////////////////////////////////// +// Include the standard header files + + +#include "pch.h" +#include +#include +#include + + +////////////////////////////////////////////////////////////////////// +// Include module headerfile + +#include "SerialWnd.h" + + +////////////////////////////////////////////////////////////////////// +// Disable warning C4127: conditional expression is constant, which +// is generated when using the _RPTF and _ASSERTE macros. + +#pragma warning(disable: 4127) + + +////////////////////////////////////////////////////////////////////// +// Enable debug memory manager + +#ifdef _DEBUG + +#ifdef THIS_FILE +#undef THIS_FILE +#endif + +static const char THIS_FILE[] = __FILE__; +#define new DEBUG_NEW + +#endif + + +////////////////////////////////////////////////////////////////////// +// Code + +// Register the standard CSerialWnd COM message +const UINT CSerialWnd::mg_nDefaultComMsg = ::RegisterWindowMessage(_T("CSerialWnd_DefaultComMsg")); + + +CSerialWnd::CSerialWnd() + : m_hwndDest(0) + , m_nComMsg(WM_NULL) + , m_lParam(0) +{ +} + +CSerialWnd::~CSerialWnd() +{ + // Check if the thread handle is still there. If so, then we + // didn't close the serial port. We cannot depend on the + // CSerial destructor, because if it calls Close then it + // won't call our overridden Close. + if (m_hThread) + { + // Display a warning + _RPTF0(_CRT_WARN, "CSerialWnd::~CSerialWnd - Serial port not closed\n"); + + // Close implicitly + Close(); + } +} + +LONG CSerialWnd::Open (LPCTSTR lpszDevice, HWND hwndDest, UINT nComMsg, LPARAM lParam, DWORD dwInQueue, DWORD dwOutQueue) +{ + // Call the base class first + long lLastError = CSerialEx::Open(lpszDevice,dwInQueue,dwOutQueue); + if (lLastError != ERROR_SUCCESS) + return lLastError; + + // Save the window handle, notification message and user message + m_hwndDest = hwndDest; + m_nComMsg = nComMsg?nComMsg:mg_nDefaultComMsg; + m_lParam = lParam; + + // Start the listener thread + lLastError = StartListener(); + if (lLastError != ERROR_SUCCESS) + { + // Close the serial port + Close(); + + // Return the error-code + m_lLastError = lLastError; + return m_lLastError; + } + + // Return the error + m_lLastError = ERROR_SUCCESS; + return m_lLastError; +} + +LONG CSerialWnd::Close (void) +{ + // Reset all members + m_hwndDest = 0; + m_nComMsg = WM_NULL; + + // Call the base class + return CSerialEx::Close(); +} + +void CSerialWnd::OnEvent (EEvent eEvent, EError eError) +{ + // Post message to the client window + ::PostMessage(m_hwndDest,m_nComMsg,MAKEWPARAM(eEvent,eError),LPARAM(m_lParam)); +} diff --git a/Window Tool/TimeSet/TimeSet/SerialWnd.h b/Window Tool/TimeSet/TimeSet/SerialWnd.h new file mode 100644 index 0000000..655b88c --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/SerialWnd.h @@ -0,0 +1,91 @@ +// SerialWnd.h - Definition of the CSerialWnd class +// +// Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#ifndef __SERIAL_WND_H +#define __SERIAL_WND_H + + +////////////////////////////////////////////////////////////////////// +// Include CSerialEx base class + +#include "SerialEx.h" + + +////////////////////////////////////////////////////////////////////// +// +// CSerialWnd - Win32 message-based wrapper for serial communications +// +// A lot of MS-Windows GUI based programs use a central message +// loop, so the application cannot block to wait for objects. This +// make serial communication difficult, because it isn't event +// driven using a message queue. This class makes the CSerial based +// classes suitable for use with such a messagequeue. Whenever +// an event occurs on the serial port, a user-defined message will +// be sent to a user-defined window. It can then use the standard +// message dispatching to handle the event. +// +// Pros: +// ----- +// - Easy to use +// - Fully ANSI and Unicode aware +// - Integrates easily in GUI applications and is intuitive to +// use for GUI application programmers +// +// Cons: +// ----- +// - Uses a thread for each COM-port, which has been opened. +// - More overhead, due to thread switching and message queues. +// - Requires a window, but that's probably why you're using +// this class. +// +// Copyright (C) 1999-2003 Ramon de Klein +// (Ramon.de.Klein@ict.nl) + +class CSerialWnd : public CSerialEx +{ +// Construction +public: + CSerialWnd(); + virtual ~CSerialWnd(); + +// Operations +public: + // Open the serial communications for a particular COM port. You + // need to use the full devicename (i.e. "COM1") to open the port. + virtual LONG Open (LPCTSTR lpszDevice, HWND hwndDest, UINT nComMsg=WM_NULL, LPARAM lParam=0, DWORD dwInQueue = 0, DWORD dwOutQueue = 0); + + // Close the serial port. + virtual LONG Close (void); + +protected: + // Event handler that is called when + virtual void OnEvent (EEvent eEvent, EError eError); + +public: + // Default Serial notification message + static const UINT mg_nDefaultComMsg; + +protected: + // Internal attributes + HWND m_hwndDest; + UINT m_nComMsg; + LONG m_lParam; +}; + +#endif // __SERIAL_WND_H diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.aps b/Window Tool/TimeSet/TimeSet/TimeSet.aps new file mode 100644 index 0000000..9fb6560 Binary files /dev/null and b/Window Tool/TimeSet/TimeSet/TimeSet.aps differ diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.cpp b/Window Tool/TimeSet/TimeSet/TimeSet.cpp new file mode 100644 index 0000000..d8d99ae --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSet.cpp @@ -0,0 +1,107 @@ + +// TimeSet.cpp: 응용 프로그램에 대한 클래스 동작을 정의합니다. +// + +#include "pch.h" +#include "framework.h" +#include "TimeSet.h" +#include "TimeSetDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CTimeSetApp + +BEGIN_MESSAGE_MAP(CTimeSetApp, CWinApp) + ON_COMMAND(ID_HELP, &CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CTimeSetApp 생성 + +CTimeSetApp::CTimeSetApp() +{ + // 다시 시작 관리자 지원 + m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; + + // TODO: 여기에 생성 코드를 추가합니다. + // InitInstance에 모든 중요한 초기화 작업을 배치합니다. +} + + +// 유일한 CTimeSetApp 개체입니다. + +CTimeSetApp theApp; + + +// CTimeSetApp 초기화 + +BOOL CTimeSetApp::InitInstance() +{ + // 응용 프로그램 매니페스트가 ComCtl32.dll 버전 6 이상을 사용하여 비주얼 스타일을 + // 사용하도록 지정하는 경우, Windows XP 상에서 반드시 InitCommonControlsEx()가 필요합니다. + // InitCommonControlsEx()를 사용하지 않으면 창을 만들 수 없습니다. + INITCOMMONCONTROLSEX InitCtrls; + InitCtrls.dwSize = sizeof(InitCtrls); + // 응용 프로그램에서 사용할 모든 공용 컨트롤 클래스를 포함하도록 + // 이 항목을 설정하십시오. + InitCtrls.dwICC = ICC_WIN95_CLASSES; + InitCommonControlsEx(&InitCtrls); + + CWinApp::InitInstance(); + + + AfxEnableControlContainer(); + + // 대화 상자에 셸 트리 뷰 또는 + // 셸 목록 뷰 컨트롤이 포함되어 있는 경우 셸 관리자를 만듭니다. + CShellManager *pShellManager = new CShellManager; + + // MFC 컨트롤의 테마를 사용하기 위해 "Windows 원형" 비주얼 관리자 활성화 + CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); + + // 표준 초기화 + // 이들 기능을 사용하지 않고 최종 실행 파일의 크기를 줄이려면 + // 아래에서 필요 없는 특정 초기화 + // 루틴을 제거해야 합니다. + // 해당 설정이 저장된 레지스트리 키를 변경하십시오. + // TODO: 이 문자열을 회사 또는 조직의 이름과 같은 + // 적절한 내용으로 수정해야 합니다. + SetRegistryKey(_T("로컬 응용 프로그램 마법사에서 생성된 응용 프로그램")); + + CTimeSetDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 여기에 [확인]을 클릭하여 대화 상자가 없어질 때 처리할 + // 코드를 배치합니다. + } + else if (nResponse == IDCANCEL) + { + // TODO: 여기에 [취소]를 클릭하여 대화 상자가 없어질 때 처리할 + // 코드를 배치합니다. + } + else if (nResponse == -1) + { + TRACE(traceAppMsg, 0, "경고: 대화 상자를 만들지 못했으므로 응용 프로그램이 예기치 않게 종료됩니다.\n"); + TRACE(traceAppMsg, 0, "경고: 대화 상자에서 MFC 컨트롤을 사용하는 경우 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS를 수행할 수 없습니다.\n"); + } + + // 위에서 만든 셸 관리자를 삭제합니다. + if (pShellManager != nullptr) + { + delete pShellManager; + } + +#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS) + ControlBarCleanUp(); +#endif + + // 대화 상자가 닫혔으므로 응용 프로그램의 메시지 펌프를 시작하지 않고 응용 프로그램을 끝낼 수 있도록 FALSE를 + // 반환합니다. + return FALSE; +} + diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.h b/Window Tool/TimeSet/TimeSet/TimeSet.h new file mode 100644 index 0000000..35033fc --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSet.h @@ -0,0 +1,32 @@ + +// TimeSet.h: PROJECT_NAME 응용 프로그램에 대한 주 헤더 파일입니다. +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error "include 'pch.h' before including this file for PCH" +#endif + +#include "resource.h" // 주 기호입니다. + + +// CTimeSetApp: +// 이 클래스의 구현에 대해서는 TimeSet.cpp을(를) 참조하세요. +// + +class CTimeSetApp : public CWinApp +{ +public: + CTimeSetApp(); + +// 재정의입니다. +public: + virtual BOOL InitInstance(); + +// 구현입니다. + + DECLARE_MESSAGE_MAP() +}; + +extern CTimeSetApp theApp; diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.rc b/Window Tool/TimeSet/TimeSet/TimeSet.rc new file mode 100644 index 0000000..328b096 Binary files /dev/null and b/Window Tool/TimeSet/TimeSet/TimeSet.rc differ diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj b/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj new file mode 100644 index 0000000..23f1209 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj @@ -0,0 +1,226 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {12662F45-5722-45B9-8C02-2863C436C1F6} + MFCProj + TimeSet + 10.0.17763.0 + + + + Application + true + v141 + MultiByte + Static + + + Application + false + v141 + true + MultiByte + Static + + + Application + true + v141 + Unicode + Static + + + Application + false + v141 + true + Unicode + Static + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + true + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + pch.h + + + Windows + + + false + true + _DEBUG;%(PreprocessorDefinitions) + + + 0x0412 + _DEBUG;%(PreprocessorDefinitions) + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Use + Level3 + Disabled + true + _WINDOWS;_DEBUG;%(PreprocessorDefinitions) + pch.h + + + Windows + + + false + true + _DEBUG;%(PreprocessorDefinitions) + + + 0x0412 + _DEBUG;%(PreprocessorDefinitions) + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + pch.h + + + Windows + true + true + + + false + true + NDEBUG;%(PreprocessorDefinitions) + + + 0x0412 + NDEBUG;%(PreprocessorDefinitions) + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Use + Level3 + MaxSpeed + true + true + true + _WINDOWS;NDEBUG;%(PreprocessorDefinitions) + pch.h + + + Windows + true + true + + + false + true + NDEBUG;%(PreprocessorDefinitions) + + + 0x0412 + NDEBUG;%(PreprocessorDefinitions) + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj.filters b/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj.filters new file mode 100644 index 0000000..ff6d1ab --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj.filters @@ -0,0 +1,84 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + + + 리소스 파일 + + + + + 리소스 파일 + + + + + 리소스 파일 + + + \ No newline at end of file diff --git a/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj.user b/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj.user new file mode 100644 index 0000000..72b91ea --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSet.vcxproj.user @@ -0,0 +1,6 @@ + + + + TimeSet.rc + + \ No newline at end of file diff --git a/Window Tool/TimeSet/TimeSet/TimeSetDlg.cpp b/Window Tool/TimeSet/TimeSet/TimeSetDlg.cpp new file mode 100644 index 0000000..ff28b86 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSetDlg.cpp @@ -0,0 +1,625 @@ + +// TimeSetDlg.cpp: 구현 파일 +// + +#include "pch.h" +#include "framework.h" +#include "TimeSet.h" +#include "TimeSetDlg.h" +#include "afxdialogex.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +#include +#pragma comment(lib, "setupapi.lib") + +// CTimeSetDlg 대화 상자 + + + +void GetDeviceInstanceID(HDEVINFO hDevInfo, SP_DEVINFO_DATA* pspDevInfoData, TCHAR *szInstanceID) +{ + if (!SetupDiGetDeviceInstanceId(hDevInfo, + pspDevInfoData, + szInstanceID, + LINE_LEN, + 0)) + { + ; + } + +}; + +void GetDeviceInterfaceInfo(HDEVINFO hDevInfo, SP_DEVINFO_DATA spDevInfoData, TCHAR *szPath) +{ + SP_DEVICE_INTERFACE_DATA spDevInterfaceData = { 0 }; + // + spDevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + if (!SetupDiCreateDeviceInterface(hDevInfo, + &spDevInfoData, + &spDevInfoData.ClassGuid, + 0L, + 0L, + &spDevInterfaceData)) + ; + else + { + SP_DEVICE_INTERFACE_DETAIL_DATA *pspDevInterfaceDetail = 0L; + DWORD dwRequire = 0L; + // + if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, + &spDevInterfaceData, + 0L, + 0, + &dwRequire, + 0L)) + { + DWORD dwError = GetLastError(); + // + if (dwError != ERROR_INSUFFICIENT_BUFFER) + { + + return; + }; + }; + // + pspDevInterfaceDetail = (SP_DEVICE_INTERFACE_DETAIL_DATA*)LocalAlloc(LPTR, + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)*dwRequire); + pspDevInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, + &spDevInterfaceData, + pspDevInterfaceDetail, + dwRequire, + &dwRequire, + 0L)) + { + DWORD dwError = GetLastError(); + // + if (dwError != ERROR_INSUFFICIENT_BUFFER) + { + int a = 3; + } + } + else + { + memcpy(szPath, pspDevInterfaceDetail->DevicePath, strlen(pspDevInterfaceDetail->DevicePath)); + }; + if (pspDevInterfaceDetail) + LocalFree(pspDevInterfaceDetail); + }; +}; +void PrintError(CString strErrorName, DWORD dwErrorNo) +{ + LPVOID lpMsgBuf; + CString strMessage; + + if (!FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwErrorNo, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),// Default language + (LPTSTR)&lpMsgBuf, + 0, + NULL)) + { + // Handle the error. + return; + } + //_cprintf("WIN_ERR(%d): %s\n", dwErrorNo, (LPCTSTR)lpMsgBuf); + strMessage.Format(_T("%s\nWIN_ERR(%d): %s\n"), strErrorName, dwErrorNo, (LPCTSTR)lpMsgBuf); + ::AfxMessageBox(strMessage, MB_OK | MB_ICONERROR); + + + + + LocalFree(lpMsgBuf); +} + + + + +CTimeSetDlg::CTimeSetDlg(CWnd* pParent /*=nullptr*/) + : CDialogEx(IDD_TIMESET_DIALOG, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CTimeSetDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogEx::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CTimeSetDlg, CDialogEx) + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CTimeSetDlg::OnBnClickedButtonConnect) + ON_BN_CLICKED(IDC_BUTTON_SET_LOCAL_TIME, &CTimeSetDlg::OnBnClickedButtonSetLocalTime) + ON_BN_CLICKED(IDC_BUTTON_SET_USER_TIME, &CTimeSetDlg::OnBnClickedButtonSetUserTime) +END_MESSAGE_MAP() + + +// CTimeSetDlg 메시지 처리기 + +BOOL CTimeSetDlg::OnInitDialog() +{ + CDialogEx::OnInitDialog(); + + // 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는 + // 프레임워크가 이 작업을 자동으로 수행합니다. + SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다. + SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다. + + //ShowWindow(SW_MINIMIZE); + + // TODO: 여기에 추가 초기화 작업을 추가합니다. + + PortSearch(); + + return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다. +} + +// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면 +// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는 +// 프레임워크에서 이 작업을 자동으로 수행합니다. + +void CTimeSetDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다. + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다. + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 아이콘을 그립니다. + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialogEx::OnPaint(); + } +} + +// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서 +// 이 함수를 호출합니다. +HCURSOR CTimeSetDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + + + + +void CTimeSetDlg::PortSearch() +{ + HDEVINFO hDevInfo = 0L; + SP_DEVINFO_DATA spDevInfoData = { 0 }; + short wIndex = 0; + CString strPortName = _T(""); + SERIAL_PORT stPortInfo; + DWORD dwRequireSize; + deque deqPort; + deque deqDeviceName; + TCHAR szName[64] = { 0 }; + HKEY hKey; + DWORD dwResult; + CString strTemp; + CString strTemp1; + deque::iterator itrPortName; + deque::iterator itrDeviceName; + + int nComboIndex = 0; + int i; + + CComboBox* pCombo = (CComboBox *)GetDlgItem(IDC_COMBO_SERIAL_LIST); + pCombo->LockWindowUpdate(); + + nComboIndex = pCombo->GetCount(); + m_mapPortSearch.clear(); + + for (i = 0; i < nComboIndex; i++) + { + pCombo->DeleteString(0); + } + + hDevInfo = SetupDiGetClassDevs(0L, 0L, this->GetParent()->GetSafeHwnd(), DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_PROFILE); + if (hDevInfo != (void*)-1) + { + wIndex = 0; + spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + while (1) + { + if (SetupDiEnumDeviceInfo(hDevInfo, wIndex, &spDevInfoData)) + { + TCHAR szBuf[MAX_PATH] = { 0 }; + short wImageIdx = 0; + short wItem = 0; + if (!SetupDiGetDeviceRegistryProperty(hDevInfo, + &spDevInfoData, + SPDRP_CLASS, //SPDRP_DEVICEDESC, + 0L, + (PBYTE)szBuf, + 2048, + 0)) + { + wIndex++; + continue; + }; + + strTemp.Format(_T("%s"), szBuf); + if (strTemp.Find(_T("Ports")) == -1) + { + wIndex++; + continue; + } + + if (!SetupDiGetClassDescription(&spDevInfoData.ClassGuid, + szBuf, + MAX_PATH, + &dwRequireSize)) + { + wIndex++; + continue; + }; + + TCHAR szID[LINE_LEN] = { 0 }; + TCHAR szPath[MAX_PATH] = { 0 }; + GetDeviceInstanceID(hDevInfo, &spDevInfoData, szID); + GetDeviceInterfaceInfo(hDevInfo, spDevInfoData, szPath); + + + if (SetupDiGetDeviceRegistryProperty(hDevInfo, + &spDevInfoData, + SPDRP_FRIENDLYNAME, + 0L, + (PBYTE)szName, + 63, + 0)) + { + + } + else if (SetupDiGetDeviceRegistryProperty(hDevInfo, + &spDevInfoData, + SPDRP_DEVICEDESC, + 0L, + (PBYTE)szName, + 63, + 0)) + { + + }; + strTemp.Format(_T("%s"), szName); + + if (strTemp.Find(_T("COM")) != -1) + { + TRACE("%s\n", strTemp); + deqDeviceName.push_back(strTemp); + } + + } + else + break; + wIndex++; + }; + SetupDiDestroyDeviceInfoList(hDevInfo); + }; + + + dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), &hKey); + + if (dwResult == ERROR_SUCCESS) + { + TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name + DWORD cchClassName = MAX_PATH; // size of class string + DWORD cSubKeys = 0; // number of subkeys + + DWORD cValues; // number of values for key + DWORD i, retCode; + + TCHAR achValue[MAX_VALUE_NAME]; + DWORD cchValue = MAX_VALUE_NAME; + + // Get the class name and the value count. + retCode = RegQueryInfoKey(hKey, // key handle + NULL, // buffer for class name + NULL, // size of class string + NULL, // reserved + NULL, // number of subkeys + NULL, // longest subkey size + NULL, // longest class string + &cValues, // number of values for this key + NULL, // longest value name + NULL, // longest value data + NULL, // security descriptor + NULL); // last write time + + // Enumerate the key values. + + + if (cValues) + { + for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) + { + cchValue = MAX_VALUE_NAME; + achValue[0] = '\0'; + retCode = RegEnumValue(hKey, i, + achValue, + &cchValue, + NULL, + NULL, + NULL, + NULL); + if (retCode == ERROR_SUCCESS) + { + + TCHAR chTemp[MAX_VALUE_NAME]; + DWORD dwBufSize; + + chTemp[0] = '\0'; + + retCode = RegQueryValueEx(hKey, achValue, NULL, NULL, (PBYTE)chTemp, &dwBufSize); + + if (retCode == ERROR_SUCCESS) + { + strTemp.Format(_T("COM%.3d"), _ttoi(chTemp + _tcslen(_T("COM")))); + deqPort.push_back(strTemp); + } + else + { + retCode = RegQueryValueEx(hKey, achValue, NULL, NULL, (PBYTE)chTemp, &dwBufSize); + + if (ERROR_SUCCESS == retCode) + { + strTemp.Format(_T("COM%.3d"), _ttoi(chTemp + _tcslen(_T("COM")))); + deqPort.push_back(strTemp); + } + } + } + } + } + RegCloseKey(hKey); + } + sort(deqPort.begin(), deqPort.end()); + + + itrPortName = deqPort.begin(); + nComboIndex = 0; + while (itrPortName != deqPort.end()) + { + TRACE("%s\n", (*itrPortName)); + int nPort = _ttoi((*itrPortName).Mid(3, 3)); + strTemp.Format(_T("COM%d"), nPort); + stPortInfo.nPort = nPort; + stPortInfo.strPortName = strTemp; + stPortInfo.strDeviceName = _T(""); + itrDeviceName = deqDeviceName.begin(); + + + while (itrDeviceName != deqDeviceName.end()) + { + if ((*itrDeviceName).Find(_T("(") + strTemp + _T(")")) != -1) + { + stPortInfo.strDeviceName = (*itrDeviceName); + } + itrDeviceName++; + } + + if (stPortInfo.strDeviceName.GetLength() == 0) + { + pCombo->InsertString(nComboIndex, stPortInfo.strPortName); + } + else + { + pCombo->InsertString(nComboIndex, stPortInfo.strDeviceName); + } + m_mapPortSearch[nComboIndex++] = stPortInfo; + + itrPortName++; + } + + pCombo->SetCurSel(0); + pCombo->UnlockWindowUpdate(); + +} + + + +void CTimeSetDlg::OnBnClickedButtonConnect() +{ + // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. + CComboBox* pCombo = (CComboBox *)GetDlgItem(IDC_COMBO_SERIAL_LIST); + + + if (m_Serial.IsOpen() == true) + { + m_Serial.Close(); + GetDlgItem(IDC_BUTTON_CONNECT)->SetWindowText(_T("Connect")); + GetDlgItem(IDC_COMBO_SERIAL_LIST)->EnableWindow(true); + GetDlgItem(IDC_BUTTON_SET_LOCAL_TIME)->EnableWindow(false); + GetDlgItem(IDC_BUTTON_SET_USER_TIME)->EnableWindow(false); + } + else + { + int nPortSelect = -1; + CString strPort; + DWORD dwResult; + + nPortSelect = pCombo->GetCurSel(); + + if (nPortSelect >= 0) + { + + strPort.Format(_T("COM%d"), m_mapPortSearch[nPortSelect].nPort); + dwResult = m_Serial.Open(strPort, this); + + if (dwResult != ERROR_SUCCESS) + { + CString strMessage = _T("Serial Port Open Failed\n"); + PrintError(strMessage, GetLastError()); + return; + } + + if (m_Serial.Setup(CSerial::EBaud115200, CSerial::EData8, CSerial::EParNone, CSerial::EStop1) != ERROR_SUCCESS) + { + CString strMessage = _T("Serial Setup Error\n"); + PrintError(strMessage, GetLastError()); + m_Serial.Close(); + return; + } + + if (m_Serial.SetupHandshaking(CSerial::EHandshakeOff)) + { + CString strMessage = _T("Serial SetupHandshaking Error\n"); + PrintError(strMessage, GetLastError()); + m_Serial.Close(); + return; + } + + CTime time = CTime::GetCurrentTime(); + CString strtemp; + strtemp.Format("%d", time.GetYear()); + GetDlgItem(IDC_EDIT_YEAR)->SetWindowText(strtemp); + strtemp.Format("%d", time.GetMonth()); + GetDlgItem(IDC_EDIT_MONTH)->SetWindowText(strtemp); + strtemp.Format("%d", time.GetDay()); + GetDlgItem(IDC_EDIT_DATE)->SetWindowText(strtemp); + strtemp.Format("%d", time.GetHour()); + GetDlgItem(IDC_EDIT_HOUR)->SetWindowText(strtemp); + strtemp.Format("%d", time.GetMinute()); + GetDlgItem(IDC_EDIT_MIN)->SetWindowText(strtemp); + strtemp.Format("%d", time.GetSecond()); + GetDlgItem(IDC_EDIT_SEC)->SetWindowText(strtemp); + + + GetDlgItem(IDC_BUTTON_CONNECT)->SetWindowText(_T("Disconnect")); + GetDlgItem(IDC_COMBO_SERIAL_LIST)->EnableWindow(false); + GetDlgItem(IDC_BUTTON_SET_LOCAL_TIME)->EnableWindow(true); + GetDlgItem(IDC_BUTTON_SET_USER_TIME)->EnableWindow(true); + } + + + + } +} + + +void CTimeSetDlg::OnBnClickedButtonSetLocalTime() +{ + // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. + uint8_t TxData[100]; + uint8_t TxIndex = 0; + CTime time = CTime::GetCurrentTime(); + uint16_t TimeData; + uint8_t i; + uint8_t checksum = 0; + + TxData[TxIndex++] = 0x02; + TxData[TxIndex++] = 0x00; + TxData[TxIndex++] = 0x07; + + TimeData = time.GetYear(); + TxData[TxIndex++] = (TimeData >> 8) & 0xFF; + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + TimeData = time.GetMonth(); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + TimeData = time.GetDay(); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + TimeData = time.GetHour(); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + TimeData = time.GetMinute(); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + TimeData = time.GetSecond(); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + checksum = 0; + + for (i = 0; i < TxIndex; i++) + { + checksum += TxData[i]; + } + + + TxData[TxIndex++] = checksum; + TxData[TxIndex++] = 0x03; + + if (m_Serial.IsOpen()) + { + m_Serial.Write(TxData, TxIndex); + } +} + + +void CTimeSetDlg::OnBnClickedButtonSetUserTime() +{ + // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. + // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. + uint8_t TxData[100]; + uint8_t TxIndex = 0; + uint16_t TimeData; + uint8_t i; + uint8_t checksum = 0; + + TxData[TxIndex++] = 0x02; + TxData[TxIndex++] = 0x00; + TxData[TxIndex++] = 0x07; + + CString strtemp; + + GetDlgItem(IDC_EDIT_YEAR)->GetWindowText(strtemp); + TimeData = atoi(strtemp); + TxData[TxIndex++] = (TimeData >> 8) & 0xFF; + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + GetDlgItem(IDC_EDIT_MONTH)->GetWindowText(strtemp); + TimeData = atoi(strtemp); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + GetDlgItem(IDC_EDIT_DATE)->GetWindowText(strtemp); + TimeData = atoi(strtemp); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + GetDlgItem(IDC_EDIT_HOUR)->GetWindowText(strtemp); + TimeData = atoi(strtemp); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + GetDlgItem(IDC_EDIT_MIN)->GetWindowText(strtemp); + TimeData = atoi(strtemp); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + GetDlgItem(IDC_EDIT_SEC)->GetWindowText(strtemp); + TimeData = atoi(strtemp); + TxData[TxIndex++] = (TimeData >> 0) & 0xFF; + + checksum = 0; + + for (i = 0; i < TxIndex; i++) + { + checksum += TxData[i]; + } + + + TxData[TxIndex++] = checksum; + TxData[TxIndex++] = 0x03; + + if (m_Serial.IsOpen()) + { + m_Serial.Write(TxData, TxIndex); + } + +} diff --git a/Window Tool/TimeSet/TimeSet/TimeSetDlg.h b/Window Tool/TimeSet/TimeSet/TimeSetDlg.h new file mode 100644 index 0000000..3c27728 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/TimeSetDlg.h @@ -0,0 +1,63 @@ + +// TimeSetDlg.h: 헤더 파일 +// + +#pragma once + +#include +#include +#include +#include + +#include "SerialMFC.h" + +using namespace std; + + + +#define MAX_KEY_LENGTH 255 +#define MAX_VALUE_NAME 16383 + + +typedef struct _Serial_Port +{ + int nPort; + CString strDeviceName; + CString strPortName; +}SERIAL_PORT; + +// CTimeSetDlg 대화 상자 +class CTimeSetDlg : public CDialogEx +{ +// 생성입니다. +public: + CTimeSetDlg(CWnd* pParent = nullptr); // 표준 생성자입니다. + +// 대화 상자 데이터입니다. +#ifdef AFX_DESIGN_TIME + enum { IDD = IDD_TIMESET_DIALOG }; +#endif + + + CSerialMFC m_Serial; + vector m_SerialPort; + map m_mapPortSearch; //포트 리스트 + protected: + + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다. + void PortSearch(); + +// 구현입니다. +protected: + HICON m_hIcon; + + // 생성된 메시지 맵 함수 + virtual BOOL OnInitDialog(); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedButtonConnect(); + afx_msg void OnBnClickedButtonSetLocalTime(); + afx_msg void OnBnClickedButtonSetUserTime(); +}; diff --git a/Window Tool/TimeSet/TimeSet/framework.h b/Window Tool/TimeSet/TimeSet/framework.h new file mode 100644 index 0000000..9fa85c6 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/framework.h @@ -0,0 +1,49 @@ +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 거의 사용되지 않는 내용은 Windows 헤더에서 제외합니다. +#endif + +#include "targetver.h" + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 일부 CString 생성자는 명시적으로 선언됩니다. + +// MFC의 공통 부분과 무시 가능한 경고 메시지에 대한 숨기기를 해제합니다. +#define _AFX_ALL_WARNINGS + +#include // MFC 핵심 및 표준 구성 요소입니다. +#include // MFC 확장입니다. + + +#include // MFC 자동화 클래스입니다. + + + +#ifndef _AFX_NO_OLE_SUPPORT +#include // Internet Explorer 4 공용 컨트롤에 대한 MFC 지원입니다. +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 공용 컨트롤에 대한 MFC 지원입니다. +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC의 리본 및 컨트롤 막대 지원 + + + + + + + + + +#ifdef _UNICODE +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif +#endif + + diff --git a/Window Tool/TimeSet/TimeSet/pch.cpp b/Window Tool/TimeSet/TimeSet/pch.cpp new file mode 100644 index 0000000..bd23a58 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: 미리 컴파일된 헤더에 해당하는 소스 파일 + +#include "pch.h" + +// 미리 컴파일된 헤더를 사용하는 경우 컴파일이 성공하려면 이 소스 파일이 필요합니다. diff --git a/Window Tool/TimeSet/TimeSet/pch.h b/Window Tool/TimeSet/TimeSet/pch.h new file mode 100644 index 0000000..d99e280 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/pch.h @@ -0,0 +1,13 @@ +// pch.h: 미리 컴파일된 헤더 파일입니다. +// 아래 나열된 파일은 한 번만 컴파일되었으며, 향후 빌드에 대한 빌드 성능을 향상합니다. +// 코드 컴파일 및 여러 코드 검색 기능을 포함하여 IntelliSense 성능에도 영향을 미칩니다. +// 그러나 여기에 나열된 파일은 빌드 간 업데이트되는 경우 모두 다시 컴파일됩니다. +// 여기에 자주 업데이트할 파일을 추가하지 마세요. 그러면 성능이 저하됩니다. + +#ifndef PCH_H +#define PCH_H + +// 여기에 미리 컴파일하려는 헤더 추가 +#include "framework.h" + +#endif //PCH_H diff --git a/Window Tool/TimeSet/TimeSet/res/TimeSet.ico b/Window Tool/TimeSet/TimeSet/res/TimeSet.ico new file mode 100644 index 0000000..d56fbcd Binary files /dev/null and b/Window Tool/TimeSet/TimeSet/res/TimeSet.ico differ diff --git a/Window Tool/TimeSet/TimeSet/res/TimeSet.rc2 b/Window Tool/TimeSet/TimeSet/res/TimeSet.rc2 new file mode 100644 index 0000000..4224a93 Binary files /dev/null and b/Window Tool/TimeSet/TimeSet/res/TimeSet.rc2 differ diff --git a/Window Tool/TimeSet/TimeSet/resource.h b/Window Tool/TimeSet/TimeSet/resource.h new file mode 100644 index 0000000..5601592 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++에서 생성한 포함 파일입니다. +// TimeSet.rc에서 사용되고 있습니다. +// +#define IDD_TIMESET_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON_CONNECT 1000 +#define IDC_COMBO_SERIAL_LIST 1001 +#define IDC_EDIT_YEAR 1003 +#define IDC_EDIT_MONTH 1004 +#define IDC_EDIT_DATE 1005 +#define IDC_EDIT_HOUR 1006 +#define IDC_EDIT_MIN 1007 +#define IDC_EDIT_SEC 1008 +#define IDC_BUTTON_SET_USER_TIME 1009 +#define IDC_BUTTON_SET_LOCAL_TIME 1010 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Window Tool/TimeSet/TimeSet/targetver.h b/Window Tool/TimeSet/TimeSet/targetver.h new file mode 100644 index 0000000..4464219 --- /dev/null +++ b/Window Tool/TimeSet/TimeSet/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// SDKDDKVer.h를 포함하면 최고 수준의 가용성을 가진 Windows 플랫폼이 정의됩니다. + +// 이전 Windows 플랫폼에 대해 응용 프로그램을 빌드하려는 경우에는 SDKDDKVer.h를 포함하기 전에 +// WinSDKVer.h를 포함하고 _WIN32_WINNT 매크로를 지원하려는 플랫폼으로 설정하십시오. + +#include