The serial port is extremely common in industrial applications. I use API to encapsulate synchronous and asynchronous serial classes, as well as an asynchronous serial class with monitoring threads; use simple and efficient, industrial strength, I am in BC, BCB, VC, BCBX, GCC By compilation, I believe enough to cope with most cases, but also inherit expansion, the following is briefly introduced, and then the home code (_COM.H); the hierarchy of the library: _base_com: virtual foundation class, basic interface, can expand itself Sub-class, synchronization application, suitable simple application, asynchronous application (overlap I / O), suitable for simple application, asynchronous application (overlapping I / O), suitable for more efficient applications, NT platforms, NT platforms, NT platforms, and Monitor threads, suitable for more complex applications, window notification messages and inheritance expansions; several issues: How to end threads from Waitcommevent (PCOM -> _ COM_HANDLE, & MAISK, & PCOM -> _ WAIT_O) API to exit to successfully end the thread: Scheme 1 : Setcommmask (_com_handle, 0); this method is contained in MSDN, when it is not fully effective in some cases, the reason is unknown; Solution 2: setEvent (_Wait_O.hevent); directly activate the event handle in the overlapping IO structure, absolutely effective I use two of this code; open more than 10 COM ports open number 10 or more ports in NT / 2000 - _COM_HANDLE = CreateFile ("COM10", generic_read | generic_write, 0, null, open_existing, file_attribute_normal | file_flag_overlapped, / / Overlapping I / O NULL); the prompt is wrong, so ok: _com_handle = CreateFile (".//com10" ,// corresponding is ///com10 generic_read | generic_write, 0, null, open_existing, file_attribute_normal | file_flag_overlapped , // overlap I / O NULL); Low efficiency issues in threads use setcommmask (pcom-> _ com_handle, ev_rxchar | ev_err) to monitor accept characters and error messages; once there is a character to activate WaitCommEvent usually do the following acceptance: if (! Waitcommevent (PCOM -> _ , & mask, & pcom -> _ wait_o) {if (getLastError () == Error_io_pending) {GetoverlappedResult (pcom -> _ coom_handle, & pcom -> _ wait_o, & length, true);}
IF (Mask & Ev_err) // == EV_ERR CLEARCOMMERROR (PCOM -> _ COM_HANDLE, & ERROR, & STAT); if (Mask & Ev_RxChar) / / == EV_RXCHAR {PCOM-> on_Receive (); // Receive character // or Send to window message} This frequent function calls or accepts the send message, the efficiency is low, I add the code of the scan buffer, when the number exceeds the set character number, the number of characters; if (Mask & Ev_RxChar) // == EV_RXCHAR {CLEARCOMMERROR (PCOM -> _ COM_HANDLE, & ERROR, & Stat); if (stat.cbinque> pcom -> _ notify_num) / // _ notify_num is set to set the number of characters pcom-> on_receive ();} Similar to streaming output I have compiled a simple way of writing serial ports, which can be similar to the stream that will output a simple data type output template
S << x; Write (s.Str (), s.pcount ());
Return * this;} can use _sync_com com1; com1.open (1, 9600); COM1 << "Then Random () 's return value is" << rand () << "./N"; COM1 .Close (); main interface class _base_com {bool open (int port); BOOL Open (int port, int baud_rate); BOOL Open (int port, char * set_str); // set_str: "9600, 8, N, 1 "BOOL set_State (int BaudRate, int Bytesize = 8, int parity = noparity, int stopbits = oneestopbit) // sets the built-in structure serial parameter: baud rate, stop bit BOOL set_state (char * set_str) BOOL IS_OPEN (); Handle get_handle (); Virtual Bool Open_Port () = 0; // Imported function Virtual Close ();} class _sync_com: public _base_com // Synchronization {Int Read (Char * BUF, INT BUF_SIZE); / / Automatically replenizes '/ 0', will use the buffer INT WRETE (CHAR * BUF, INT LEN); int Write (Char * buf);} class _asyn_com: public _base_com // asynchronous {Int Read (char * buf, int buf_size; // automatically replenizes '/ 0', will use the buffer Int Write (Char * buf, int LEN); int Write (char * buf);} class _thread_com: public_asyn_com // Thread {virtual void on_receive () // The call is called when the character is received, and the replacement is inherited {if (_notify_hwnd) PostMessage (_notify_hwnd, ON_COM_RECEIVE, WPARAM (_port), LPARAM (0)); else {if (_func) _func (_port);}} void set_hwnd (HWND hwnd); // set the window handle, the transmission ON_COM_RECEIVE WM_USER 618 void set_func (Void (* f) (int)); // Set the call function, window handle priority void set_notify_num (int Num); // Set send notification, accept the minimum value} Some application examples must first first #include "_com.h "First, open the serial port 1 synchronously write char str [] =" com_class test "; _sync_com com1; // Synchronize Com1.Open (1); // Equivalent to Com1.Open (1, 9600); COM1.Open (1, "9600, 8, N, 1"); for (int i = 0; i <100; i ) {SLEEP (500); com1.write (str); // can also com1.write (Str, Strlen (STR ));
} Com1.close (); Second, open the serial port 2 asynchronous reading char STR [100]; _ASYN_COM COM2; // Asynchronous COM2.Open (2); // Equivalent to Com2.open (2, 9600); COM2.Open 2, "9600, 8, n, 1"); if (! Com2._open ()) cout << "COM2 NOT OPEN, ERROR: << GetLastError () << endl; / * can also use the following use IF ( COUT << "COM2 NOT OPEN, ERROR:" << getLastError () << Endl; * / for (int i = 0; i <100; i ) {Sleep (500); if (COM2.READ (STR, 100)> 0) // Asynchronous reading, return to the reading character number cout << Str;} com2.close (); 3, extended application with monitoring thread serial class _COM_EX: PUBLIC THREAD_COM { Public: Virtual on_receive () {char STR [100]; if (STR, 100)> 0) // Asynchronous read, return reading character number cout << Str;}}; int main (int Argc, char * Argv []) {Try {char STR [100]; _com_ex com2; // Asynchronous extension COM2.Open (2); Sleep (10000); COM2.Close ();} catch (exception & e) {cout << e. What () << endl;} return 0;} 4 COMDLG) ON_WM_SYSCOMMAND () ON_WM_PAINT () ON_WM_QUERYDRAGICON () ON _WM_DESTROY () //}} AFX_MSG_MAP ON_MESSAGE (ON_COM_RECEIVE, On_Receive) END_MESSAGE_MAP () open the serial port, the window handle passed _thread_com com2; com2.open (2); com2.set_hwnd (ComDlg-> m_hWnd); processed message LRESULT ComDlg :: On_Receive (WPARAM WP, LPARAM LP) {Char Str [100]; COM2.READ (STR, 100);
CHAR COM_STR [10]; STRCPY (COM_STR, "COM"); LTOA ((long) WP, COM_STR 3, 10); // WPARAM Save port number
MessageBox (str, com_str, MB_OK); return 0;} C Builder class TForm1: public TForm {__published: // IDE-managed Components void __fastcall FormClose (TObject * Sender, TCloseAction & Action); void __fastcall FormCreate (TObject * Sender); private: // User declarations public: // User declarations void On_Receive (TMessage & Message); __fastcall TForm1 (TComponent * Owner); _thread_com com2; BEGIN_MESSAGE_MAP MESSAGE_HANDLER (ON_COM_RECEIVE, TMessage, On_Receive) END_MESSAGE_MAP (TForm)}; void __fastcall TForm1 :: FormClose (TpoBject * sender, tclosection & action) {com2.close ();} // ------------------------------- ------------------------------------------- void __fastcall tform1 :: formcreate (Tobject * sender) {com2.open (2); com2.set_hwnd (Handle);} // --------------------------- ------------------------------------------------ Void TFORM1 :: ON_Receive (TMESSAGE & Message) {char XX [20]; INT port = message.wparam; IF (COM2.READ (XX, 20)> 0) ShowMessage (XX);} Error and defects It is inevitable, welcome to letter criticism; wushaojian@21cn.com adhere to the source code _com.h / * serial base base library (Win32) Ver 0.1 compiler: BC 5; C Builder 4, 5, 6, x; vc 5 , 6; vc.net; gcc;
Class _base_com: Frequency base class basic serial port; class _sync_com: synchronous I / O serial port class; class _asyn_com: asynchronous I / O serial port class; class _thread_com: Asynchronous I / O secondary read monitoring thread Refrequent window message serial classes (can inherit The virtual function on_receive is used to read the operation); class _com: _thread_com is the same name
Copyright (c) 2004.8 llbird wushaojian@21cn.com//*Example: * / # iFNDef _com_h_ # define _com_h_
#pragma Warning (Disable: 4530) #pragma Warning (Disable: 4786) #pragma Warning (Disable: 4800)
#include
Class _base_com // Virtual base class basic serial port interface {protected:
Volatile int _port; // serial number volatile handle _com_handle; // serial handle char _com_str [20]; DCB _DCB; // baud rate, stop bit, etc. CommTimeouts _CO; // timeout time
Virtual bool open_port () = 0; void init () // Initialization {MEMSET (_COM_STR, 0, 20); MEMSET (& _ CO, 0, SIZEOF (_CO)); MEMSET (& _ DCB, 0, SIZEOF (_dcb)); _dcb .Dcblength = sizeof (_dcb); _com_handle = invalid_handle_value;} Virtual Bool Setup_port () {if (! Is_open ()) Return False;
IF (! setupcomm (_COM_HANDLE, 8192, 8192)) Return False; // Set the recommended buffer
if (! GetCommTimeouts (_com_handle, & _co)) return false; _co.ReadIntervalTimeout = 0xFFFFFFFF; _co.ReadTotalTimeoutMultiplier = 0; _co.ReadTotalTimeoutConstant = 0; _co.WriteTotalTimeoutMultiplier = 0; _co.WriteTotalTimeoutConstant = 2000; if (SetCommTimeouts (_com_handle,! & _) Return False; // Set timeout time
IF (! purgecomm (_pa_handle, purge_txabort | purge_rxabort | purge_txclear | purge_rxclear) Return False; / / Clear serial buffer
Return true;} inline void set_com_port (int port) {char p [12]; _Port = port; strcpy (_com_str, ".//com"); LTOA (_Port, p, 10); strcat (_COM_STR, P); } public: _base_com () {init ();} Virtual ~ _base_com () {close ();} // Setting serial parameters: baud rate, stop bit, etc. Support setting string "9600, 8, n, 1" bool set_state (char * set_str) {if (is_open ()) {if (! GetCommState (_com_handle, & _dcb)) return false; if return false (BuildCommDCB (set_str, & _dcb)!); return SetCommState (_com_handle, & _dcb) == True;} RETURN FALSE;} // Set built-in structure serial parameters: baud rate, stop bit BOOL set_state (int Baudrate, int Bytesize = 8, int parity = noparity, int stopbits = oneestopbit) {ix (is_open ()) { if (GetCommState (_com_handle, & _dcb)!) return false; _dcb.BaudRate = BaudRate; _dcb.ByteSize = ByteSize; _dcb.Parity = Parity; _dcb.StopBits = StopBits; return SetCommState (_com_handle, & _dcb) == TRUE;} return False;} // Open the serial outlet 9600, 8, n, 1 inline Bool Open (int port) {return open (port, 9600);} // Open the serial outlets BAUD_RATE, 8, N, 1 Inline Bool Open (int port, int baud_rate) {ix (port <1 || port> 1024) Return False; set_com_port (port);
IF (! Open_Port ()) Return False;
IF (! setup_port ()) Return False;
Return set_state;} // Open the serial port inline Bool Open (int port, char * set_str) {if (port <1 || port> 1024) Return False;
SET_COM_PORT (Port);
IF (! Open_Port ()) Return False;
IF (! setup_port ()) Return False;
RETURN SET_STATE (SET_STR);} Inline Bool Set_buf (INT IN, INT OUT) {RETURN IS_OPEN ()? setupcomm (__Handle, IN, OUT): false;} // Close Serial port inline Virtual Void Close () {if (IS_OPEN )) {CloseHandle (_com_handle); _com_handle = INVALID_HANDLE_VALUE;}} // port is determined to open or inline bool is_open () {return _com_handle = INVALID_HANDLE_VALUE;!} // get serial sentences Bing HANDLE get_handle () {return _com_handle;} operator Handle () {return _com_handle;}}; class _sync_com: public _base_com {protected: // Open serial port Virtual Bool Open_Port () {if (is_open ()) close ();
_COM_HANDLE = CREATEFILE (_COM_STR, Generic_Read | Generic_Write, 0, Null, Open_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); assert (is_open ()); return is_open (); // Detecting the serial port Successfully Open}
PUBLIC:
_Sync_COM () {} // Synchronize Read INT Read (Char * BUF, INT BUF_LEN) {if (! is_open ()) Return 0;
BUF [0] = '/ 0'; Comstat Stat; DWORD ERROR;
IF (Clearcommrror (_COM_HANDLE, & ERROR, & Stat) && error> 0) // Clear error {purgeComm (_COM_HANDLE, PURGE_RXABORT | PURGE_RXCLEAR); / * Clear the input buffer * / return 0;} Unsigned long r_len = 0;
BUF_LEN = Min (buf_len - 1, (int) stat.cbinque); if (! Readfile (_Com_Handle, BUF, BUF_LEN, & R_LEN, NULL)) r_len = 0; BUF [R_LEN] = '/ 0';
R_len;} // Synchronous Write Int Write (CHAR * BUF, INT BUF_LEN) {if (! is_open () ||! buf) Return 0; DWORD Error; if (Clearcomm_Handle, & Error, Null && Error> 0 ) // Clear the error purgeComm (_COM_HANDLE, PURGE_TXABORT | PURGE_TXCLEAR);
Unsigned long w_len = 0; if (! Writefile (_COM_HANDLE, BUF, BUF_LEN, & W_LEN, NULL) W_len = 0;
Return W_Len;} // Synchronous Write Inline Int Write (Assert (BUF); BUF); BUF, Strlen (BUF));} // Synchronous Write, Support Part Type Flow Direction Template
Return * this;}};
Class _asyn_com: public _base_com {protected:
Overlapped _ro, _wo; // overlap I / O
Virtual Bool Open_Port () {if (is_open ()) close ();
_com_handle = CreateFile (_com_str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I / O NULL); assert (is_open ()); return is_open (); // open detecting successful serial}
PUBLIC:
_asyn_com () {MEMSET (& _ Ro, 0, SizeOf (_RO)); MEMSET (& _ Wo, 0, Sizeof (_WO));
_ro.hEvent = CreateEvent (NULL, true, false, NULL); assert (_ro.hEvent = INVALID_HANDLE_VALUE!); _wo.hEvent = CreateEvent (NULL, true, false, NULL); assert (! _wo.hEvent = INVALID_HANDLE_VALUE); } Virtual ~ _ASYN_COM () {close ();
IF (_ro.hevent! = invalid_handle_value) closehandle (_ro.hevent);
IF (_wo.hevent! = invalid_handle_value) CloseHandle (_wo.hevent);} // Asynchronous Read int {ix (! is_wait = 20) {if (! is_open ()) Return 0;
BUF [0] = '/ 0';
COMSTAT Stat; DWORD ERROR;
IF (ClearcomMerror (_COM_HANDLE, & ERROR, & Stat) && error> 0) // Clear error {purgeComm (_COM_HANDLE, PURGE_RXABORT | PURGE_RXCLEAR); / * Clear Enter Buffer * / Return 0;}
If (! stat.cbinque) // buffer countless data return 0;
UNSIGNED long r_len = 0;
BUF_LEN = Min ((int) (buf_len - 1), (int) stat.cbinque);
If (! Readfile (_COM_HANDLE, BUF, BUF_LEN, & R_LEN, & _RO)) // 2000 ReadFile Always returns true {if (getLastError () == error_io_pending) // End asynchronous I / O {//waitforsingleObject(_ro.hevent, Time_wait); // Waiting for 20ms if (! getoverlappedresult (_Com_Handle, & _ro, & R_len, false) {if (getLastError ()! = error_io_incumplete) // Other error R_len = 0;}} else r_len = 0;} buf [r_len ] = '/ 0'; R_Len;} // Asynchronous Write INT WRETE (CHAR * BUF, INT BUF_LEN) {if (! Is_open ()) Return 0; DWORD ERROR; IF (ClearcomMerror (_COM_HANDLE, & Error, Null) &&&& Error> 0) // Clear error purgeComm (_COM_HANDLE, PURGE_TXABORT | PURGE_TXCLEAR); unsigned long w_len = 0, o_len = 0; if (! Writefile (_COM_HANDLE, BUF, BUF_LEN, & W_LEN, & _WO)) IF (getLastError ()! = ERROR_IO_PENDING) W_LEN = 0;
Return W_Len;} // Asynchronous Write Inline Int Write (Assert (BUF); Return Write (BUF, Strlen (BUF));} // Asynchronous Write, Support Part Type Flow Shutdown Template
S << x; Write (s.Str (), s.pcount ());
Return * this;}};
// When accepting the data sent to the window #define on_com_receive wm_user 618 // wparam port number
class _thread_com: public _asyn_com {protected: volatile HANDLE _thread_handle; // secondary thread volatile HWND _notify_hwnd; // notification window volatile long _notify_num; // number of bytes accepted (> _notify_num) sends a notification message volatile bool _run_flag; // thread running cycle Sign Void (* _func) (INT port);
Overlapped_wait_o; // Waitcommevent Use
// Thread receives the message automatic call, such as the window handle is valid, send a message, including the window number Virtual void on_receive () {i (_hwnd) Postmessage (_notify_hwnd, on_com_receive, wparam (_port), lpaam (0)); else {if (_func) _func (_port);}} // Open the serial port while opening the monitor thread Virtual Bool Open_Port () {if (_asyn_com :: pen_port ()) {_run_flag = true; dword id; _thread_handle = CreateThread (null, 0, ! com_thread, this, 0, & id); // secondary thread assert (_thread_handle); if (_ thread_handle) {CloseHandle (_com_handle); _com_handle = INVALID_HANDLE_VALUE;} else return true;} return false;} public: _thread_com () {_notify_num = 0; _NOTIFY_HWND = null; _thread_handle = null; _func = null;
Memset (& _ WAIT_O, 0, SIZEOF (_WAIT_O)); _Wait_O.hevent = CreateEvent (null, true, false, null); assert (_Wait_O.hevent! = INVALID_HANDLE_VALUE);} ~ _thread_com () {close ();
if (_wait_o.hEvent = INVALID_HANDLE_VALUE!) CloseHandle (_wait_o.hEvent);} // set the transmission notification, accepting characters minimum void set_notify_num (int num) {_notify_num = num;} int get_notify_num () {return _notify_num;} / / Send a message window handle inline void set_hwnd (hwnd hwnd) {_notify_hwnd = hwnd;} inline hwnd get_hwnd () {return _notify_hwnd;} inline void set_func (void (* f)) {_func = f;} // Close thread and serial port Virtual void close () {if (is_open ()) {_run_flag = false; setcommmask (_com_handle, 0); setEvent (_wait_o.hevent);
IF (WaitforsingleObject (_thread_handle, 100)! = Wait_Object_0) TerminateThread (_thread_handle, 0);
CloseHandle; CloseHandle (_thread_handle);
_thread_handle = NULL; _com_handle = INVALID_HANDLE_VALUE; ResetEvent (_wait_o.hEvent);}} / * * control secondary thread / thread handle // get HANDLE get_thread () {return _thread_handle;} // pause monitoring thread bool suspend () {return _thread_handle !? = NULL SuspendThread (_thread_handle) = 0xFFFFFFFF:! false;} // resume monitoring threads bool resume () {return _thread_handle = NULL ResumeThread (_thread_handle) = 0xFFFFFFFF:!?! false;} // rebuild monitor thread bool restart ( ) {if (when _thread_handle) / * presence only existing thread * / {_run_flag = false; SetCommMask (_com_handle, 0); SetEvent (_wait_o.hEvent); if (WaitForSingleObject (_thread_handle, 100)! = WAIT_OBJECT_0) TerminateThread (_thread_handle , 0);
CloseHandle;
_run_flag = true; _thread_handle = null;
DWORD ID; _THREAD_HANDLE = Createthread (Null, 0, COM_THREAD, THIS, 0, & ID); Return (_thread_handle! = Null); // Auxiliary thread} Return False;
Private: // Surveillance Thread Static DWORD WINAPI COM_THREAD (LPVOID PARA) {_thread_com * pcom = (_thread_com *) Para;
IF (! setcommmask (pcom -> _ com_handle, ev_rxchar | ev_err) Return 0;
COMSTAT Stat; DWORD ERROR;
For (DWord Length, Mask = 0; PCOM -> _ Run_Flag && Pcom-> is_open (); mask = 0) {if (! Waitcommevent (pcom -> _ com_handle, & mask, & pcom -> _ wait_o) {ified (getLastError () == Error_io_pending) {getoverlappedResult (pcom -> _ com_handle, & pcom -> _ wait_o, & length, true);}}
IF (Mask & Ev_err) // == EV_ERR CLEARCOMMERROR (PCOM -> _ COM_HANDLE, & ERROR, & Stat);
IF (Mask & Ev_RxChar) // == EV_RXCHAR {ClearcomMerror (PCOM -> _ COM_HANDLE, & ERROR, & Stat); if (stat.cbinque> pcom-> _ notify_num) pcom-> on_receive ();}} Return 0;}};
TYPEDEF _THREAD_COM _COM; // Name Simplified
#ENDIF / / _ COM_H_