├── Examples ├── SerialPortAsyncTest │ ├── SerialPortAsyncTest.cpp │ ├── SerialPortAsyncTest.dsp │ ├── SerialPortAsyncTest.dsw │ ├── StateMachine.cpp │ └── StateMachine.h └── SerialPortTest │ ├── SerialPortTest.cpp │ ├── SerialPortTest.dsp │ └── SerialPortTest.dsw ├── README.md ├── SerialPort.c ├── SerialPort.cpp ├── SerialPort.h └── SerialPort.hpp /Examples/SerialPortAsyncTest/SerialPortAsyncTest.cpp: -------------------------------------------------------------------------------- 1 | #include "SerialPort.h" 2 | #include 3 | #include "StateMachine.h" 4 | 5 | StateMachine stateMachine; 6 | 7 | void CommandReceived(unsigned char command, unsigned char param1, unsigned char param2) 8 | { 9 | printf("Info: Command received (Cmd: %i, Param1: %i, Param2: %i)\r\n", command, param1, param2); 10 | } 11 | 12 | void DataReceived (const unsigned char* pData, int dataLength) 13 | { 14 | for(int i = 0; i 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=SerialPortAsyncTest - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "SerialPortAsyncTest.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "SerialPortAsyncTest.mak" CFG="SerialPortAsyncTest - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "SerialPortAsyncTest - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "SerialPortAsyncTest - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "SerialPortAsyncTest - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c 44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | 54 | !ELSEIF "$(CFG)" == "SerialPortAsyncTest - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Ignore_Export_Lib 0 66 | # PROP Target_Dir "" 67 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c 68 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c 69 | # SUBTRACT CPP /YX /Yc /Yu 70 | # ADD BASE RSC /l 0x409 /d "_DEBUG" 71 | # ADD RSC /l 0x409 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # ADD BSC32 /nologo 75 | LINK32=link.exe 76 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 77 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 78 | 79 | !ENDIF 80 | 81 | # Begin Target 82 | 83 | # Name "SerialPortAsyncTest - Win32 Release" 84 | # Name "SerialPortAsyncTest - Win32 Debug" 85 | # Begin Group "Source Files" 86 | 87 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 88 | # Begin Source File 89 | 90 | SOURCE=..\..\SerialPort.cpp 91 | # End Source File 92 | # Begin Source File 93 | 94 | SOURCE=.\SerialPortAsyncTest.cpp 95 | # End Source File 96 | # Begin Source File 97 | 98 | SOURCE=.\StateMachine.cpp 99 | # End Source File 100 | # End Group 101 | # Begin Group "Header Files" 102 | 103 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 104 | # Begin Source File 105 | 106 | SOURCE=..\..\SerialPort.h 107 | # End Source File 108 | # Begin Source File 109 | 110 | SOURCE=.\StateMachine.h 111 | # End Source File 112 | # End Group 113 | # Begin Group "Resource Files" 114 | 115 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 116 | # End Group 117 | # Begin Source File 118 | 119 | SOURCE=.\ReadMe.txt 120 | # End Source File 121 | # End Target 122 | # End Project 123 | -------------------------------------------------------------------------------- /Examples/SerialPortAsyncTest/SerialPortAsyncTest.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "SerialPortAsyncTest"=.\SerialPortAsyncTest.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /Examples/SerialPortAsyncTest/StateMachine.cpp: -------------------------------------------------------------------------------- 1 | #include "StateMachine.h" 2 | #include 3 | 4 | StateMachine::StateMachine() 5 | { 6 | m_commandReceivedHandler = NULL; 7 | m_state = sMagicByte; 8 | m_command = 0; 9 | m_param1 = 0; 10 | m_param2 = 0; 11 | } 12 | 13 | void StateMachine::SetEventHandler(void (*commandReceivedHandler)(unsigned char command, unsigned char param1, unsigned char param2)) 14 | { 15 | m_commandReceivedHandler = commandReceivedHandler; 16 | } 17 | 18 | void StateMachine::OnByteReceived(unsigned char b) 19 | { 20 | switch (m_state) 21 | { 22 | case sMagicByte: 23 | { 24 | if (b==MAGICBYTE) 25 | { 26 | m_state = sCommand; 27 | } 28 | } 29 | break; 30 | 31 | case sCommand: 32 | { 33 | m_command = b; 34 | m_state = sParam1; 35 | } 36 | break; 37 | 38 | case sParam1: 39 | { 40 | m_param1 = b; 41 | m_state = sParam2; 42 | } 43 | break; 44 | 45 | case sParam2: 46 | { 47 | m_param2 = b; 48 | m_state = sMagicByte; 49 | 50 | if (m_commandReceivedHandler) 51 | { 52 | m_commandReceivedHandler(m_command, m_param1, m_param2); 53 | } 54 | } 55 | break; 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /Examples/SerialPortAsyncTest/StateMachine.h: -------------------------------------------------------------------------------- 1 | #ifndef STATEMACHINE___H 2 | #define STATEMACHINE___H 3 | 4 | #define MAGICBYTE 0x38 5 | 6 | enum State 7 | { 8 | sMagicByte, 9 | sCommand, 10 | sParam1, 11 | sParam2, 12 | }; 13 | 14 | 15 | class StateMachine 16 | { 17 | private: 18 | State m_state; 19 | unsigned char m_command; 20 | unsigned char m_param1; 21 | unsigned char m_param2; 22 | 23 | void (*m_commandReceivedHandler)(unsigned char command, unsigned char param1, unsigned char param2); 24 | 25 | public: 26 | StateMachine(); 27 | void SetEventHandler(void (*commandReceivedHandler)(unsigned char command, unsigned char param1, unsigned char param2)); 28 | void OnByteReceived(unsigned char b); 29 | 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /Examples/SerialPortTest/SerialPortTest.cpp: -------------------------------------------------------------------------------- 1 | #include "SerialPort.h" 2 | #include 3 | 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | char response[64]; 8 | 9 | TSerialPort com1; 10 | com1.Open(3, 9600, 1000); 11 | while(1) 12 | { 13 | com1.WriteLine("050010"); 14 | com1.ReadLine(response, sizeof(response)); 15 | 16 | printf("Response: %s\r\n", response); 17 | } 18 | com1.Close(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /Examples/SerialPortTest/SerialPortTest.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="SerialPortTest" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=SerialPortTest - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "SerialPortTest.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "SerialPortTest.mak" CFG="SerialPortTest - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "SerialPortTest - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "SerialPortTest - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "SerialPortTest - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c 44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | 54 | !ELSEIF "$(CFG)" == "SerialPortTest - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Ignore_Export_Lib 0 66 | # PROP Target_Dir "" 67 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c 68 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c 69 | # SUBTRACT CPP /YX /Yc /Yu 70 | # ADD BASE RSC /l 0x409 /d "_DEBUG" 71 | # ADD RSC /l 0x409 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # SUBTRACT BSC32 /nologo 75 | LINK32=link.exe 76 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 77 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 78 | 79 | !ENDIF 80 | 81 | # Begin Target 82 | 83 | # Name "SerialPortTest - Win32 Release" 84 | # Name "SerialPortTest - Win32 Debug" 85 | # Begin Group "Source Files" 86 | 87 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 88 | # Begin Source File 89 | 90 | SOURCE=..\..\SerialPort.cpp 91 | # End Source File 92 | # Begin Source File 93 | 94 | SOURCE=.\SerialPortTest.cpp 95 | # End Source File 96 | # End Group 97 | # Begin Group "Header Files" 98 | 99 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 100 | # Begin Source File 101 | 102 | SOURCE=..\..\SerialPort.hpp 103 | # End Source File 104 | # End Group 105 | # Begin Group "Resource Files" 106 | 107 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 108 | # End Group 109 | # Begin Source File 110 | 111 | SOURCE=.\ReadMe.txt 112 | # End Source File 113 | # End Target 114 | # End Project 115 | -------------------------------------------------------------------------------- /Examples/SerialPortTest/SerialPortTest.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "SerialPortAsyncTest"=.\SerialPortAsyncTest\SerialPortAsyncTest.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Project: "SerialPortTest"=.\SerialPortTest.dsp - Package Owner=<4> 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<4> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | Global: 31 | 32 | Package=<5> 33 | {{{ 34 | }}} 35 | 36 | Package=<3> 37 | {{{ 38 | }}} 39 | 40 | ############################################################################### 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple C a C++ library for handling serial port communication. 2 | 3 | During embedded system development is always easier to debug the communication protocol on PC, because debugging on PC and with Visual Studio is much more comfortable than on any embedded system. 4 | 5 | However embeeded software developers are often not interrested to develop a new quite complex component for Serial port communication on Windows OS. 6 | 7 | This library is ready to use for any embedded developer (it requires no additional research or effort), it supports BOTH styles of data receiving - calling an event immediatelly after data are received OR waiting for specific amount of data with timeout. 8 | 9 | You can look into example projects for Visual Studio. 10 | -------------------------------------------------------------------------------- /SerialPort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows Serial Port for Windows API 3 | * 4 | * Copyright (c) 2016 Ondrej Sterba 5 | * 6 | * https://github.com/embedded-tools/WindowsSerialPort 7 | * 8 | * Permission to use, copy, modify, distribute and sell this software 9 | * and its documentation for any purpose is hereby granted without fee 10 | * provided that the above copyright notice appear in all copies and 11 | * that both that copyright notice and this permission notice appear 12 | * in supporting documentation. 13 | * It is provided "as is" without express or implied warranty. 14 | * 15 | */ 16 | 17 | #include "SerialPort.h" 18 | #include 19 | #include 20 | 21 | static HANDLE m_portHandle = 0; 22 | static HANDLE m_workingThread = 0; 23 | static DWORD m_workingThreadId = 0; 24 | static int m_timeoutMilliSeconds = 0; 25 | static void (*m_OnDataReceivedHandler)(const unsigned char* pData, int dataLength) = NULL; 26 | static void (*m_OnDataSentHandler)(void) = NULL; 27 | static CRITICAL_SECTION m_criticalSectionRead; 28 | static CRITICAL_SECTION m_criticalSectionWrite; 29 | 30 | DWORD WINAPI SerialPort_WaitForData( LPVOID lpParam ); 31 | int SerialPort__WriteBuffer(const unsigned char* pData, int dataLength); 32 | int SerialPort__ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS); 33 | 34 | #define SERIALPORT_INTERNAL_TIMEOUT 1 35 | 36 | void SerialPort_Initialize(void) 37 | { 38 | m_portHandle = NULL; 39 | m_OnDataReceivedHandler = NULL; 40 | m_OnDataSentHandler = NULL; 41 | m_timeoutMilliSeconds = 0; 42 | m_workingThread = NULL; 43 | m_workingThreadId = 0; 44 | InitializeCriticalSection(&m_criticalSectionRead); 45 | InitializeCriticalSection(&m_criticalSectionWrite); 46 | } 47 | 48 | void SerialPort_Uninitialize(void) 49 | { 50 | if (m_portHandle) 51 | { 52 | SerialPort_Close(); 53 | } 54 | DeleteCriticalSection(&m_criticalSectionRead); 55 | DeleteCriticalSection(&m_criticalSectionWrite); 56 | } 57 | 58 | int SerialPort_GetMaxTimeout() 59 | { 60 | return m_timeoutMilliSeconds; 61 | } 62 | 63 | BOOL SerialPort_OpenAsync(int comPortNumber, int baudRate, 64 | void (*OnDataReceivedHandler)(const unsigned char* pData, int dataLength), 65 | void (*OnDataSentHandler)(void), 66 | int timeoutMS 67 | ) 68 | 69 | { 70 | BOOL result = SerialPort_Open(comPortNumber, baudRate, timeoutMS); 71 | if (result) 72 | { 73 | m_OnDataReceivedHandler = OnDataReceivedHandler; 74 | m_OnDataSentHandler = OnDataSentHandler; 75 | if (m_OnDataSentHandler || m_OnDataReceivedHandler) 76 | { 77 | m_workingThread = CreateThread(NULL, 0, SerialPort_WaitForData, NULL, 0, &m_workingThreadId); 78 | } 79 | } 80 | return result; 81 | } 82 | 83 | BOOL SerialPort_Open(int comPortNumber, int baudRate, int timeoutMS) 84 | { 85 | char portName[12]; 86 | int portNameLength; 87 | DCB portSettings; 88 | COMMTIMEOUTS portTimeOuts; 89 | 90 | if (comPortNumber<0) return FALSE; 91 | if (comPortNumber>255) return FALSE; 92 | if (timeoutMS>15000) return FALSE; 93 | 94 | portNameLength = sprintf(portName, "\\\\.\\COM%i", comPortNumber ); 95 | 96 | m_portHandle = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 97 | if ((m_portHandle==0) || ((unsigned long)m_portHandle==0xffffffff)) 98 | { 99 | m_portHandle = 0; 100 | return FALSE; 101 | } 102 | 103 | m_timeoutMilliSeconds = timeoutMS; 104 | 105 | memset(&portSettings, 0, sizeof(portSettings)); 106 | 107 | portSettings.BaudRate = baudRate; 108 | portSettings.ByteSize = 8; 109 | portSettings.Parity = NOPARITY; 110 | portSettings.StopBits = ONESTOPBIT; 111 | 112 | if (!SetCommState(m_portHandle, &portSettings)) 113 | { 114 | return FALSE; 115 | } 116 | 117 | memset(&portTimeOuts, 0, sizeof(portTimeOuts)); 118 | portTimeOuts.ReadIntervalTimeout = SERIALPORT_INTERNAL_TIMEOUT; 119 | portTimeOuts.ReadTotalTimeoutMultiplier = 0; 120 | portTimeOuts.ReadTotalTimeoutConstant = SERIALPORT_INTERNAL_TIMEOUT; 121 | 122 | if (!SetCommTimeouts(m_portHandle, &portTimeOuts)) 123 | { 124 | return FALSE; 125 | } 126 | return (m_portHandle!=0); 127 | } 128 | 129 | void SerialPort_Close() 130 | { 131 | EnterCriticalSection(&m_criticalSectionRead); //prevents port closing if ReadBuffer is not complete 132 | EnterCriticalSection(&m_criticalSectionWrite); //prevents port closing if WriteBuffer is not complete 133 | if (m_portHandle) 134 | { 135 | CloseHandle(m_portHandle); 136 | m_portHandle = NULL; 137 | Sleep(SERIALPORT_INTERNAL_TIMEOUT*4); 138 | m_workingThread = NULL; 139 | m_workingThreadId = 0; 140 | } 141 | LeaveCriticalSection(&m_criticalSectionRead); 142 | LeaveCriticalSection(&m_criticalSectionWrite); 143 | } 144 | 145 | BOOL SerialPort_IsOpen() 146 | { 147 | return (m_portHandle!=NULL); 148 | } 149 | 150 | int SerialPort__WriteBuffer(const unsigned char* pData, int dataLength) 151 | { 152 | DWORD bytesWritten = 0; 153 | 154 | if (m_portHandle==NULL) 155 | { 156 | return 0; 157 | } 158 | 159 | if (!WriteFile(m_portHandle, pData, dataLength, &bytesWritten, NULL)) 160 | { 161 | return 0; 162 | } 163 | return (int)bytesWritten; 164 | } 165 | 166 | int SerialPort__ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS) 167 | { 168 | DWORD bytesRead,bytesReadTotal; 169 | int timeOutCounter, bytesLeft; 170 | 171 | if (m_portHandle==NULL) 172 | { 173 | return 0; 174 | } 175 | if (timeOutMS<0) 176 | { 177 | timeOutMS = m_timeoutMilliSeconds; 178 | } 179 | 180 | bytesRead = 0; 181 | bytesReadTotal = 0; 182 | timeOutCounter = timeOutMS; 183 | bytesLeft = dataLength; 184 | 185 | if (timeOutMS0) 192 | { 193 | bytesRead = 0; 194 | ReadFile(m_portHandle, pData+bytesReadTotal, dataLength, &bytesRead, NULL); 195 | if (bytesRead) 196 | { 197 | dataLength -= bytesRead; 198 | bytesReadTotal += bytesRead; 199 | if (dataLength==0) break; 200 | timeOutCounter = timeOutMS; 201 | } else { 202 | timeOutCounter -= SERIALPORT_INTERNAL_TIMEOUT; 203 | } 204 | 205 | } 206 | } 207 | return bytesReadTotal; 208 | } 209 | 210 | int SerialPort_ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS) 211 | { 212 | int result; 213 | EnterCriticalSection(&m_criticalSectionRead); 214 | result = SerialPort__ReadBuffer(pData, dataLength, timeOutMS); 215 | LeaveCriticalSection(&m_criticalSectionRead); 216 | return result; 217 | } 218 | 219 | 220 | int SerialPort_WriteBuffer(const unsigned char* pData, int dataLength) 221 | { 222 | int result; 223 | EnterCriticalSection(&m_criticalSectionWrite); 224 | result = SerialPort__WriteBuffer(pData, dataLength); 225 | LeaveCriticalSection(&m_criticalSectionWrite); 226 | if (m_OnDataSentHandler) 227 | { 228 | m_OnDataSentHandler(); 229 | } 230 | return result; 231 | } 232 | 233 | 234 | int SerialPort_WriteLine(char* pLine, BOOL addCRatEnd) 235 | { 236 | int lineLength, result; 237 | 238 | if (m_portHandle==NULL) 239 | { 240 | return 0; 241 | } 242 | if (pLine==NULL) 243 | { 244 | return 0; 245 | } 246 | lineLength = strlen(pLine); 247 | if (lineLength==0) 248 | { 249 | return 0; 250 | } 251 | 252 | EnterCriticalSection(&m_criticalSectionWrite); 253 | result = SerialPort__WriteBuffer((unsigned char*)pLine, lineLength); 254 | if (pLine[lineLength-1]!=0x0D) 255 | { 256 | char cr = 13; 257 | result+=SerialPort__WriteBuffer((unsigned char*)&cr, 1); 258 | } 259 | LeaveCriticalSection(&m_criticalSectionWrite); 260 | if (m_OnDataSentHandler) 261 | { 262 | m_OnDataSentHandler(); 263 | } 264 | return result; 265 | } 266 | 267 | int SerialPort_ReadLine(char* pLine, int maxBufferSize, int timeOutMS) 268 | { 269 | int result; 270 | if (m_portHandle==NULL) 271 | { 272 | return 0; 273 | } 274 | if (pLine==NULL) 275 | { 276 | return 0; 277 | } 278 | 279 | EnterCriticalSection(&m_criticalSectionRead); 280 | result = SerialPort__ReadBuffer((unsigned char*)pLine, maxBufferSize-1, timeOutMS); 281 | if (result 5 | * 6 | * https://github.com/embedded-tools/WindowsSerialPort 7 | * 8 | * Permission to use, copy, modify, distribute and sell this software 9 | * and its documentation for any purpose is hereby granted without fee 10 | * provided that the above copyright notice appear in all copies and 11 | * that both that copyright notice and this permission notice appear 12 | * in supporting documentation. 13 | * It is provided "as is" without express or implied warranty. 14 | * 15 | */ 16 | 17 | #include "SerialPort.hpp" 18 | #include 19 | #include 20 | 21 | #define SERIALPORT_INTERNAL__TIMEOUT 1 22 | 23 | TSerialPort::TSerialPort() 24 | { 25 | m_portHandle = NULL; 26 | m_OnDataReceivedHandler = NULL; 27 | m_OnDataSentHandler = NULL; 28 | m_timeoutMilliSeconds = 0; 29 | m_workingThread = NULL; 30 | m_workingThreadId = 0; 31 | InitializeCriticalSection(&m_criticalSectionRead); 32 | InitializeCriticalSection(&m_criticalSectionWrite); 33 | } 34 | 35 | TSerialPort::~TSerialPort() 36 | { 37 | if (m_portHandle) 38 | { 39 | Close(); 40 | } 41 | DeleteCriticalSection(&m_criticalSectionRead); 42 | DeleteCriticalSection(&m_criticalSectionWrite); 43 | } 44 | 45 | int TSerialPort::GetMaxTimeout() 46 | { 47 | return m_timeoutMilliSeconds; 48 | } 49 | 50 | void* TSerialPort::GetDataReceivedHandler() 51 | { 52 | return m_OnDataReceivedHandler; 53 | } 54 | 55 | void* TSerialPort::GetDataSentHandler() 56 | { 57 | return m_OnDataSentHandler; 58 | } 59 | 60 | bool TSerialPort::OpenAsync(int comPortNumber, 61 | int baudRate, 62 | void (*OnDataReceivedHandler)(const unsigned char* pData, int dataLength), 63 | void (*OnDataSentHandler)(void), 64 | int timeoutMS 65 | ) 66 | { 67 | bool result = Open(comPortNumber, baudRate, timeoutMS); 68 | if (result) 69 | { 70 | m_OnDataReceivedHandler = OnDataReceivedHandler; 71 | m_OnDataSentHandler = OnDataSentHandler; 72 | if (m_OnDataSentHandler || m_OnDataReceivedHandler) 73 | { 74 | m_workingThread = CreateThread(NULL, 0, SerialPort_WaitForData, this, 0, &m_workingThreadId); 75 | } 76 | } 77 | return result; 78 | } 79 | 80 | bool TSerialPort::Open(int comPortNumber, int baudRate, int timeoutMS) 81 | { 82 | char portName[12]; 83 | int portNameLength; 84 | if (comPortNumber<0) return false; 85 | if (comPortNumber>255) return false; 86 | if (timeoutMS>15000) return false; 87 | 88 | portNameLength = sprintf(portName, "\\\\.\\COM%i", comPortNumber ); 89 | 90 | m_portHandle = CreateFileA(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 91 | if ((m_portHandle==0) || ((unsigned long)m_portHandle==0xffffffff)) 92 | { 93 | m_portHandle = 0; 94 | return false; 95 | } 96 | 97 | m_timeoutMilliSeconds = timeoutMS; 98 | 99 | DCB portSettings; 100 | memset(&portSettings, 0, sizeof(portSettings)); 101 | 102 | portSettings.BaudRate = baudRate; 103 | portSettings.ByteSize = 8; 104 | portSettings.Parity = NOPARITY; 105 | portSettings.StopBits = ONESTOPBIT; 106 | 107 | if (!SetCommState(m_portHandle, &portSettings)) 108 | { 109 | return false; 110 | } 111 | 112 | COMMTIMEOUTS portTimeOuts; 113 | memset(&portTimeOuts, 0, sizeof(portTimeOuts)); 114 | portTimeOuts.ReadIntervalTimeout = SERIALPORT_INTERNAL_TIMEOUT; 115 | portTimeOuts.ReadTotalTimeoutMultiplier = 0; 116 | portTimeOuts.ReadTotalTimeoutConstant = SERIALPORT_INTERNAL_TIMEOUT; 117 | 118 | if (!SetCommTimeouts(m_portHandle, &portTimeOuts)) 119 | { 120 | return false; 121 | } 122 | return (m_portHandle!=0); 123 | } 124 | 125 | void TSerialPort::Close() 126 | { 127 | EnterCriticalSection(&m_criticalSectionRead); //prevents port closing if ReadBuffer is not complete 128 | EnterCriticalSection(&m_criticalSectionWrite); //prevents port closing if WriteBuffer is not complete 129 | if (m_portHandle) 130 | { 131 | CloseHandle(m_portHandle); 132 | m_portHandle = NULL; 133 | Sleep(SERIALPORT_INTERNAL_TIMEOUT*4); 134 | m_workingThread = NULL; 135 | m_workingThreadId = 0; 136 | } 137 | LeaveCriticalSection(&m_criticalSectionRead); 138 | LeaveCriticalSection(&m_criticalSectionWrite); 139 | } 140 | 141 | bool TSerialPort::IsOpen() 142 | { 143 | return (m_portHandle!=0); 144 | } 145 | 146 | int TSerialPort::__WriteBuffer(const unsigned char* pData, int dataLength) 147 | { 148 | if (m_portHandle==NULL) 149 | { 150 | return 0; 151 | } 152 | DWORD bytesWritten = 0; 153 | 154 | if (!WriteFile(m_portHandle, pData, dataLength, &bytesWritten, NULL)) 155 | { 156 | return 0; 157 | } 158 | return (int)bytesWritten; 159 | } 160 | 161 | int TSerialPort::__ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS) 162 | { 163 | DWORD bytesRead,bytesReadTotal; 164 | int timeOutCounter, bytesLeft; 165 | 166 | if (m_portHandle==NULL) 167 | { 168 | return 0; 169 | } 170 | if (timeOutMS<0) 171 | { 172 | timeOutMS = m_timeoutMilliSeconds; 173 | } 174 | 175 | bytesRead = 0; 176 | bytesReadTotal = 0; 177 | timeOutCounter = timeOutMS; 178 | bytesLeft = dataLength; 179 | 180 | if (timeOutMS0) 187 | { 188 | bytesRead = 0; 189 | ReadFile(m_portHandle, pData+bytesReadTotal, dataLength, &bytesRead, NULL); 190 | if (bytesRead) 191 | { 192 | dataLength -= bytesRead; 193 | bytesReadTotal += bytesRead; 194 | if (dataLength==0) break; 195 | timeOutCounter = timeOutMS; 196 | } else { 197 | timeOutCounter -= SERIALPORT_INTERNAL_TIMEOUT; 198 | } 199 | } 200 | } 201 | if (bytesReadTotal) 202 | { 203 | if (m_OnDataReceivedHandler) 204 | { 205 | m_OnDataReceivedHandler(pData, bytesReadTotal); 206 | } 207 | } 208 | return bytesReadTotal; 209 | } 210 | 211 | int TSerialPort::ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS) 212 | { 213 | EnterCriticalSection(&m_criticalSectionRead); 214 | int result = __ReadBuffer(pData, dataLength, timeOutMS); 215 | LeaveCriticalSection(&m_criticalSectionRead); 216 | return result; 217 | } 218 | 219 | 220 | int TSerialPort::WriteBuffer(const unsigned char* pData, int dataLength) 221 | { 222 | EnterCriticalSection(&m_criticalSectionWrite); 223 | int result = __WriteBuffer(pData, dataLength); 224 | LeaveCriticalSection(&m_criticalSectionWrite); 225 | if (m_OnDataSentHandler) 226 | { 227 | m_OnDataSentHandler(); 228 | } 229 | return result; 230 | } 231 | 232 | 233 | int TSerialPort::WriteLine(char* pLine, bool addCRatEnd) 234 | { 235 | 236 | if (m_portHandle==NULL) 237 | { 238 | return 0; 239 | } 240 | if (pLine==NULL) 241 | { 242 | return 0; 243 | } 244 | int lineLength = strlen(pLine); 245 | if (lineLength==0) 246 | { 247 | return 0; 248 | } 249 | 250 | EnterCriticalSection(&m_criticalSectionWrite); 251 | int result = __WriteBuffer((unsigned char*)pLine, lineLength); 252 | if (pLine[lineLength-1]!=0x0D) 253 | { 254 | char cr = 13; 255 | result+=__WriteBuffer((unsigned char*)&cr, 1); 256 | } 257 | LeaveCriticalSection(&m_criticalSectionWrite); 258 | if (m_OnDataSentHandler) 259 | { 260 | m_OnDataSentHandler(); 261 | } 262 | return result; 263 | } 264 | 265 | int TSerialPort::ReadLine(char* pLine, int maxBufferSize, int timeOutMS) 266 | { 267 | if (m_portHandle==NULL) 268 | { 269 | return 0; 270 | } 271 | if (pLine==NULL) 272 | { 273 | return 0; 274 | } 275 | 276 | EnterCriticalSection(&m_criticalSectionRead); 277 | int result = __ReadBuffer((unsigned char*)pLine, maxBufferSize-1, timeOutMS); 278 | if (resultIsOpen()) 293 | { 294 | serialPort->ReadBuffer(packet, packetSize, SERIALPORT_INTERNAL_TIMEOUT); 295 | } 296 | return 0; 297 | } 298 | 299 | -------------------------------------------------------------------------------- /SerialPort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows Serial Port for Windows API 3 | * 4 | * Copyright (c) 2016 Ondrej Sterba 5 | * 6 | * https://github.com/embedded-tools/WindowsSerialPort 7 | * 8 | * Permission to use, copy, modify, distribute and sell this software 9 | * and its documentation for any purpose is hereby granted without fee 10 | * provided that the above copyright notice appear in all copies and 11 | * that both that copyright notice and this permission notice appear 12 | * in supporting documentation. 13 | * It is provided "as is" without express or implied warranty. 14 | * 15 | */ 16 | 17 | #ifndef SERIALPORT___H 18 | #define SERIALPORT___H 19 | 20 | #include 21 | 22 | void SerialPort_Initialize(void); 23 | void SerialPort_Uninitialize(void); 24 | int SerialPort_GetMaxTimeout(); 25 | int SerialPort_GetDataReceivedHandler(); 26 | int SerialPort_GetDataSentHandler(); 27 | BOOL SerialPort_OpenAsync(int comPortNumber, 28 | int baudRate, 29 | void (*OnDataReceivedHandler)(const unsigned char* pData, int dataLength), 30 | void (*OnDataSentHandler)(void), 31 | int timeoutMS); 32 | BOOL SerialPort_Open(int comPortNumber, int baudRate, int timeoutMS); 33 | void SerialPort_Close(); 34 | BOOL SerialPort_IsOpen(); 35 | int SerialPort_ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS); 36 | int SerialPort_WriteBuffer(const unsigned char* pData, int dataLength); 37 | int SerialPort_WriteLine(char* pLine, BOOL addCRatEnd); 38 | int SerialPort_ReadLine(char* pLine, int maxBufferSize, int timeOutMS); 39 | 40 | 41 | 42 | 43 | #endif -------------------------------------------------------------------------------- /SerialPort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows Serial Port for Windows API 3 | * 4 | * Copyright (c) 2016 Ondrej Sterba 5 | * 6 | * https://github.com/embedded-tools/WindowsSerialPort 7 | * 8 | * Permission to use, copy, modify, distribute and sell this software 9 | * and its documentation for any purpose is hereby granted without fee 10 | * provided that the above copyright notice appear in all copies and 11 | * that both that copyright notice and this permission notice appear 12 | * in supporting documentation. 13 | * It is provided "as is" without express or implied warranty. 14 | * 15 | */ 16 | 17 | #ifndef SERIALPORT___H 18 | #define SERIALPORT___H 19 | 20 | #include 21 | 22 | class TSerialPort 23 | { 24 | private: 25 | HANDLE m_portHandle; 26 | HANDLE m_workingThread; 27 | DWORD m_workingThreadId; 28 | 29 | int m_timeoutMilliSeconds; 30 | int m_maxPacketLength; 31 | 32 | void (*m_OnDataReceivedHandler)(const unsigned char* pData, int dataLength); 33 | void (*m_OnDataSentHandler)(void); 34 | 35 | CRITICAL_SECTION m_criticalSectionRead; 36 | CRITICAL_SECTION m_criticalSectionWrite; 37 | 38 | int __ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS=-1); 39 | int __WriteBuffer(const unsigned char* pData, int dataLength); 40 | 41 | 42 | public: 43 | TSerialPort(); 44 | ~TSerialPort(); 45 | 46 | int GetMaxTimeout(); 47 | void* GetDataReceivedHandler(); 48 | void* GetDataSentHandler(); 49 | 50 | bool Open(int comPortNumber, int baudRate, int timeoutMS=1000); 51 | 52 | bool OpenAsync( int comPortNumber, int baudRate, 53 | void (*OnDataReceivedHandler)(const unsigned char* pData, int dataLength), 54 | void (*OnDataSentHandler)(void), 55 | int timeoutMS=100 56 | ); 57 | 58 | void Close(); 59 | bool IsOpen(); 60 | 61 | int ReadBuffer(unsigned char* pData, int dataLength, int timeOutMS=-1); 62 | int WriteBuffer(const unsigned char* pData, int dataLength); 63 | 64 | int ReadLine(char* pLine, int maxBufferSize, int timeOutMS=-1); 65 | int WriteLine(char* pLine, bool addCRatEnd=true); 66 | 67 | 68 | }; 69 | 70 | DWORD WINAPI SerialPort_WaitForData( LPVOID lpParam ); 71 | 72 | 73 | #endif --------------------------------------------------------------------------------