2 // MHComPort Êîìïîíåíò (MHComPort Component)
3 // Àâòîð (Author): Æàðîâ Äìèòðèé (Zharov Dmitry) aka Ãýíäàëüô (Gandalf)
4 // Äàòà ñîçäàíèÿ (Create date): 4-ìàé(may)-2002
5 // Äàòà êîððåêöèè (Last correction Date): 15-ôåâ(feb)-2003
6 // Âåðñèÿ (Version): 1.12
7 // EMail: Gandalf@kol.mastak.ru
8 // WWW: http://kol.mastak.ru
9 // Áëàãîäàðíîñòè (Thanks):
14 // [+] Ïîääåðæêà D7 (D7 Support) [KOLnMCK]
17 // [+] Ïîääåðæêà D6 (D6 Support) <Thanks to Alexander Pravdin> [KOLnMCK]
20 // [!] Ñîîáùåíèÿ (Events) [KOLnMCK]
21 // [+] Ïðèâÿçêà ñîáûòèé (Assign Events) [MCK]
23 // Ñïèñîê äåë (To-Do list):
25 // 2. Îïòèìèçèðîâàòü (Optimize)
26 // 3. Ïîä÷èñòèòü (Clear Stuff)
28 // 5. Óäàëèòü RxOnBuf (Strip RxOnBuf)
29 // 6. Íîðìàëüíàÿ èêîíêà (Icon Correct)
34 KOL
, Windows
, Messages
;
39 TBaudRate
= (brCustom
, br110
, br300
, br600
, br1200
, br2400
, br4800
, br9600
, br14400
,
40 br19200
, br38400
, br56000
, br57600
, br115200
, br128000
, br256000
);
41 TStopBits
= (sbOneStopBit
, sbOne5StopBits
, sbTwoStopBits
);
42 TDataBits
= (dbFive
, dbSix
, dbSeven
, dbEight
);
43 TParityBits
= (prNone
, prOdd
, prEven
, prMark
, prSpace
);
44 TDTRFlowControl
= (dtrDisable
, dtrEnable
, dtrHandshake
);
45 TRTSFlowControl
= (rtsDisable
, rtsEnable
, rtsHandshake
, rtsToggle
);
46 TFlowControl
= (fcHardware
, fcSoftware
, fcNone
, fcCustom
);
47 TComEvent
= (evRxChar
, evTxEmpty
, evRxFlag
, evRing
, evBreak
, evCTS
, evDSR
,
48 evError
, evRLSD
, evRx80Full
);
49 TComEvents
= set of TComEvent
;
50 TComSignal
= (csCTS
, csDSR
, csRing
, csRLSD
);
51 TComSignals
= set of TComSignal
;
52 TComLedSignal
= (lsCTS
, lsDSR
, lsRLSD
, lsRing
, lsRx
, lsTx
);
53 TComError
= (ceFrame
, ceRxParity
, ceOverrun
, ceBreak
, ceIO
, ceMode
, ceRxOver
,
55 TComErrors
= set of TComError
;
56 TSyncMethod
= (smThreadSync
, smWindowSync
, smNone
);
57 TStoreType
= (stRegistry
, stIniFile
);
58 TStoredProp
= (spBasic
, spFlowControl
, spBuffer
, spTimeouts
, spParity
,
60 TStoredProps
= set of TStoredProp
;
61 TRxCharEvent
= procedure(Sender
: PObj
; Count
: Integer) of object;
62 TRxBufEvent
= procedure(Sender
: PObj
; Buf
:array of Byte;
63 Count
: Integer) of object;
64 TRxStrEvent
= procedure(Sender
: PObj
; Str
: string) of object;
65 TComErrorEvent
= procedure(Sender
: PObj
; Errors
: TComErrors
) of object;
66 TComSignalEvent
= procedure(Sender
: PObj
; OnOff
: Boolean) of object;
68 // types for asynchronous calls
69 TOperationKind
= (okWrite
, okRead
);
71 Overlapped
: TOverlapped
;
76 // TComPort component and asistant classes
79 PMHComPort
=^TMHComPort
;
80 TKOLMHComPort
= PMHComPort
;
82 PMHComBuffer
=^TMHComBuffer
;
83 TKOLMHComBuffer
=PMHComBuffer
;
85 PMHComParity
=^TMHComParity
;
86 TKOLMHComParity
=PMHComParity
;
88 PMHComFlowControl
=^TMHComFlowControl
;
89 TKOLMHComFlowControl
=PMHComFlowControl
;
91 PMHComTimeouts
=^TMHComTimeouts
;
92 TKOLMHComTimeouts
=PMHComTimeouts
;
94 PMHComThread
=^TMHComThread
;
95 TKOLMHComThread
=PMHComThread
;
97 TMHComThread
= object(TObj
)
104 procedure DispatchComMsg
;
106 procedure SendEvents
;
109 function Execute(Sender
:PThread
): integer; virtual;
110 destructor Destroy
; virtual;
113 TMHComTimeouts
= object(TObj
)
115 FComPort
: PMHComPort
;
116 FReadInterval
: Integer;
117 FReadTotalM
: Integer;
118 FReadTotalC
: Integer;
119 FWriteTotalM
: Integer;
120 FWriteTotalC
: Integer;
121 procedure SetComPort(const AComPort
: PMHComPort
);
122 procedure SetReadInterval(const Value
: Integer);
123 procedure SetReadTotalM(const Value
: Integer);
124 procedure SetReadTotalC(const Value
: Integer);
125 procedure SetWriteTotalM(const Value
: Integer);
126 procedure SetWriteTotalC(const Value
: Integer);
128 procedure AssignTo(Dest
: PObj
);
130 property ComPort
: PMHComPort read FComPort
;
131 property ReadInterval
: Integer read FReadInterval write SetReadInterval default
-1;
132 property ReadTotalMultiplier
: Integer read FReadTotalM write SetReadTotalM default
0;
133 property ReadTotalConstant
: Integer read FReadTotalC write SetReadTotalC default
0;
134 property WriteTotalMultiplier
: Integer
135 read FWriteTotalM write SetWriteTotalM default
100;
136 property WriteTotalConstant
: Integer
137 read FWriteTotalC write SetWriteTotalC default
1000;
140 TMHComFlowControl
= object(TObj
)
142 FComPort
: PMHComPort
;
143 FOutCTSFlow
: Boolean;
144 FOutDSRFlow
: Boolean;
145 FControlDTR
: TDTRFlowControl
;
146 FControlRTS
: TRTSFlowControl
;
147 FXonXoffOut
: Boolean;
149 FDSRSensitivity
: Boolean;
150 FTxContinueOnXoff
: Boolean;
153 procedure SetComPort(const AComPort
: PMHComPort
);
154 procedure SetOutCTSFlow(const Value
: Boolean);
155 procedure SetOutDSRFlow(const Value
: Boolean);
156 procedure SetControlDTR(const Value
: TDTRFlowControl
);
157 procedure SetControlRTS(const Value
: TRTSFlowControl
);
158 procedure SetXonXoffOut(const Value
: Boolean);
159 procedure SetXonXoffIn(const Value
: Boolean);
160 procedure SetDSRSensitivity(const Value
: Boolean);
161 procedure SetTxContinueOnXoff(const Value
: Boolean);
162 procedure SetXonChar(const Value
: Char);
163 procedure SetXoffChar(const Value
: Char);
164 procedure SetFlowControl(const Value
: TFlowControl
);
165 function GetFlowControl
: TFlowControl
;
167 procedure AssignTo(Dest
: PObj
);
169 property ComPort
: PMHComPort read FComPort
;
170 property FlowControl
: TFlowControl read GetFlowControl write SetFlowControl stored
False;
171 property OutCTSFlow
: Boolean read FOutCTSFlow write SetOutCTSFlow
;
172 property OutDSRFlow
: Boolean read FOutDSRFlow write SetOutDSRFlow
;
173 property ControlDTR
: TDTRFlowControl read FControlDTR write SetControlDTR
;
174 property ControlRTS
: TRTSFlowControl read FControlRTS write SetControlRTS
;
175 property XonXoffOut
: Boolean read FXonXoffOut write SetXonXoffOut
;
176 property XonXoffIn
: Boolean read FXonXoffIn write SetXonXoffIn
;
177 property DSRSensitivity
: Boolean
178 read FDSRSensitivity write SetDSRSensitivity default
False;
179 property TxContinueOnXoff
: Boolean
180 read FTxContinueOnXoff write SetTxContinueOnXoff default
False;
181 property XonChar
: Char read FXonChar write SetXonChar default
#17;
182 property XoffChar
: Char read FXoffChar write SetXoffChar default
#19;
185 TMHComParity
= object(TObj
)
187 FComPort
: PMHComPort
;
192 procedure SetComPort(const AComPort
: PMHComPort
);
193 procedure SetBits(const Value
: TParityBits
);
194 procedure SetCheck(const Value
: Boolean);
195 procedure SetReplace(const Value
: Boolean);
196 procedure SetReplaceChar(const Value
: Char);
198 procedure AssignTo(Dest
: PObj
);
200 property ComPort
: PMHComPort read FComPort
;
201 property Bits
: TParityBits read FBits write SetBits
;
202 property Check
: Boolean read FCheck write SetCheck default
False;
203 property Replace
: Boolean read FReplace write SetReplace default
False;
204 property ReplaceChar
: Char read FReplaceChar write SetReplaceChar default
#0;
207 TMHComBuffer
= object(TObj
)
209 FComPort
: PMHComPort
;
211 FOutputSize
: Integer;
212 procedure SetComPort(const AComPort
: PMHComPort
);
213 procedure SetInputSize(const Value
: Integer);
214 procedure SetOutputSize(const Value
: Integer);
216 procedure AssignTo(Dest
: PObj
);// override;
218 property ComPort
: PMHComPort read FComPort
;
219 property InputSize
: Integer read FInputSize write SetInputSize default
1024;
220 property OutputSize
: Integer read FOutputSize write SetOutputSize default
1024;
223 TMHComPort
= object(TObj
)
225 FEventThread
: PMHComThread
;
226 FThreadCreated
: Boolean;
229 FUpdateCount
: Integer;
231 FBaudRate
: TBaudRate
;
232 FCustomBaudRate
: Integer;
234 FStopBits
: TStopBits
;
235 FDataBits
: TDataBits
;
236 FDiscardNull
: Boolean;
239 FBuffer
: PMHComBuffer
;
240 FParity
: PMHComParity
;
241 FTimeouts
: PMHComTimeouts
;
242 FFlowControl
: PMHComFlowControl
;
243 FSyncMethod
: TSyncMethod
;
244 FStoredProps
: TStoredProps
;
245 FOnRxChar
: TRxCharEvent
;
246 FOnRxBuf
: TRxBufEvent
;
247 FOnTxEmpty
: TOnEvent
;
250 FOnCTSChange
: TComSignalEvent
;
251 FOnDSRChange
: TComSignalEvent
;
252 FOnRLSDChange
: TComSignalEvent
;
253 FOnError
: TComErrorEvent
;
255 FOnAfterOpen
: TOnEvent
;
256 FOnAfterClose
: TOnEvent
;
257 FOnBeforeOpen
: TOnEvent
;
258 FOnBeforeClose
: TOnEvent
;
259 FOnRx80Full
: TOnEvent
;
260 function GetTriggersOnRxChar
: Boolean;
261 procedure SetConnected(const Value
: Boolean);
262 procedure SetBaudRate(const Value
: TBaudRate
);
263 procedure SetCustomBaudRate(const Value
: Integer);
264 procedure SetPort(const Value
: TPort
);
265 procedure SetStopBits(const Value
: TStopBits
);
266 procedure SetDataBits(const Value
: TDataBits
);
267 procedure SetDiscardNull(const Value
: Boolean);
268 procedure SetEventChar(const Value
: Char);
269 procedure SetSyncMethod(const Value
: TSyncMethod
);
270 procedure SetParity(const Value
: PMHComParity
);
271 procedure SetTimeouts(const Value
: PMHComTimeouts
);
272 procedure SetBuffer(const Value
: PMHComBuffer
);
273 procedure SetFlowControl(const Value
: PMHComFlowControl
);
274 procedure CheckSignals(Open2
: Boolean);
275 procedure WindowMethod(var Message: TMessage
);
276 procedure CallAfterOpen
;
277 procedure CallAfterClose
;
278 procedure CallBeforeOpen
;
279 procedure CallBeforeClose
;
280 procedure CallRxChar
;
281 procedure CallTxEmpty
;
284 procedure CallRxFlag
;
285 procedure CallCTSChange
;
286 procedure CallDSRChange
;
288 procedure CallRLSDChange
;
289 procedure CallRx80Full
;
292 procedure DoAfterClose
;
293 procedure DoAfterOpen
;
294 procedure DoBeforeClose
;
295 procedure DoBeforeOpen
;
296 procedure DoRxChar(Count
: Integer);
297 procedure DoRxBuf(Buf
:array of Byte; Count
: Integer);
302 procedure DoCTSChange(OnOff
: Boolean);
303 procedure DoDSRChange(OnOff
: Boolean);
304 procedure DoError(Errors
: TComErrors
);
305 procedure DoRLSDChange(OnOff
: Boolean);
306 procedure DoRx80Full
;
307 procedure CreateHandle
; virtual;
308 procedure DestroyHandle
; virtual;
310 procedure ApplyTimeouts
;
311 procedure ApplyBuffer
;
312 procedure SetupComPort
; virtual;
314 destructor Destroy
; virtual;
315 procedure BeginUpdate
;
319 function InputCount
: Integer;
320 function OutputCount
: Integer;
321 function Signals
: TComSignals
;
322 function StateFlags
: TComStateFlags
;
323 procedure SetDTR(OnOff
: Boolean);
324 procedure SetRTS(OnOff
: Boolean);
325 procedure SetXonXoff(OnOff
: Boolean);
326 procedure SetBreak(OnOff
: Boolean);
327 procedure ClearBuffer(Input
, Output
: Boolean);
328 // function LastErrors: TComErrors;
329 function Write(const Buf
; Count
: Integer): Integer;
330 function WriteStr(Str
: string): Integer;
331 function Read(var Buf
; Count
: Integer): Integer;
332 function ReadStr(var Str
: string; Count
: Integer): Integer;
333 function WriteAsync(const Buf
; Count
: Integer;
334 var AsyncPtr
: PAsync
): Integer;
335 function WriteStrAsync(Str
: string; var AsyncPtr
: PAsync
): Integer;
336 function ReadAsync(var Buf
; Count
: Integer;
337 var AsyncPtr
: PAsync
): Integer;
338 function ReadStrAsync(var Str
: string; Count
: Integer;
339 var AsyncPtr
: PAsync
): Integer;
340 function WaitForAsync(var AsyncPtr
: PAsync
): Integer;
341 function IsAsyncCompleted(AsyncPtr
: PAsync
): Boolean;
342 procedure WaitForEvent(var Events2
: TComEvents
; Timeout
: Integer);
343 procedure AbortAllAsync
;
344 procedure TransmitChar(Ch
: Char);
345 // procedure RegisterLink(AComLink: PMHComLink);
346 // procedure UnRegisterLink(AComLink: PMHComLink);
347 property Handle
: THandle read FHandle
;
348 property TriggersOnRxChar
: Boolean read GetTriggersOnRxChar
;
349 property StoredProps
: TStoredProps read FStoredProps write FStoredProps
;
350 property Connected
: Boolean read FConnected write SetConnected default
False;
351 property BaudRate
: TBaudRate read FBaudRate write SetBaudRate
;
352 property CustomBaudRate
: Integer
353 read FCustomBaudRate write SetCustomBaudRate
;
354 property Port
: TPort read FPort write SetPort
;
355 property Parity
: PMHComParity read FParity write SetParity
;
356 property StopBits
: TStopBits read FStopBits write SetStopBits
;
357 property DataBits
: TDataBits read FDataBits write SetDataBits
;
358 property DiscardNull
: Boolean read FDiscardNull write SetDiscardNull default
False;
359 property EventChar
: Char read FEventChar write SetEventChar default
#0;
360 property Events
: TComEvents read FEvents write FEvents
;
361 property Buffer
: PMHComBuffer read FBuffer write SetBuffer
;
362 property FlowControl
: PMHComFlowControl read FFlowControl write SetFlowControl
;
363 property Timeouts
: PMHComTimeouts read FTimeouts write SetTimeouts
;
364 property SyncMethod
: TSyncMethod read FSyncMethod write SetSyncMethod default smThreadSync
;
365 property OnAfterOpen
: TOnEvent read FOnAfterOpen write FOnAfterOpen
;
366 property OnAfterClose
: TOnEvent read FOnAfterClose write FOnAfterClose
;
367 property OnBeforeOpen
: TOnEvent read FOnBeforeOpen write FOnBeforeOpen
;
368 property OnBeforeClose
: TOnEvent read FOnBeforeClose write FOnBeforeClose
;
369 property OnRxChar
: TRxCharEvent read FOnRxChar write FOnRxChar
;
370 property OnRxBuf
: TRxBufEvent read FOnRxBuf write FOnRxBuf
;
371 property OnTxEmpty
: TOnEvent read FOnTxEmpty write FOnTxEmpty
;
372 property OnBreak
: TOnEvent read FOnBreak write FOnBreak
;
373 property OnRing
: TOnEvent read FOnRing write FOnRing
;
374 property OnCTSChange
: TComSignalEvent read FOnCTSChange write FOnCTSChange
;
375 property OnDSRChange
: TComSignalEvent read FOnDSRChange write FOnDSRChange
;
376 property OnRLSDChange
: TComSignalEvent read FOnRLSDChange write FOnRLSDChange
;
377 property OnRxFlag
: TOnEvent read FOnRxFlag write FOnRxFlag
;
378 property OnError
: TComErrorEvent read FOnError write FOnError
;
379 property OnRx80Full
: TOnEvent read FOnRx80Full write FOnRx80Full
;
384 ComErrorMessages
: array[1..21] of string =
385 ('Unable to open com port',
386 'WriteFile function failed',
387 'ReadFile function failed',
388 'Invalid Async parameter',
389 'PurgeComm function failed',
390 'Unable to get async status',
391 'SetCommState function failed',
392 'SetCommTimeouts failed',
393 'SetupComm function failed',
394 'ClearCommError function failed',
395 'GetCommModemStatus function failed',
396 'EscapeCommFunction function failed',
397 'TransmitCommChar function failed',
398 'Cannot set SyncMethod while connected',
399 'EnumPorts function failed',
400 'Failed to store settings',
401 'Failed to load settings',
402 'Link (un)registration failed',
403 'Cannot change led state if ComPort is selected',
404 'Cannot wait for event if event thread is created',
405 'WaitForEvent method failed');
407 // auxilary constants used not defined in windows.pas
408 dcb_Binary
= $00000001;
409 dcb_Parity
= $00000002;
410 dcb_OutxCTSFlow
= $00000004;
411 dcb_OutxDSRFlow
= $00000008;
412 dcb_DTRControl
= $00000030;
413 dcb_DSRSensivity
= $00000040;
414 dcb_TxContinueOnXoff
= $00000080;
415 dcb_OutX
= $00000100;
417 dcb_ErrorChar
= $00000400;
418 dcb_Null
= $00000800;
419 dcb_RTSControl
= $00003000;
420 dcb_AbortOnError
= $00004000;
422 // com port window message
423 CM_COMPORT
= WM_USER
+ 1;
425 function NewMHComThread(AComPort
: PMHComPort
):PMHComThread
;
426 function NewMHComTimeouts
:PMHComTimeouts
;
427 function NewMHComFlowControl
:PMHComFlowControl
;
428 function NewMHComParity
:PMHComParity
;
429 function NewMHComBuffer
:PMHComBuffer
;
430 function NewMHComPort( Wnd
: PControl
):PMHComPort
;
434 {function WndProcMHFontDialog( Control: PControl; var Msg: TMsg; var Rslt: Integer ) : Boolean;
437 if Msg.message=HelpMessageIndex then
439 if Assigned( MHFontDialogNow.FOnHelp ) then
440 MHFontDialogNow.FOnHelp( @MHFontDialogNow);
447 function EventsToInt(const Events
: TComEvents
): Integer;
450 if evRxChar
in Events
then
451 Result
:= Result
or EV_RXCHAR
;
452 if evRxFlag
in Events
then
453 Result
:= Result
or EV_RXFLAG
;
454 if evTxEmpty
in Events
then
455 Result
:= Result
or EV_TXEMPTY
;
456 if evRing
in Events
then
457 Result
:= Result
or EV_RING
;
458 if evCTS
in Events
then
459 Result
:= Result
or EV_CTS
;
460 if evDSR
in Events
then
461 Result
:= Result
or EV_DSR
;
462 if evRLSD
in Events
then
463 Result
:= Result
or EV_RLSD
;
464 if evError
in Events
then
465 Result
:= Result
or EV_ERR
;
466 if evBreak
in Events
then
467 Result
:= Result
or EV_BREAK
;
468 if evRx80Full
in Events
then
469 Result
:= Result
or EV_RX80FULL
;
472 function IntToEvents(Mask
: Integer): TComEvents
;
475 if (EV_RXCHAR
and Mask
) <> 0 then
476 Result
:= Result
+ [evRxChar
];
477 if (EV_TXEMPTY
and Mask
) <> 0 then
478 Result
:= Result
+ [evTxEmpty
];
479 if (EV_BREAK
and Mask
) <> 0 then
480 Result
:= Result
+ [evBreak
];
481 if (EV_RING
and Mask
) <> 0 then
482 Result
:= Result
+ [evRing
];
483 if (EV_CTS
and Mask
) <> 0 then
484 Result
:= Result
+ [evCTS
];
485 if (EV_DSR
and Mask
) <> 0 then
486 Result
:= Result
+ [evDSR
];
487 if (EV_RXFLAG
and Mask
) <> 0 then
488 Result
:= Result
+ [evRxFlag
];
489 if (EV_RLSD
and Mask
) <> 0 then
490 Result
:= Result
+ [evRLSD
];
491 if (EV_ERR
and Mask
) <> 0 then
492 Result
:= Result
+ [evError
];
493 if (EV_RX80FULL
and Mask
) <> 0 then
494 Result
:= Result
+ [evRx80Full
];
498 procedure InitAsync(var AsyncPtr
: PAsync
);
503 FillChar(Overlapped
, SizeOf(TOverlapped
), 0);
504 Overlapped
.hEvent
:= CreateEvent(nil, True, True, nil);
508 procedure DoneAsync(var AsyncPtr
: PAsync
);
511 CloseHandle(Overlapped
.hEvent
);
516 function NewMHComThread(AComPort
: PMHComPort
):PMHComThread
;
519 Result
.FStopEvent
:= CreateEvent(nil, True, False, nil);
520 Result
.FComPort
:= AComPort
;
521 Result
.FThread
:=NewThreadEx(Result
.Execute
);
522 // select which events are monitored
523 SetCommMask(Result
.FComPort
.Handle
, EventsToInt(Result
.FComPort
.Events
));
530 destructor TMHComThread
.Destroy
;
539 {function MHComThreadExecute(Sender:PMHComThread):Integer;
541 EventHandles: array[0..1] of THandle;
542 Overlapped: TOverlapped;
543 Signaled, BytesTrans, Mask: DWORD;
545 FillChar(Overlapped, SizeOf(Overlapped), 0);
546 Overlapped.hEvent := CreateEvent(nil, True, True, nil);
547 EventHandles[0] := PMHComThread(Sender).FStopEvent;
548 EventHandles[1] := Overlapped.hEvent;
550 // wait for event to occur on serial port
551 WaitCommEvent(PMHComThread(Sender).FComPort.Handle, Mask, @Overlapped);
552 Signaled := WaitForMultipleObjects(2, @EventHandles, False, INFINITE);
553 // if event occurs, dispatch it
554 if (Signaled = WAIT_OBJECT_0 + 1)
555 and GetOverlappedResult(PMHComThread(Sender).FComPort.Handle, Overlapped, BytesTrans, False)
558 PMHComThread(Sender).FEvents := IntToEvents(Mask);
559 PMHComThread(Sender).DispatchComMsg;
561 until Signaled <> (WAIT_OBJECT_0 + 1);
563 SetCommMask(PMHComThread(Sender).FComPort.Handle, 0);
564 PurgeComm(PMHComThread(Sender).FComPort.Handle, PURGE_TXCLEAR or PURGE_RXCLEAR);
565 CloseHandle(Overlapped.hEvent);
566 CloseHandle(PMHComThread(Sender).FStopEvent);
570 function TMHComThread
.Execute(Sender
:PThread
):Integer;
572 EventHandles
: array[0..1] of THandle
;
573 Overlapped
: TOverlapped
;
574 Signaled
, BytesTrans
, Mask
: DWORD
;
576 FillChar(Overlapped
, SizeOf(Overlapped
), 0);
577 Overlapped
.hEvent
:= CreateEvent(nil, True, True, nil);
578 EventHandles
[0] := FStopEvent
;
579 EventHandles
[1] := Overlapped
.hEvent
;
581 // wait for event to occur on serial port
582 WaitCommEvent(FComPort
.Handle
, Mask
, @Overlapped
);
583 Signaled
:= WaitForMultipleObjects(2, @EventHandles
, False, INFINITE
);
584 // if event occurs, dispatch it
585 if (Signaled
= WAIT_OBJECT_0
+ 1)
586 and GetOverlappedResult(FComPort
.Handle
, Overlapped
, BytesTrans
, False)
589 FEvents
:= IntToEvents(Mask
);
592 until Signaled
<> (WAIT_OBJECT_0
+ 1);
594 SetCommMask(FComPort
.Handle
, 0);
595 PurgeComm(FComPort
.Handle
, PURGE_TXCLEAR
or PURGE_RXCLEAR
);
596 CloseHandle(Overlapped
.hEvent
);
597 CloseHandle(FStopEvent
);
601 procedure TMHComThread
.Stop
;
603 SetEvent(FStopEvent
);
608 procedure TMHComThread
.DispatchComMsg
;
611 case FComPort
.SyncMethod
of
612 smThreadSync
:{ Synchronize}(DoEvents
); // call events in main thread
613 smWindowSync
: SendEvents
; // call events in thread that opened the port
614 smNone
: DoEvents
; // call events inside monitoring thread
619 // send events to TCustomComPort component using window message
620 procedure TMHComThread
.SendEvents
;
622 if evRxChar
in FEvents
then
623 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_RXCHAR
, 0);
624 if evTxEmpty
in FEvents
then
625 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_TXEMPTY
, 0);
626 if evBreak
in FEvents
then
627 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_BREAK
, 0);
628 if evRing
in FEvents
then
629 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_RING
, 0);
630 if evCTS
in FEvents
then
631 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_CTS
, 0);
632 if evDSR
in FEvents
then
633 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_DSR
, 0);
634 if evRxFlag
in FEvents
then
635 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_RXFLAG
, 0);
636 if evRing
in FEvents
then
637 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_RLSD
, 0);
638 if evError
in FEvents
then
639 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_ERR
, 0);
640 if evRx80Full
in FEvents
then
641 SendMessage(FComPort
.FWindow
, CM_COMPORT
, EV_RX80FULL
, 0);
645 procedure TMHComThread
.DoEvents
;
647 if evRxChar
in FEvents
then
649 if evTxEmpty
in FEvents
then
650 FComPort
.CallTxEmpty
;
651 if evBreak
in FEvents
then
653 if evRing
in FEvents
then
655 if evCTS
in FEvents
then
656 FComPort
.CallCTSChange
;
657 if evDSR
in FEvents
then
658 FComPort
.CallDSRChange
;
659 if evRxFlag
in FEvents
then
661 if evRLSD
in FEvents
then
662 FComPort
.CallRLSDChange
;
663 if evError
in FEvents
then
665 if evRx80Full
in FEvents
then
666 FComPort
.CallRx80Full
;
670 function NewMHComTimeouts
:PMHComTimeouts
;
673 Result
.FReadInterval
:= -1;
674 Result
.FWriteTotalM
:= 100;
675 Result
.FWriteTotalC
:= 1000;
678 // copy properties to other class
679 procedure TMHComTimeouts
.AssignTo(Dest
: PObj
);
681 if TMHComTimeouts
.AncestorOfObject(Dest
) then
683 with PMHComTimeouts(Dest
)^ do
685 FReadInterval
:= Self
.ReadInterval
;
686 FReadTotalM
:= Self
.ReadTotalMultiplier
;
687 FReadTotalC
:= Self
.ReadTotalConstant
;
688 FWriteTotalM
:= Self
.WriteTotalMultiplier
;
689 FWriteTotalC
:= Self
.WriteTotalConstant
;
696 // select TCustomComPort to own this class
697 procedure TMHComTimeouts
.SetComPort(const AComPort
: PMHComPort
);
699 FComPort
:= AComPort
;
703 procedure TMHComTimeouts
.SetReadInterval(const Value
: Integer);
705 if Value
<> FReadInterval
then
707 FReadInterval
:= Value
;
708 // if possible, apply the changes
709 if FComPort
<> nil then
710 FComPort
.ApplyTimeouts
;
714 // set read total constant
715 procedure TMHComTimeouts
.SetReadTotalC(const Value
: Integer);
717 if Value
<> FReadTotalC
then
719 FReadTotalC
:= Value
;
720 if FComPort
<> nil then
721 FComPort
.ApplyTimeouts
;
725 // set read total multiplier
726 procedure TMHComTimeouts
.SetReadTotalM(const Value
: Integer);
728 if Value
<> FReadTotalM
then
730 FReadTotalM
:= Value
;
731 if FComPort
<> nil then
732 FComPort
.ApplyTimeouts
;
736 // set write total constant
737 procedure TMHComTimeouts
.SetWriteTotalC(const Value
: Integer);
739 if Value
<> FWriteTotalC
then
741 FWriteTotalC
:= Value
;
742 if FComPort
<> nil then
743 FComPort
.ApplyTimeouts
;
747 // set write total multiplier
748 procedure TMHComTimeouts
.SetWriteTotalM(const Value
: Integer);
750 if Value
<> FWriteTotalM
then
752 FWriteTotalM
:= Value
;
753 if FComPort
<> nil then
754 FComPort
.ApplyTimeouts
;
759 function NewMHComFlowControl
:PMHComFlowControl
;
762 Result
.FXonChar
:= #17;
763 Result
.FXoffChar
:= #19;
768 // copy properties to other class
769 procedure TMHComFlowControl
.AssignTo(Dest
: PObj
);
771 if TMHComFlowControl
.AncestorOfObject(Dest
) then
773 with PMHComFlowControl(Dest
)^ do
775 FOutCTSFlow
:= Self
.OutCTSFlow
;
776 FOutDSRFlow
:= Self
.OutDSRFlow
;
777 FControlDTR
:= Self
.ControlDTR
;
778 FControlRTS
:= Self
.ControlRTS
;
779 FXonXoffOut
:= Self
.XonXoffOut
;
780 FXonXoffIn
:= Self
.XonXoffIn
;
781 FTxContinueOnXoff
:= Self
.TxContinueOnXoff
;
782 FDSRSensitivity
:= Self
.DSRSensitivity
;
783 FXonChar
:= Self
.XonChar
;
784 FXoffChar
:= Self
.XoffChar
;
791 // select TCustomComPort to own this class
792 procedure TMHComFlowControl
.SetComPort(const AComPort
: PMHComPort
);
794 FComPort
:= AComPort
;
797 // set input flow control for DTR (data-terminal-ready)
798 procedure TMHComFlowControl
.SetControlDTR(const Value
: TDTRFlowControl
);
800 if Value
<> FControlDTR
then
802 FControlDTR
:= Value
;
803 if FComPort
<> nil then
808 // set input flow control for RTS (request-to-send)
809 procedure TMHComFlowControl
.SetControlRTS(const Value
: TRTSFlowControl
);
811 if Value
<> FControlRTS
then
813 FControlRTS
:= Value
;
814 if FComPort
<> nil then
819 // set ouput flow control for CTS (clear-to-send)
820 procedure TMHComFlowControl
.SetOutCTSFlow(const Value
: Boolean);
822 if Value
<> FOutCTSFlow
then
824 FOutCTSFlow
:= Value
;
825 if FComPort
<> nil then
830 // set output flow control for DSR (data-set-ready)
831 procedure TMHComFlowControl
.SetOutDSRFlow(const Value
: Boolean);
833 if Value
<> FOutDSRFlow
then
835 FOutDSRFlow
:= Value
;
836 if FComPort
<> nil then
841 // set software input flow control
842 procedure TMHComFlowControl
.SetXonXoffIn(const Value
: Boolean);
844 if Value
<> FXonXoffIn
then
847 if FComPort
<> nil then
852 // set software ouput flow control
853 procedure TMHComFlowControl
.SetXonXoffOut(const Value
: Boolean);
855 if Value
<> FXonXoffOut
then
857 FXonXoffOut
:= Value
;
858 if FComPort
<> nil then
863 // set DSR sensitivity
864 procedure TMHComFlowControl
.SetDSRSensitivity(const Value
: Boolean);
866 if Value
<> FDSRSensitivity
then
868 FDSRSensitivity
:= Value
;
869 if FComPort
<> nil then
874 // set transfer continue when Xoff is sent
875 procedure TMHComFlowControl
.SetTxContinueOnXoff(const Value
: Boolean);
877 if Value
<> FTxContinueOnXoff
then
879 FTxContinueOnXoff
:= Value
;
880 if FComPort
<> nil then
886 procedure TMHComFlowControl
.SetXonChar(const Value
: Char);
888 if Value
<> FXonChar
then
891 if FComPort
<> nil then
897 procedure TMHComFlowControl
.SetXoffChar(const Value
: Char);
899 if Value
<> FXoffChar
then
902 if FComPort
<> nil then
907 // get common flow control
908 function TMHComFlowControl
.GetFlowControl
: TFlowControl
;
910 if (FControlRTS
= rtsHandshake
) and (FOutCTSFlow
)
911 and (not FXonXoffIn
) and (not FXonXoffOut
)
915 if (FControlRTS
= rtsDisable
) and (not FOutCTSFlow
)
916 and (FXonXoffIn
) and (FXonXoffOut
)
920 if (FControlRTS
= rtsDisable
) and (not FOutCTSFlow
)
921 and (not FXonXoffIn
) and (not FXonXoffOut
)
928 // set common flow control
929 procedure TMHComFlowControl
.SetFlowControl(const Value
: TFlowControl
);
931 if Value
<> fcCustom
then
933 FControlRTS
:= rtsDisable
;
934 FOutCTSFlow
:= False;
936 FXonXoffOut
:= False;
940 FControlRTS
:= rtsHandshake
;
950 if FComPort
<> nil then
955 function NewMHComParity
:PMHComParity
;
958 Result
.FBits
:= prNone
;
961 // copy properties to other class
962 procedure TMHComParity
.AssignTo(Dest
:PObj
);
964 if TMHComParity
.AncestorOfObject(Dest
) then
966 with PMHComParity(Dest
)^ do
969 FCheck
:= Self
.Check
;
970 FReplace
:= Self
.Replace
;
971 FReplaceChar
:= Self
.ReplaceChar
;
978 // select TCustomComPort to own this class
979 procedure TMHComParity
.SetComPort(const AComPort
: PMHComPort
);
981 FComPort
:= AComPort
;
985 procedure TMHComParity
.SetBits(const Value
: TParityBits
);
987 if Value
<> FBits
then
990 if FComPort
<> nil then
996 procedure TMHComParity
.SetCheck(const Value
: Boolean);
998 if Value
<> FCheck
then
1001 if FComPort
<> nil then
1006 // set replace on parity error
1007 procedure TMHComParity
.SetReplace(const Value
: Boolean);
1009 if Value
<> FReplace
then
1012 if FComPort
<> nil then
1018 procedure TMHComParity
.SetReplaceChar(const Value
: Char);
1020 if Value
<> FReplaceChar
then
1022 FReplaceChar
:= Value
;
1023 if FComPort
<> nil then
1029 function NewMHComBuffer
:PMHComBuffer
;
1031 New(Result
, Create
);
1032 Result
.FInputSize
:= 1024;
1033 Result
.FOutputSize
:= 1024;
1036 // copy properties to other class
1037 procedure TMHComBuffer
.AssignTo(Dest
: PObj
);
1039 if TMHComBuffer
.AncestorOfObject(Dest
) then
1041 with PMHComBuffer(Dest
)^ do
1043 FOutputSize
:= Self
.OutputSize
;
1044 FInputSize
:= Self
.InputSize
;
1051 // select TCustomComPort to own this class
1052 procedure TMHComBuffer
.SetComPort(const AComPort
: PMHComPort
);
1054 FComPort
:= AComPort
;
1058 procedure TMHComBuffer
.SetInputSize(const Value
: Integer);
1060 if Value
<> FInputSize
then
1062 FInputSize
:= Value
;
1063 if (FInputSize
mod 2) = 1 then
1065 if FComPort
<> nil then
1066 FComPort
.ApplyBuffer
;
1071 procedure TMHComBuffer
.SetOutputSize(const Value
: Integer);
1073 if Value
<> FOutputSize
then
1075 FOutputSize
:= Value
;
1076 if (FOutputSize
mod 2) = 1 then
1078 if FComPort
<> nil then
1079 FComPort
.ApplyBuffer
;
1083 function NewMHComPort(Wnd
: PControl
):PMHComPort
;
1085 New(Result
, Create
);
1086 // Result.FLinks := TList.Create;
1087 Result
.FBaudRate
:= br9600
;
1088 Result
.FCustomBaudRate
:= 9600;
1089 Result
.FPort
:= 'COM1';
1090 Result
.FStopBits
:= sbOneStopBit
;
1091 Result
.FDataBits
:= dbEight
;
1092 Result
.FEvents
:= [evRxChar
, evTxEmpty
, evRxFlag
, evRing
, evBreak
, evCTS
, evDSR
, evError
, evRLSD
, evRx80Full
];
1093 Result
.FHandle
:= INVALID_HANDLE_VALUE
;
1094 Result
.FStoredProps
:= [spBasic
];
1095 Result
.FParity
:= NewMHComParity
;
1096 Result
.FParity
.SetComPort(Result
);
1097 Result
.FFlowControl
:= NewMHComFlowControl
;
1098 Result
.FFlowControl
.SetComPort(Result
);
1099 Result
.FTimeouts
:= NewMHComTimeouts
;
1100 Result
.FTimeouts
.SetComPort(Result
);
1101 Result
.FBuffer
:= NewMHComBuffer
;
1102 Result
.FBuffer
.SetComPort(Result
);
1107 // destroy component
1108 destructor TMHComPort
.Destroy
;
1119 // create handle to serial port
1120 procedure TMHComPort
.CreateHandle
;
1124 pc
:=PChar('\\.\'+FPort
);
1125 FHandle
:= CreateFile(pc
,//PChar('\\.\' + FPort),
1126 GENERIC_READ
or GENERIC_WRITE
,
1130 FILE_FLAG_OVERLAPPED
,
1134 //if FHandle = INVALID_HANDLE_VALUE then
1135 // ShowMessage('!!!');
1136 { raise EComPort.Create(CError_OpenFailed, GetLastError);
1140 // destroy serial port handle
1141 procedure TMHComPort
.DestroyHandle
;
1143 if FHandle
<> INVALID_HANDLE_VALUE
then
1144 CloseHandle(FHandle
);
1147 procedure TMHComPort
.Loaded
;
1149 // inherited Loaded;
1150 // open port if Connected is True at design-time
1151 if (FConnected
) then
1153 FConnected
:= False;
1161 // on E:Exception do
1162 // Application.ShowException(E);
1168 // call events which have been dispatch using window message
1169 procedure TMHComPort
.WindowMethod(var Message: TMessage
);
1172 if Msg
= CM_COMPORT
then
1175 EV_RXCHAR
: CallRxChar
;
1176 EV_TXEMPTY
: CallTxEmpty
;
1177 EV_BREAK
: CallBreak
;
1179 EV_CTS
: CallCTSChange
;
1180 EV_DSR
: CallDSRChange
;
1181 EV_RXFLAG
: CallRxFlag
;
1182 EV_RLSD
: CallRLSDChange
;
1184 EV_RX80FULL
: CallRx80Full
;
1188 Result
:= DefWindowProc(FWindow
, Msg
, wParam
, lParam
);
1191 // prevent from applying changes at runtime
1192 procedure TMHComPort
.BeginUpdate
;
1194 FUpdateCount
:= FUpdateCount
+ 1;
1197 // apply the changes made since BeginUpdate call
1198 procedure TMHComPort
.EndUpdate
;
1200 if FUpdateCount
> 0 then
1202 FUpdateCount
:= FUpdateCount
- 1;
1203 if FUpdateCount
= 0 then
1209 procedure TMHComPort
.Open
;
1211 // if already connected, do nothing
1212 if (not FConnected
) then
1222 // error occured during initialization, destroy handle
1224 FConnected
:= False;
1227 // if at least one event is set, create special thread to monitor port
1228 if (FEvents
= []) then
1229 FThreadCreated
:= False
1232 // if (FSyncMethod = smWindowSync) then
1233 // FWindow := AllocateHWnd(WindowMethod);
1234 FEventThread
:= NewMHComThread(@Self
);
1235 // FEventThread.OnExecute:=TOnThreadExecute(MHComThreadExecute(FEventThread));
1236 FEventThread
.FThread
.Resume
;
1237 //TComThread.Create(Self);
1238 FThreadCreated
:= True;
1240 // port is succesfully opened, do any additional initialization
1246 procedure TMHComPort
.Close
;
1248 // if already closed, do nothing
1249 if (FConnected
) then
1252 // abort all pending operations
1254 // stop monitoring for events
1255 if FThreadCreated
then
1258 FThreadCreated
:= False;
1259 // if FSyncMethod = smWindowSync then
1260 // DeallocateHWnd(FWindow);
1264 FConnected
:= False;
1265 // port is closed, do any additional finalization
1270 // apply port properties
1271 procedure TMHComPort
.ApplyDCB
;
1273 CParityBits
: array[TParityBits
] of Integer =
1274 (NOPARITY
, ODDPARITY
, EVENPARITY
, MARKPARITY
, SPACEPARITY
);
1275 CStopBits
: array[TStopBits
] of Integer =
1276 (ONESTOPBIT
, ONE5STOPBITS
, TWOSTOPBITS
);
1277 CBaudRate
: array[TBaudRate
] of Integer =
1278 (0, CBR_110
, CBR_300
, CBR_600
, CBR_1200
, CBR_2400
, CBR_4800
, CBR_9600
,
1279 CBR_14400
, CBR_19200
, CBR_38400
, CBR_56000
, CBR_57600
, CBR_115200
,
1280 CBR_128000
, CBR_256000
);
1281 CDataBits
: array[TDataBits
] of Integer = (5, 6, 7, 8);
1282 CControlRTS
: array[TRTSFlowControl
] of Integer =
1283 (RTS_CONTROL_DISABLE
shl 12,
1284 RTS_CONTROL_ENABLE
shl 12,
1285 RTS_CONTROL_HANDSHAKE
shl 12,
1286 RTS_CONTROL_TOGGLE
shl 12);
1287 CControlDTR
: array[TDTRFlowControl
] of Integer =
1288 (DTR_CONTROL_DISABLE
shl 4,
1289 DTR_CONTROL_ENABLE
shl 4,
1290 DTR_CONTROL_HANDSHAKE
shl 4);
1296 // if not connected or inside BeginUpdate/EndUpdate block, do nothing
1297 if (FConnected
) and (FUpdateCount
= 0) then
1299 DCB
.DCBlength
:= SizeOf(TDCB
);
1300 DCB
.XonLim
:= FBuffer
.InputSize
div 4;
1301 DCB
.XoffLim
:= DCB
.XonLim
;
1302 DCB
.EvtChar
:= Char(FEventChar
);
1304 DCB
.Flags
:= dcb_Binary
;
1305 if FDiscardNull
then
1306 DCB
.Flags
:= DCB
.Flags
or dcb_Null
;
1308 with FFlowControl
^ do
1310 DCB
.XonChar
:= XonChar
;
1311 DCB
.XoffChar
:= XoffChar
;
1313 DCB
.Flags
:= DCB
.Flags
or dcb_OutxCTSFlow
;
1315 DCB
.Flags
:= DCB
.Flags
or dcb_OutxDSRFlow
;
1316 DCB
.Flags
:= DCB
.Flags
or CControlDTR
[ControlDTR
]
1317 or CControlRTS
[ControlRTS
];
1319 DCB
.Flags
:= DCB
.Flags
or dcb_OutX
;
1321 DCB
.Flags
:= DCB
.Flags
or dcb_InX
;
1322 if DSRSensitivity
then
1323 DCB
.Flags
:= DCB
.Flags
or dcb_DSRSensivity
;
1324 if TxContinueOnXoff
then
1325 DCB
.Flags
:= DCB
.Flags
or dcb_TxContinueOnXoff
;
1328 DCB
.Parity
:= CParityBits
[FParity
.Bits
];
1329 DCB
.StopBits
:= CStopBits
[FStopBits
];
1330 if FBaudRate
<> brCustom
then
1331 DCB
.BaudRate
:= CBaudRate
[FBaudRate
]
1333 DCB
.BaudRate
:= FCustomBaudRate
;
1334 DCB
.ByteSize
:= CDataBits
[FDataBits
];
1336 if FParity
.Check
then
1338 DCB
.Flags
:= DCB
.Flags
or dcb_Parity
;
1339 if FParity
.Replace
then
1341 DCB
.Flags
:= DCB
.Flags
or dcb_ErrorChar
;
1342 DCB
.ErrorChar
:= Char(FParity
.ReplaceChar
);
1348 SetCommState(FHandle
, DCB
);// then
1349 // ShowMessage('!@!!');
1350 // raise EComPort.Create(CError_SetStateFailed, GetLastError);
1355 // apply timeout properties
1356 procedure TMHComPort
.ApplyTimeouts
;
1358 Timeouts2
: TCommTimeouts
;
1360 function GetTOValue(const Value
: Integer): DWORD
;
1369 // if not connected or inside BeginUpdate/EndUpdate block, do nothing
1370 if (FConnected
) and (FUpdateCount
= 0) then
1372 Timeouts2
.ReadIntervalTimeout
:= GetTOValue(FTimeouts
.ReadInterval
);
1373 Timeouts2
.ReadTotalTimeoutMultiplier
:= GetTOValue(FTimeouts
.ReadTotalMultiplier
);
1374 Timeouts2
.ReadTotalTimeoutConstant
:= GetTOValue(FTimeouts
.ReadTotalConstant
);
1375 Timeouts2
.WriteTotalTimeoutMultiplier
:= GetTOValue(FTimeouts
.WriteTotalMultiplier
);
1376 Timeouts2
.WriteTotalTimeoutConstant
:= GetTOValue(FTimeouts
.WriteTotalConstant
);
1381 SetCommTimeouts(FHandle
, Timeouts2
);
1383 raise EComPort.Create(CError_TimeoutsFailed, GetLastError);
1389 procedure TMHComPort
.ApplyBuffer
;
1391 // if not connected or inside BeginUpdate/EndUpdate block, do nothing
1393 if (FConnected
) and (FUpdateCount
= 0) then
1396 SetupComm(FHandle
, FBuffer
.InputSize
, FBuffer
.OutputSize
);
1398 raise EComPort.Create(CError_SetupComFailed, GetLastError);
1403 procedure TMHComPort
.SetupComPort
;
1410 // get number of bytes in input buffer
1411 function TMHComPort
.InputCount
: Integer;
1418 ClearCommError(FHandle
, Errors
, @ComStat
);
1420 raise EComPort.Create(CError_ClearComFailed, GetLastError);
1422 Result
:= ComStat
.cbInQue
;
1425 // get number of bytes in output buffer
1426 function TMHComPort
.OutputCount
: Integer;
1433 ClearCommError(FHandle
, Errors
, @ComStat
);
1435 // raise EComPort.Create(CError_ClearComFailed, GetLastError);
1437 Result
:= ComStat
.cbOutQue
;
1440 // get signals which are in high state
1441 function TMHComPort
.Signals
: TComSignals
;
1447 GetCommModemStatus(FHandle
, Status
);
1449 // raise EComPort.Create(CError_ModemStatFailed, GetLastError);
1453 if (MS_CTS_ON
and Status
) <> 0 then
1454 Result
:= Result
+ [csCTS
];
1455 if (MS_DSR_ON
and Status
) <> 0 then
1456 Result
:= Result
+ [csDSR
];
1457 if (MS_RING_ON
and Status
) <> 0 then
1458 Result
:= Result
+ [csRing
];
1459 if (MS_RLSD_ON
and Status
) <> 0 then
1460 Result
:= Result
+ [csRLSD
];
1463 // get port state flags
1464 function TMHComPort
.StateFlags
: TComStateFlags
;
1471 ClearCommError(FHandle
, Errors
, @ComStat
);
1473 raise EComPort.Create(CError_ClearComFailed, GetLastError);
1475 Result
:= ComStat
.Flags
;
1478 // set hardware line break
1479 procedure TMHComPort
.SetBreak(OnOff
: Boolean);
1484 Act
:= Windows
.SETBREAK
1486 Act
:= Windows
.CLRBREAK
;
1490 EscapeCommFunction(FHandle
, Act
);
1492 raise EComPort.Create(CError_EscapeComFailed, GetLastError);
1497 procedure TMHComPort
.SetDTR(OnOff
: Boolean);
1502 Act
:= Windows
.SETDTR
1504 Act
:= Windows
.CLRDTR
;
1508 EscapeCommFunction(FHandle
, Act
)
1510 raise EComPort.Create(CError_EscapeComFailed, GetLastError);
1515 procedure TMHComPort
.SetRTS(OnOff
: Boolean);
1520 Act
:= Windows
.SETRTS
1522 Act
:= Windows
.CLRRTS
;
1526 EscapeCommFunction(FHandle
, Act
);
1528 raise EComPort.Create(CError_EscapeComFailed, GetLastError);
1532 // set XonXoff state
1533 procedure TMHComPort
.SetXonXoff(OnOff
: Boolean);
1538 Act
:= Windows
.SETXON
1540 Act
:= Windows
.SETXOFF
;
1544 EscapeCommFunction(FHandle
, Act
);
1546 raise EComPort.Create(CError_EscapeComFailed, GetLastError);
1550 // clear input and/or output buffer
1551 procedure TMHComPort
.ClearBuffer(Input
, Output
: Boolean);
1557 Flag
:= PURGE_RXCLEAR
;
1559 Flag
:= Flag
or PURGE_TXCLEAR
;
1563 PurgeComm(FHandle
, Flag
);
1565 raise EComPort.Create(CError_PurgeFailed, GetLastError);
1569 // return last errors on port
1570 {function TMHComPort.LastErrors: TComErrors;
1575 if not ClearCommError(FHandle, Errors, @ComStat) then
1576 raise EComPort.Create(CError_ClearComFailed, GetLastError);
1579 if (CE_FRAME and Errors) <> 0 then
1580 Result := Result + [ceFrame];
1581 if ((CE_RXPARITY and Errors) <> 0) and FParity.Check then // get around a bug
1582 Result := Result + [ceRxParity];
1583 if (CE_OVERRUN and Errors) <> 0 then
1584 Result := Result + [ceOverrun];
1585 if (CE_RXOVER and Errors) <> 0 then
1586 Result := Result + [ceRxOver];
1587 if (CE_TXFULL and Errors) <> 0 then
1588 Result := Result + [ceTxFull];
1589 if (CE_BREAK and Errors) <> 0 then
1590 Result := Result + [ceBreak];
1591 if (CE_IOE and Errors) <> 0 then
1592 Result := Result + [ceIO];
1593 if (CE_MODE and Errors) <> 0 then
1594 Result := Result + [ceMode];
1597 // perform asynchronous write operation
1598 function TMHComPort
.WriteAsync(const Buf
; Count
: Integer; var AsyncPtr
: PAsync
): Integer;
1603 AsyncPtr
^.Kind
:= okWrite
;
1605 Success
:= WriteFile(FHandle
, Buf
, Count
, BytesTrans
, @AsyncPtr
^.Overlapped
)
1606 or (GetLastError
= ERROR_IO_PENDING
);
1610 raise EComPort.Create(CError_WriteFailed, GetLastError);
1613 // SendSignals(lsTx, True);
1614 Result
:= BytesTrans
;
1617 // perform synchronous write operation
1618 function TMHComPort
.Write(const Buf
; Count
: Integer): Integer;
1622 InitAsync(AsyncPtr
);
1624 WriteAsync(Buf
, Count
, AsyncPtr
);
1625 Result
:= WaitForAsync(AsyncPtr
);
1627 DoneAsync(AsyncPtr
);
1631 // perform asynchronous write operation
1632 function TMHComPort
.WriteStrAsync(Str
: string; var AsyncPtr
: PAsync
): Integer;
1637 AsyncPtr
^.Kind
:= okWrite
;
1639 Success
:= WriteFile(FHandle
, Str
[1], Length(Str
), BytesTrans
, @AsyncPtr
^.Overlapped
)
1640 or (GetLastError
= ERROR_IO_PENDING
);
1644 raise EComPort.Create(CError_WriteFailed, GetLastError);
1647 // SendSignals(lsTx, True);
1648 Result
:= BytesTrans
;
1651 // perform synchronous write operation
1652 function TMHComPort
.WriteStr(Str
: string): Integer;
1656 InitAsync(AsyncPtr
);
1658 WriteStrAsync(Str
, AsyncPtr
);
1659 Result
:= WaitForAsync(AsyncPtr
);
1661 DoneAsync(AsyncPtr
);
1665 // perform asynchronous read operation
1666 function TMHComPort
.ReadAsync(var Buf
; Count
: Integer; var AsyncPtr
: PAsync
): Integer;
1671 AsyncPtr
^.Kind
:= okRead
;
1673 Success
:= ReadFile(FHandle
, Buf
, Count
, BytesTrans
, @AsyncPtr
^.Overlapped
)
1674 or (GetLastError
= ERROR_IO_PENDING
);
1678 raise EComPort.Create(CError_ReadFailed, GetLastError);
1681 Result
:= BytesTrans
;
1684 // perform synchronous read operation
1685 function TMHComPort
.Read(var Buf
; Count
: Integer): Integer;
1689 InitAsync(AsyncPtr
);
1691 ReadAsync(Buf
, Count
, AsyncPtr
);
1692 Result
:= WaitForAsync(AsyncPtr
);
1694 DoneAsync(AsyncPtr
);
1698 // perform asynchronous read operation
1699 function TMHComPort
.ReadStrAsync(var Str
: string; Count
: Integer; var AsyncPtr
: PAsync
): Integer;
1704 AsyncPtr
^.Kind
:= okRead
;
1705 SetLength(Str
, Count
);
1707 Success
:= ReadFile(FHandle
, Str
[1], Count
, BytesTrans
, @AsyncPtr
^.Overlapped
)
1708 or (GetLastError
= ERROR_IO_PENDING
);
1712 raise EComPort.Create(CError_ReadFailed, GetLastError);
1715 Result
:= BytesTrans
;
1718 // perform synchronous read operation
1719 function TMHComPort
.ReadStr(var Str
: string; Count
: Integer): Integer;
1723 InitAsync(AsyncPtr
);
1725 ReadStrAsync(Str
, Count
, AsyncPtr
);
1726 Result
:= WaitForAsync(AsyncPtr
);
1727 SetLength(Str
, Result
);
1729 DoneAsync(AsyncPtr
);
1733 function ErrorCode(AsyncPtr
: PAsync
): Integer;
1736 { case AsyncPtr^.Kind of
1737 okWrite: Result := CError_WriteFailed;
1738 okRead: Result := CError_ReadFailed;
1742 // wait for asynchronous operation to end
1743 function TMHComPort
.WaitForAsync(var AsyncPtr
: PAsync
): Integer;
1745 BytesTrans
, Signaled
: DWORD
;
1749 if AsyncPtr = nil then
1750 raise EComPort.CreateNoWinCode(CError_InvalidAsync);
1753 Signaled
:= WaitForSingleObject(AsyncPtr
^.Overlapped
.hEvent
, INFINITE
);
1754 Success
:= (Signaled
= WAIT_OBJECT_0
) and
1755 (GetOverlappedResult(FHandle
, AsyncPtr
^.Overlapped
, BytesTrans
, False));
1757 // if (AsyncPtr^.Kind = okRead) and (InputCount = 0) then
1758 // SendSignals(lsRx, False);
1762 raise EComPort.Create(ErrorCode(AsyncPtr), GetLastError);
1765 Result
:= BytesTrans
;
1768 // abort all asynchronous operations
1769 procedure TMHComPort
.AbortAllAsync
;
1773 PurgeComm(FHandle
, PURGE_TXABORT
or PURGE_RXABORT
);
1775 raise EComPort.Create(CError_PurgeFailed, GetLastError);
1779 // detect whether asynchronous operation is completed
1780 function TMHComPort
.IsAsyncCompleted(AsyncPtr
: PAsync
): Boolean;
1785 if AsyncPtr = nil then
1786 raise EComPort.CreateNoWinCode(CError_InvalidAsync);
1789 Result
:= GetOverlappedResult(FHandle
, AsyncPtr
^.Overlapped
, BytesTrans
, False);
1792 if GetLastError <> ERROR_IO_PENDING then
1793 raise EComPort.Create(CError_AsyncCheck, GetLastError);
1797 // waits for event to occur on serial port
1798 procedure TMHComPort
.WaitForEvent(var Events2
: TComEvents
; Timeout
: Integer);
1800 Overlapped
: TOverlapped
;
1806 if FThreadCreated then
1807 raise EComPort.CreateNoWinCode(CError_ThreadCreated);
1809 FillChar(Overlapped
, SizeOf(TOverlapped
), 0);
1810 Overlapped
.hEvent
:= CreateEvent(nil, True, False, nil);
1812 SetCommMask(FHandle
, EventsToInt(Events2
));
1813 Success
:= WaitCommEvent(FHandle
, Mask
, @Overlapped
);
1814 if (Success
) or (GetLastError
= ERROR_IO_PENDING
) then
1816 Signaled
:= WaitForSingleObject(Overlapped
.hEvent
, Timeout
);
1817 if Signaled
= WAIT_TIMEOUT
then
1818 SetCommMask(FHandle
, 0);
1819 Success
:= (Signaled
= WAIT_OBJECT_0
) or (Signaled
= WAIT_TIMEOUT
);
1823 raise EComPort.Create(CError_WaitFailed, GetLastError);
1825 Events2
:= IntToEvents(Mask
);
1827 CloseHandle(Overlapped
.hEvent
);
1831 // transmit char ahead of any pending data in ouput buffer
1832 procedure TMHComPort
.TransmitChar(Ch
: Char);
1835 if not TransmitCommChar(FHandle, Ch) then
1836 raise EComPort.Create(CError_TransmitFailed, GetLastError);
1840 // some conversion routines
1841 function BoolToStr(const Value
: Boolean): string;
1849 function StrToBool(const Value
: string): Boolean;
1851 if UpperCase(Value
) = 'YES' then
1857 function DTRToStr(DTRFlowControl
: TDTRFlowControl
): string;
1859 DTRStrings
: array[TDTRFlowControl
] of string = ('Disable', 'Enable',
1862 Result
:= DTRStrings
[DTRFlowControl
];
1865 function RTSToStr(RTSFlowControl
: TRTSFlowControl
): string;
1867 RTSStrings
: array[TRTSFlowControl
] of string = ('Disable', 'Enable',
1868 'Handshake', 'Toggle');
1870 Result
:= RTSStrings
[RTSFlowControl
];
1873 function StrToRTS(Str
: string): TRTSFlowControl
;
1877 I
:= Low(TRTSFlowControl
);
1878 while (I
<= High(TRTSFlowControl
)) do
1880 if UpperCase(Str
) = UpperCase(RTSToStr(I
)) then
1884 if I
> High(TRTSFlowControl
) then
1885 Result
:= rtsDisable
1890 function StrToDTR(Str
: string): TDTRFlowControl
;
1894 I
:= Low(TDTRFlowControl
);
1895 while (I
<= High(TDTRFlowControl
)) do
1897 if UpperCase(Str
) = UpperCase(DTRToStr(I
)) then
1901 if I
> High(TDTRFlowControl
) then
1902 Result
:= dtrDisable
1907 function StrToChar(Str
: string): Char;
1911 if Length(Str
) > 0 then
1913 if (Str
[1] = '#') and (Length(Str
) > 1) then
1916 A
:= Str2Int(Copy(Str
, 2, Length(Str
) - 1));
1920 Result
:= Chr(Byte(A
));
1929 function CharToStr(Ch
: Char): string;
1931 if Ch
in [#33..#127] then
1934 Result
:= '#' + Int2Str(Ord(Ch
));
1938 // default actions on port events
1940 procedure TMHComPort
.DoBeforeClose
;
1942 if Assigned(FOnBeforeClose
) then
1943 FOnBeforeClose(@Self
);
1946 procedure TMHComPort
.DoBeforeOpen
;
1948 if Assigned(FOnBeforeOpen
) then
1949 FOnBeforeOpen(@Self
);
1952 procedure TMHComPort
.DoAfterOpen
;
1954 if Assigned(FOnAfterOpen
) then
1955 FOnAfterOpen(@Self
);
1958 procedure TMHComPort
.DoAfterClose
;
1960 if Assigned(FOnAfterClose
) then
1961 FOnAfterClose(@Self
);
1964 procedure TMHComPort
.DoRxChar(Count
: Integer);
1966 if Assigned(FOnRxChar
) then
1967 FOnRxChar(PObj(@Self
), Count
);
1970 procedure TMHComPort
.DoRxBuf(Buf
:array of Byte; Count
: Integer);
1972 if Assigned(FOnRxBuf
) then
1973 FOnRxBuf(PObj(@Self
), Buf
, Count
);
1976 procedure TMHComPort
.DoBreak
;
1978 if Assigned(FOnBreak
) then
1982 procedure TMHComPort
.DoTxEmpty
;
1984 if Assigned(FOnTxEmpty
)
1985 then FOnTxEmpty(@Self
);
1988 procedure TMHComPort
.DoRing
;
1990 if Assigned(FOnRing
) then
1994 procedure TMHComPort
.DoCTSChange(OnOff
: Boolean);
1996 if Assigned(FOnCTSChange
) then
1997 FOnCTSChange(PObj(@Self
), OnOff
);
2000 procedure TMHComPort
.DoDSRChange(OnOff
: Boolean);
2002 if Assigned(FOnDSRChange
) then
2003 FOnDSRChange(PObj(@Self
), OnOff
);
2006 procedure TMHComPort
.DoRLSDChange(OnOff
: Boolean);
2008 if Assigned(FOnRLSDChange
) then
2009 FOnRLSDChange(PObj(@Self
), OnOff
);
2012 procedure TMHComPort
.DoError(Errors
: TComErrors
);
2014 if Assigned(FOnError
) then
2015 FOnError(PObj(@Self
), Errors
);
2018 procedure TMHComPort
.DoRxFlag
;
2020 if Assigned(FOnRxFlag
) then
2024 procedure TMHComPort
.DoRx80Full
;
2026 if Assigned(FOnRx80Full
) then
2030 // set signals to false on close, and to proper value on open,
2031 // because OnXChange events are not called automatically
2032 procedure TMHComPort
.CheckSignals(Open2
: Boolean);
2041 { SendSignals(lsCTS, False);
2042 SendSignals(lsDSR, False);
2043 SendSignals(lsRLSD, False);}
2046 DoRLSDChange(False);
2050 // called in response to EV_X events, except CallXClose, CallXOpen
2052 procedure TMHComPort
.CallAfterClose
;
2057 procedure TMHComPort
.CallAfterOpen
;
2060 // check all com signals, since OnXChange events are not called on open
2064 procedure TMHComPort
.CallBeforeClose
;
2067 // shutdown com signals manually
2068 CheckSignals(False);
2071 procedure TMHComPort
.CallBeforeOpen
;
2076 procedure TMHComPort
.CallBreak
;
2081 procedure TMHComPort
.CallCTSChange
;
2085 OnOff
:= csCTS
in Signals
;
2086 // check for linked components
2087 // SendSignals(lsCTS, OnOff);
2088 DoCTSChange(csCTS
in Signals
);
2091 procedure TMHComPort
.CallDSRChange
;
2095 OnOff
:= csDSR
in Signals
;
2096 // check for linked components
2097 // SendSignals(lsDSR, OnOff);
2098 DoDSRChange(csDSR
in Signals
);
2101 procedure TMHComPort
.CallRLSDChange
;
2105 OnOff
:= csRLSD
in Signals
;
2106 // check for linked components
2107 // SendSignals(lsRLSD, OnOff);
2108 DoRLSDChange(csRLSD
in Signals
);
2111 procedure TMHComPort
.CallError
;
2113 // DoError(LastErrors);
2116 procedure TMHComPort
.CallRing
;
2121 procedure TMHComPort
.CallRx80Full
;
2126 procedure TMHComPort
.CallRxChar
;
2130 // check if any component is linked, to OnRxChar event
2131 procedure CheckLinks
;
2134 ReadFromBuffer
: Boolean;
2137 if (Count
> 0){ and (FLinks.Count > 0)} then
2139 ReadFromBuffer
:= False;
2145 // link to OnRxChar event found
2146 if not ReadFromBuffer
then
2148 // TMHComPort must read from comport, so OnRxChar event is
2151 ReadFromBuffer
:= True;
2153 // instead, call OnRxBuf event
2154 DoRxBuf(Byte(P
^), Count
);
2161 if ReadFromBuffer
then
2164 // data is already out of buffer, prevent from OnRxChar event to occur
2172 Count
:= InputCount
;
2178 procedure TMHComPort
.CallRxFlag
;
2183 procedure TMHComPort
.CallTxEmpty
;
2185 // SendSignals(lsTx, False);
2189 // send signals to linked components
2191 // set connected property, same as Open/Close methods
2192 procedure TMHComPort
.SetConnected(const Value
: Boolean);
2194 if Value
<> FConnected
then
2200 FConnected
:= Value
;
2204 procedure TMHComPort
.SetBaudRate(const Value
: TBaudRate
);
2206 if Value
<> FBaudRate
then
2209 // if possible, apply settings
2214 // set custom baud rate
2215 procedure TMHComPort
.SetCustomBaudRate(const Value
: Integer);
2217 if Value
<> FCustomBaudRate
then
2219 FCustomBaudRate
:= Value
;
2225 procedure TMHComPort
.SetDataBits(const Value
: TDataBits
);
2227 if Value
<> FDataBits
then
2234 // set discard null charachters
2235 procedure TMHComPort
.SetDiscardNull(const Value
: Boolean);
2237 if Value
<> FDiscardNull
then
2239 FDiscardNull
:= Value
;
2244 // set event charachters
2245 procedure TMHComPort
.SetEventChar(const Value
: Char);
2247 if Value
<> FEventChar
then
2249 FEventChar
:= Value
;
2254 // translated numeric string to port string
2255 function ComString(Str
: string): TPort
;
2259 if UpperCase(Copy(Str
, 1, 3)) = 'COM' then
2260 Str
:= Copy(Str
, 4, Length(Str
) - 3);
2262 Num
:= Str2Int(Str
);
2266 if (Num
< 1) or (Num
> 16) then
2268 Result
:= Format('COM%d', [Num
]);
2272 procedure TMHComPort
.SetPort(const Value
: TPort
);
2276 Str
:= ComString(Value
);
2277 if Str
<> FPort
then
2280 if (FConnected
) then
2289 procedure TMHComPort
.SetStopBits(const Value
: TStopBits
);
2291 if Value
<> FStopBits
then
2298 // set event synchronization method
2299 procedure TMHComPort
.SetSyncMethod(const Value
: TSyncMethod
);
2301 if Value
<> FSyncMethod
then
2305 // raise EComPort.CreateNoWinCode(CError_SyncMeth)
2307 FSyncMethod
:= Value
;
2311 // returns true if RxChar is triggered when data arrives input buffer
2312 function TMHComPort
.GetTriggersOnRxChar
: Boolean;
2318 procedure TMHComPort
.SetFlowControl(const Value
: PMHComFlowControl
);
2320 FFlowControl
.AssignTo(Value
);
2325 procedure TMHComPort
.SetParity(const Value
: PMHComParity
);
2327 FParity
.AssignTo(Value
);
2332 procedure TMHComPort
.SetTimeouts(const Value
: PMHComTimeouts
);
2334 FTimeouts
.AssignTo(Value
);
2339 procedure TMHComPort
.SetBuffer(const Value
: PMHComBuffer
);
2341 FBuffer
.AssignTo(Value
);
2345 function BaudRateToStr(BaudRate
: TBaudRate
): string;
2347 BaudRateStrings
: array[TBaudRate
] of string = ('Custom', '110', '300', '600',
2348 '1200', '2400', '4800', '9600', '14400', '19200', '38400', '56000', '57600',
2349 '115200', '128000', '256000');
2351 Result
:= BaudRateStrings
[BaudRate
];
2354 // string to baud rate
2355 function StrToBaudRate(Str
: string): TBaudRate
;
2359 I
:= Low(TBaudRate
);
2360 while (I
<= High(TBaudRate
)) do
2362 if UpperCase(Str
) = UpperCase(BaudRateToStr(TBaudRate(I
))) then
2366 if I
> High(TBaudRate
) then
2372 function FlowControlToStr(FlowControl
: TFlowControl
): string;
2374 FlowControlStrings
: array[TFlowControl
] of string = ('Hardware',
2375 'Software', 'None', 'Custom');
2377 Result
:= FlowControlStrings
[FlowControl
];
2380 function StopBitsToStr(StopBits
: TStopBits
): string;
2382 StopBitsStrings
: array[TStopBits
] of string = ('1', '1.5', '2');
2384 Result
:= StopBitsStrings
[StopBits
];
2387 // string to stop bits
2388 function StrToStopBits(Str
: string): TStopBits
;
2392 I
:= Low(TStopBits
);
2393 while (I
<= High(TStopBits
)) do
2395 if UpperCase(Str
) = UpperCase(StopBitsToStr(TStopBits(I
))) then
2399 if I
> High(TStopBits
) then
2400 Result
:= sbOneStopBit
2405 function DataBitsToStr(DataBits
: TDataBits
): string;
2407 DataBitsStrings
: array[TDataBits
] of string = ('5', '6', '7', '8');
2409 Result
:= DataBitsStrings
[DataBits
];
2412 // string to data bits
2413 function StrToDataBits(Str
: string): TDataBits
;
2417 I
:= Low(TDataBits
);
2418 while (I
<= High(TDataBits
)) do
2420 if UpperCase(Str
) = UpperCase(DataBitsToStr(I
)) then
2424 if I
> High(TDataBits
) then
2429 function ParityToStr(Parity
: TParityBits
): string;
2431 ParityBitsStrings
: array[TParityBits
] of string = ('None', 'Odd', 'Even',
2434 Result
:= ParityBitsStrings
[Parity
];
2438 function StrToParity(Str
: string): TParityBits
;
2442 I
:= Low(TParityBits
);
2443 while (I
<= High(TParityBits
)) do
2445 if UpperCase(Str
) = UpperCase(ParityToStr(I
)) then
2449 if I
> High(TParityBits
) then
2456 // string to flow control
2457 function StrToFlowControl(Str
: string): TFlowControl
;
2461 I
:= Low(TFlowControl
);
2462 while (I
<= High(TFlowControl
)) do
2464 if UpperCase(Str
) = UpperCase(FlowControlToStr(I
)) then
2468 if I
> High(TFlowControl
) then