Serielle Kommunikation via USB (PC zu Arduino)
-
Hallo zusammen!
Für ein kleines Projekt möchte ich eine Serielle Kommunikation zwischen meinem Computer und einem Arduino aufbauen. Via USB sollen sie Strings austauschen. Ich hab mich hierzu schon etwas belesen (siehe unten).
Im ersten Schritt habe ich ein Programm geschrieben, mit dem ich eine Verbindung zum COM-Port, an dem der Arduino angeschlossen ist, herstellen und die DCB Konfiguration auslesen möchte.
Das Problem:
Alle Werte, bis auf „DCBlength = 28“, sind = 0. Mit einem Kontrollprogramm, dass ich aus Windwos Docs kopiert habe, bekomme ich allerdings „richtige Werte“ (Baudrate 9600 usw.).Frage:
Anscheinend habe ich also doch keine Verbindung zum COM-Port aufgebaut? Oder gibt es Probleme beim Speichern der Werte? Kurz: ich hoffe, dass mir jemand meinen Fehler aufzeigen und erklären kann, wie ich ihn beheben mussHier der Code meiner Quelldatei und der Main-Datei. Im Header sind nur die Attribute und die Konstruktoren:
Serialport.cpp
#include "Serialport.h" #include "pch.h" using namespace std; void SerialPort_Oeffnen(HANDLE CommPort) { const wchar_t *Port = TEXT("COM4"); CommPort = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); } void PrintCommState(DCB dcb) { int BaudRate = dcb.BaudRate; int ByteSize = dcb.ByteSize; int DCBlength = dcb.DCBlength; int EofChar = dcb.EofChar; int ErrorChar = dcb.ErrorChar; int EvtChar = dcb.EvtChar; int fDtrControl = dcb.fDtrControl; int fDsrSensitivity = dcb.fDsrSensitivity; int fDummy2 = dcb.fDummy2; int fOutX = dcb.fOutX; int fOutxCtsFlow = dcb.fOutxCtsFlow; int fRtsControl = dcb.fRtsControl; int fOutxDsrFlow = dcb.fOutxDsrFlow; int fTXContinueOnXoff = dcb.fTXContinueOnXoff; int wReserved = dcb.wReserved; int XoffChar = dcb.XoffChar; int XoffLim = dcb.XoffLim; int XonChar = dcb.XonChar; int XonLim = dcb.XonLim; cout << "BaudRate = " << BaudRate << "\n" << "ByteSize = " << ByteSize << "\n" << "DCBlength = " << DCBlength << "\n" << "EofChar = " << EofChar << "\n" << "ErrorChar = " << ErrorChar << "\n" << "fDtrControl = " << fDtrControl << "\n" << "fDsrSensitivity = " << fDsrSensitivity << "\n" << "fDummy2 = " << fDummy2 << "\n" << "fOutX = " << fOutX << "\n" << "fOutxCtsFlow = " << fOutxCtsFlow << "\n" << "fRtsControl = " << fRtsControl << "\n" << "fOutxDsrFlow = " << fOutxDsrFlow << "\n" << "fTXContinueOnXoff = " << fTXContinueOnXoff << "\n" << "wReserved = " << wReserved << "\n" << "XoffChar = " << XoffChar << "\n" << "XoffLim = " << XonChar << "\n" << "XonLim = " << XonLim << endl; }
Main.cpp
#include "pch.h" #include "Serialport.h" #include <iostream> int main() { SerialPort_Oeffnen(hcomm); SecureZeroMemory(&dcb_1, sizeof(DCB)); dcb_1.DCBlength = sizeof(DCB); GetCommState(hcomm, &dcb_1); PrintCommState(dcb_1); CloseHandle(hcomm); system("Pause"); }
Ich freue mich auf eure Hilfe! Vielen Dank und euch ein gutes Wochenende!
P.S.:
Hier meine Quellen. Als Referenz nehme ich den Code aus (1).
(1) https://docs.microsoft.com/de-de/windows/desktop/DevIO/configuring-a-communications-resource
(2) https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498
Falls noch wichtig, hier näheres zu meinem Hintergrund: Bin Student, hatte jetzt ein Semester Informatik und möchte gern das gelernte nebenher vertiefen / auffrischen. Vielleicht mag deshalb einiges sehr umständlich erscheinen.
-
Deine Funktion
SerialPort_Oeffnen
ist falsch, da du den ParameterCommPort
nur lokal beschreibst (und nicht den übergebenen Parameterhcomm
).
Entweder als Referenz übergeben oder noch besser gleich als Rückgabewert (denn einen Eingabeparameter brauchst du dafür ja nicht):HANDLE SerialPort_Oeffnen() { HANDLE commPort = ...; return commPort; }
Und dann entsprechend den Aufruf abändern.
Edit: Und bei Systemfunktionen wie GetCommState immer den Rückgabewert (-> Fehlercode) prüfen.
-
Hi Jon,
die Sachen mit dem rs232 sind wesentlich komplexer als man zu vermuten glaubt, gerade im Zusammenhang mit all den möglichen Konfigurationen.
Über Jahrzehnte hat sich unter Windows folgendes bewährt:
CVersions::DbgMsg(false, kannst Du durch TRACE( ersetzen..
#include "StdAfx.h" #include "serialio.h" #include <process.h> //*************************************************************** SERIAL IO TEMPLATE **************************************************** CSerialIO::CSerialIO(void) : m_pcallback(0), m_UserDat(0), m_bConnected(false), m_lLastError(ERROR_SUCCESS), m_hFile(0), m_eEvent(EEventNone), m_dwEventMask(0), m_fStopping(false), m_hThread(0), m_hevtOverlapped(0), m_hevtOverlappedWorkerThread(0) { } CSerialIO::~CSerialIO(void) { Delete(); } bool CSerialIO::IsConnected(void) { return m_bConnected; } CStringList *CSerialIO::GetPortLst(void) { CString str; CHAR TargetPath[MAX_PATH]; m_strPortLst.RemoveAll(); for (int i = 0; i < 255; i++) { str.Format(_T("COM%d"), i); if (QueryDosDevice(str, (LPSTR)&TargetPath[0], sizeof(TargetPath))) m_strPortLst.AddTail(str); } return &m_strPortLst; } DWORD WINAPI CSerialIO::ThreadProc(LPVOID lpArg) { CSerialIO *pThis = (CSerialIO *)lpArg; return pThis->ThreadProc(); } DWORD CSerialIO::ThreadProc(void) { LPOVERLAPPED lpOverlapped = 0; do { ::ResetEvent(m_hevtOverlappedWorkerThread); OVERLAPPED ovInternal = { 0 }; ovInternal.hEvent = m_hevtOverlappedWorkerThread; DWORD ti(GetTickCount()); if (WaitEvent(&ovInternal) != ERROR_SUCCESS) return m_lLastError; if (::WaitForSingleObject(m_hevtOverlappedWorkerThread, INFINITE) != WAIT_OBJECT_0) { m_lLastError = ::GetLastError(); return m_lLastError; } if (!m_fStopping) { EEvent eEvent = GetEventType(); DWORD dwErrors = 0; if (!::ClearCommError(m_hFile, &dwErrors, 0)) { m_lLastError = ::GetLastError(); } EError eError = EError(dwErrors); if (eEvent) OnEvent(eError, eEvent); } } while (!m_fStopping); return 0; } LRESULT CSerialIO::OnEvent(EError eError, EEvent eEvent) { if (eError) CVersions::DbgMsg(false,"CSerialIO::OnEvent An internal error occurred."); if (eEvent & CSerialIO::EEventBreak) CVersions::DbgMsg(false,"CSerialIO::OnEvent Break detected on input."); if (eEvent & CSerialIO::EEventError) CVersions::DbgMsg(false,"CSerialIO::OnEvent A line-status error occurred."); if (eEvent & CSerialIO::EEventRcvEv) CVersions::DbgMsg(false,"CSerialIO::OnEvent Event character has been received."); if (eEvent & CSerialIO::EEventRing) CVersions::DbgMsg(false,"CSerialIO::OnEvent Ring detected"); if (eEvent & CSerialIO::EEventSend) CVersions::DbgMsg(false,"CSerialIO::OnEvent All data is send"); if (eEvent & CSerialIO::EEventCTS) CVersions::DbgMsg(false,"CSerialIO::OnEvent CTS signal change %s %d", "CTS", GetCTS()); if (eEvent & CSerialIO::EEventDSR) CVersions::DbgMsg(false,"CSerialIO::OnEvent DSR signal change %s %d", "DSR", GetDSR()); if (eEvent & CSerialIO::EEventRLSD) CVersions::DbgMsg(false,"CSerialIO::OnEvent RLSD signal change %s %d", "RLSD", GetRLSD()); if (eEvent & CSerialIO::EEventRecv) { DWORD dwRead; char szData[256]; const int nBuflen = sizeof(szData) - 1; do { if (!Read(szData, nBuflen, &dwRead)) { if (dwRead > 0 && !m_pcallback(szData, dwRead, m_UserDat, this)) ; } } while (dwRead == nBuflen); } return 0; } LONG CSerialIO::StartListener(void) { if (m_hThread == 0) { DWORD dwThreadId = 0; m_hThread = ::CreateThread(0, 0, ThreadProc, LPVOID(this), 0, &dwThreadId); if (m_hThread == 0) { m_lLastError = ::GetLastError(); return m_lLastError; } } m_lLastError = ERROR_SUCCESS; return m_lLastError; } LONG CSerialIO::StopListener(DWORD dwTimeout) { if (m_hThread) { m_fStopping = true; SetMask(GetEventMask()); if (m_hevtOverlappedWorkerThread) SetEvent(m_hevtOverlappedWorkerThread); ::WaitForSingleObject(m_hThread, dwTimeout); m_fStopping = false; ::CloseHandle(m_hThread); m_hThread = 0; } m_lLastError = ERROR_SUCCESS; return m_lLastError; } void CSerialIO::Delete(void) { //if (!m_fStopping) Close(); } bool CSerialIO::Create(int comport, int baud,SERCALLBACK pC,DWORD UserDat, DWORD HandShake/*=0*/) { if (!pC || !comport || !baud) return false; Delete(); m_pcallback = pC; m_UserDat = UserDat; CString comStr; comStr.Format("COM%d",comport); if (CheckPort(comStr)) return false; if (Open(comStr, 0, 0)) return false; LONG stat = Setup((EBaudrate)baud/*EBaud115200*/, EData8, EParNone, EStop1); SetupHandshaking(HandShake);// EHandshakeOff); return (m_bConnected=true); } LONG CSerialIO::Open(LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue) { bool fOverlapped = true; m_lLastError = ERROR_SUCCESS; if (m_hFile) { m_lLastError = ERROR_ALREADY_INITIALIZED; return m_lLastError; } m_hFile = ::CreateFile(lpszDevice, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, fOverlapped ? FILE_FLAG_OVERLAPPED : 0, 0); if (m_hFile == INVALID_HANDLE_VALUE) { m_hFile = 0; m_lLastError = ::GetLastError(); return m_lLastError; } if (fOverlapped) { m_hevtOverlapped = ::CreateEvent(0, true, false, 0); if (m_hevtOverlapped == 0) { m_lLastError = ::GetLastError(); ::CloseHandle(m_hFile); m_hFile = 0; return m_lLastError; } } if (dwInQueue || dwOutQueue) { if (!::SetupComm(m_hFile, dwInQueue, dwOutQueue)) { long lLastError = ::GetLastError(); Close(); m_lLastError = lLastError; return m_lLastError; } } SetMask(); SetupReadTimeouts(EReadTimeoutNonblocking); COMMCONFIG commConfig = { 0 }; DWORD dwSize = sizeof(commConfig); commConfig.dwSize = dwSize; if (::GetDefaultCommConfig(lpszDevice, &commConfig, &dwSize)) { if (!::SetCommConfig(m_hFile, &commConfig, dwSize)) { ; } } else { ; } if (m_lLastError != ERROR_SUCCESS) return m_lLastError; m_hevtOverlappedWorkerThread = ::CreateEvent(0, true, false, 0); if (m_hevtOverlappedWorkerThread == 0) { m_lLastError = ::GetLastError(); Close(); return m_lLastError; } m_lLastError = StartListener(); if (m_lLastError != ERROR_SUCCESS) return m_lLastError; return m_lLastError; } inline BOOL CSerialIO::CancelCommIo(void) { return ::CancelIo(m_hFile); } CSerialIO::EPort CSerialIO::CheckPort(LPCTSTR lpszDevice) { HANDLE hFile = ::CreateFile(lpszDevice,GENERIC_READ | GENERIC_WRITE,0,0, OPEN_EXISTING,0,0); if (hFile == INVALID_HANDLE_VALUE) { switch (::GetLastError()) { case ERROR_FILE_NOT_FOUND: return EPortNotAvailable; case ERROR_ACCESS_DENIED: return EPortInUse; default: return EPortUnknownError; } } ::CloseHandle(hFile); return EPortAvailable; } LONG CSerialIO::Close(void) { StopListener(100);// INFINITE); if (m_hevtOverlappedWorkerThread) { ::CloseHandle(m_hevtOverlappedWorkerThread); m_hevtOverlappedWorkerThread = 0; } if (m_hevtOverlapped) { ::CloseHandle(m_hevtOverlapped); m_hevtOverlapped = 0; } m_lLastError = ERROR_SUCCESS; if (m_hFile == 0) return m_lLastError; ::CloseHandle(m_hFile); m_hFile = 0; m_bConnected = false; return m_lLastError; } LONG CSerialIO::Setup(EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits) { m_lLastError = ERROR_SUCCESS; if (m_hFile == 0) { m_lLastError = ERROR_INVALID_HANDLE; return m_lLastError; } CDCB dcb; if (!::GetCommState(m_hFile, &dcb)) { m_lLastError = ::GetLastError(); return m_lLastError; } dcb.BaudRate = DWORD(eBaudrate); dcb.ByteSize = BYTE(eDataBits); dcb.Parity = BYTE(eParity); dcb.StopBits = BYTE(eStopBits); dcb.fParity = (eParity != EParNone); if (!::SetCommState(m_hFile, &dcb)) { m_lLastError = ::GetLastError(); return m_lLastError; } return m_lLastError; } LONG CSerialIO::SetEventChar(BYTE bEventChar, bool fAdjustMask) { m_lLastError = ERROR_SUCCESS; if (m_hFile == 0) { m_lLastError = ERROR_INVALID_HANDLE; return m_lLastError; } CDCB dcb; if (!::GetCommState(m_hFile, &dcb)) { m_lLastError = ::GetLastError(); return m_lLastError; } dcb.EvtChar = char(bEventChar); if (fAdjustMask) { SetMask(GetEventMask() | EEventRcvEv); } if (!::SetCommState(m_hFile, &dcb)) { m_lLastError = ::GetLastError(); return m_lLastError; } return m_lLastError; } LONG CSerialIO::SetMask(DWORD dwEventMask) { m_lLastError = ERROR_SUCCESS; if (m_hFile == 0) { m_lLastError = ERROR_INVALID_HANDLE; _RPTF0(_CRT_WARN, "CSerialIO::SetMask - Device is not opened\n"); return m_lLastError; } if (!::SetCommMask(m_hFile, dwEventMask)) { m_lLastError = ::GetLastError(); return m_lLastError; } m_dwEventMask = dwEventMask; return m_lLastError; } LONG CSerialIO::WaitEvent(LPOVERLAPPED lpOverlapped, DWORD 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, "CSerialIO::WaitEvent - Device is not opened\n"); return m_lLastError; } // 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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::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); } // Return successfully return m_lLastError; } LONG CSerialIO::SetupHandshaking(int 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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::SetupHandshaking - Unable to set DCB information\n"); return m_lLastError; } // Return successful return m_lLastError; } LONG CSerialIO::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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::SetupReadTimeouts - Unable to set timeout information\n"); return m_lLastError; } // Return successful return m_lLastError; } CSerialIO::EBaudrate CSerialIO::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, "CSerialIO::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, "CSerialIO::GetBaudrate - Unable to obtain DCB information\n"); return EBaudUnknown; } // Return the appropriate baudrate return EBaudrate(dcb.BaudRate); } CSerialIO::EDataBits CSerialIO::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, "CSerialIO::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, "CSerialIO::GetDataBits - Unable to obtain DCB information\n"); return EDataUnknown; } // Return the appropriate bytesize return EDataBits(dcb.ByteSize); } CSerialIO::EParity CSerialIO::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, "CSerialIO::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, "CSerialIO::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); } CSerialIO::EStopBits CSerialIO::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, "CSerialIO::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, "CSerialIO::GetStopBits - Unable to obtain DCB information\n"); return EStopUnknown; } // Return the appropriate stopbits return EStopBits(dcb.StopBits); } DWORD CSerialIO::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, "CSerialIO::GetEventMask - Device is not opened\n"); return 0; } // Return the event mask return m_dwEventMask; } BYTE CSerialIO::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, "CSerialIO::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, "CSerialIO::GetEventChar - Unable to obtain DCB information\n"); return 0; } // Set the new event character return BYTE(dcb.EvtChar); } CSerialIO::EHandshake CSerialIO::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, "CSerialIO::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, "CSerialIO::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 CSerialIO::Write(const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) { // 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, "CSerialIO::Write - Device is not opened\n"); return m_lLastError; } // 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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::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); } // Return successfully return m_lLastError; } LONG CSerialIO::Read(void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) { // 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, "CSerialIO::Read - Device is not opened\n"); return m_lLastError; } // 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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::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, "CSerialIO::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); } // Return successfully return m_lLastError; } LONG CSerialIO::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, "CSerialIO::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, "CSerialIO::Purge - Overlapped completed without result\n"); } // Return successfully return m_lLastError; } LONG CSerialIO::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, "CSerialIO::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; } CSerialIO::EEvent CSerialIO::GetEventType(void) { // 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; } CSerialIO::EError CSerialIO::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, "CSerialIO::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, "CSerialIO::GetError - Unable to obtain COM status\n"); return EErrorUnknown; } // Return the error return EError(dwErrors); } bool CSerialIO::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, "CSerialIO::GetCTS - Unable to obtain the modem status\n"); return false; } // Determine if CTS is on return (dwModemStat & MS_CTS_ON) != 0; } bool CSerialIO::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, "CSerialIO::GetDSR - Unable to obtain the modem status\n"); return false; } // Determine if DSR is on return (dwModemStat & MS_DSR_ON) != 0; } bool CSerialIO::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, "CSerialIO::GetRing - Unable to obtain the modem status"); return false; } // Determine if Ring is on return (dwModemStat & MS_RING_ON) != 0; } bool CSerialIO::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, "CSerialIO::GetRLSD - Unable to obtain the modem status"); return false; } // Determine if RLSD is on return (dwModemStat & MS_RLSD_ON) != 0; } bool CSerialIO::SetDTR(bool Stat) { if (!EscapeCommFunction(m_hFile, Stat ? SETDTR : CLRDTR)) return false; return true; } bool CSerialIO::SetRTS(bool Stat) { if (!EscapeCommFunction(m_hFile, Stat ? SETRTS : CLRRTS)) return false; return true; } Header Zusatz: #include "y:\\Common\Versions\Versions.h" #pragma once #ifdef _DEBUG #pragma comment(lib, "seriod.lib") #else #pragma comment(lib, "serio.lib") #endif /******************************* SERIAL EXCESS ***********************************/ class CSerialIO; typedef int (AFX_CDECL *SERCALLBACK)(void *,int,DWORD,CSerialIO *); class CSerialIO { public: CSerialIO(void); ~CSerialIO(void); public: bool IsConnected(void); void Delete(void); bool Create(int comport, int baud, SERCALLBACK pC,DWORD UserDat, DWORD HandShake=0); CStringList *GetPortLst(void); protected: bool m_bConnected; DWORD m_UserDat; SERCALLBACK m_pcallback; CStringList m_strPortLst; public: typedef enum { EEventUnknown = -1, EEventNone = 0, EEventBreak = EV_BREAK, EEventCTS = EV_CTS, EEventDSR = EV_DSR, EEventError = EV_ERR, EEventRing = EV_RING, EEventRLSD = EV_RLSD, EEventRecv = EV_RXCHAR, EEventRcvEv = EV_RXFLAG, EEventSend = EV_TXEMPTY, EEventPrinterError = EV_PERR, EEventRx80Full = EV_RX80FULL, EEventProviderEvt1 = EV_EVENT1, EEventProviderEvt2 = EV_EVENT2, } EEvent; typedef enum { EBaudUnknown = -1, EBaud110 = CBR_110, EBaud300 = CBR_300, EBaud600 = CBR_600, EBaud1200 = CBR_1200, EBaud2400 = CBR_2400, EBaud4800 = CBR_4800, EBaud9600 = CBR_9600, EBaud14400 = CBR_14400, EBaud19200 = CBR_19200, EBaud38400 = CBR_38400, EBaud56000 = CBR_56000, EBaud57600 = CBR_57600, EBaud115200 = CBR_115200, EBaud128000 = CBR_128000, EBaud256000 = CBR_256000, } EBaudrate; typedef enum { EDataUnknown = -1, EData5 = 5, EData6 = 6, EData7 = 7, EData8 = 8 } EDataBits; typedef enum { EParUnknown = -1, EParNone = NOPARITY, EParOdd = ODDPARITY, EParEven = EVENPARITY, EParMark = MARKPARITY, EParSpace = SPACEPARITY } EParity; typedef enum { EStopUnknown = -1, EStop1 = ONESTOPBIT, EStop1_5 = ONE5STOPBITS, EStop2 = TWOSTOPBITS } EStopBits; typedef enum { EHandshakeUnknown = -1, EHandshakeOff = 0, EHandshakeHardware = 1, EHandshakeSoftware = 2 } EHandshake; typedef enum { EReadTimeoutUnknown = -1, EReadTimeoutNonblocking = 0, EReadTimeoutBlocking = 1 } EReadTimeout; typedef enum { EErrorUnknown = 0, EErrorBreak = CE_BREAK, EErrorFrame = CE_FRAME, EErrorIOE = CE_IOE, EErrorMode = CE_MODE, EErrorOverrun = CE_OVERRUN, EErrorRxOver = CE_RXOVER, EErrorParity = CE_RXPARITY, EErrorTxFull = CE_TXFULL } EError; typedef enum { EPortUnknownError = -1, EPortAvailable = 0, EPortNotAvailable = 1, EPortInUse = 2 } EPort; public: static DWORD WINAPI ThreadProc(LPVOID lpArg); static EPort CheckPort(LPCTSTR lpszDevice); long Open(LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0); LONG Close(void); LONG Setup(EBaudrate eBaudrate = EBaud9600, EDataBits eDataBits = EData8, EParity eParity = EParNone, EStopBits eStopBits = EStop1); LONG SetEventChar(BYTE bEventChar, bool fAdjustMask = true); LONG SetMask(DWORD dwMask = EEventBreak | EEventError | EEventRecv); LONG WaitEvent(LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); LONG SetupHandshaking(int eHandshake); LONG SetupReadTimeouts(EReadTimeout eReadTimeout); EBaudrate GetBaudrate(void); EDataBits GetDataBits(void); EParity GetParity(void); EStopBits GetStopBits(void); EHandshake GetHandshaking(void); DWORD GetEventMask(void); BYTE GetEventChar(void); LONG Write(const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); LONG Read(void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); LONG Break(void); EEvent GetEventType(void); EError GetError(void); HANDLE GetCommHandle(void) { return m_hFile; } bool IsOpen(void) const { return (m_hFile != 0); } LONG GetLastError(void) const { return m_lLastError; } bool GetCTS(void); bool GetDSR(void); bool GetRing(void); bool GetRLSD(void); LONG Purge(void); bool SetDTR(bool Stat); bool SetRTS(bool Stat); protected: class CDCB : public DCB{public:CDCB() { DCBlength = sizeof(DCB); }}; BOOL CancelCommIo(void); LRESULT OnEvent(EError eError, EEvent eEvent); LONG StartListener(void); LONG StopListener(DWORD dwTimeout = INFINITE); DWORD ThreadProc(void); LONG m_lLastError; HANDLE m_hFile; EEvent m_eEvent; DWORD m_dwEventMask; HANDLE m_hevtOverlapped; bool m_fStopping; HANDLE m_hThread; HANDLE m_hevtOverlappedWorkerThread; };
-
@KahnSoft: Über Jahrzehnte hat sich in diesem Forum folgendes bewährt: Code-Tags setzen ;- )
-
Funktioniert leider nicht mehr so wie früher, ist halt neu. Konnte ich auch nachträglich nicht aktivieren, scheinen Spezialkenntnisse nötig zu sein.
-
Du wirst ja wohl den Code markieren und den "</>"-Button drücken können?
Ansonsten ist dein Beitrag nämlich so komplett sinnlos.
-
Ah funktioniert mit Edge, IE Scheint unterdrückt zu werden , sinnlos ist vieles. Und genau das macht den Sinn aus.