1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . S E R I A L _ C O M M U N I C A T I O N S --
9 -- Copyright (C) 2007-2009, AdaCore --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 -- This is the Windows implementation of this package
36 with Ada
.Unchecked_Deallocation
; use Ada
;
37 with Ada
.Streams
; use Ada
.Streams
;
39 with System
; use System
;
40 with System
.Communication
; use System
.Communication
;
41 with System
.CRTL
; use System
.CRTL
;
42 with System
.Win32
; use System
.Win32
;
43 with System
.Win32
.Ext
; use System
.Win32
.Ext
;
45 package body GNAT
.Serial_Communications
is
49 type Port_Data
is new HANDLE
;
51 C_Bits
: constant array (Data_Bits
) of Interfaces
.C
.unsigned
:= (8, 7);
52 C_Parity
: constant array (Parity_Check
) of Interfaces
.C
.unsigned
:=
53 (None
=> NOPARITY
, Odd
=> ODDPARITY
, Even
=> EVENPARITY
);
54 C_Stop_Bits
: constant array (Stop_Bits_Number
) of Interfaces
.C
.unsigned
:=
55 (One
=> ONESTOPBIT
, Two
=> TWOSTOPBITS
);
61 procedure Raise_Error
(Message
: String; Error
: DWORD
:= GetLastError
);
62 pragma No_Return
(Raise_Error
);
68 procedure Close
(Port
: in out Serial_Port
) is
69 procedure Unchecked_Free
is
70 new Unchecked_Deallocation
(Port_Data
, Port_Data_Access
);
75 if Port
.H
/= null then
76 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
77 Unchecked_Free
(Port
.H
);
79 if Success
= Win32
.FALSE then
80 Raise_Error
("error closing the port");
89 function Name
(Number
: Positive) return Port_Name
is
90 N_Img
: constant String := Positive'Image (Number
);
92 return Port_Name
("COM" & N_Img
(N_Img
'First + 1 .. N_Img
'Last) & ':');
100 (Port
: out Serial_Port
;
103 C_Name
: constant String := String (Name
) & ASCII
.NUL
;
105 pragma Unreferenced
(Success
);
108 if Port
.H
= null then
109 Port
.H
:= new Port_Data
;
111 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
114 Port
.H
.all := CreateFileA
115 (lpFileName
=> C_Name
(C_Name
'First)'Address,
116 dwDesiredAccess
=> GENERIC_READ
or GENERIC_WRITE
,
118 lpSecurityAttributes
=> null,
119 dwCreationDisposition
=> OPEN_EXISTING
,
120 dwFlagsAndAttributes
=> 0,
123 if Port
.H
.all = 0 then
124 Raise_Error
("cannot open com port");
132 procedure Raise_Error
(Message
: String; Error
: DWORD
:= GetLastError
) is
134 raise Serial_Error
with Message
& " (" & DWORD
'Image (Error
) & ')';
141 overriding
procedure Read
142 (Port
: in out Serial_Port
;
143 Buffer
: out Stream_Element_Array
;
144 Last
: out Stream_Element_Offset
)
147 Read_Last
: aliased DWORD
;
150 if Port
.H
= null then
151 Raise_Error
("read: port not opened", 0);
156 (hFile
=> HANDLE
(Port
.H
.all),
157 lpBuffer
=> Buffer
(Buffer
'First)'Address,
158 nNumberOfBytesToRead
=> DWORD
(Buffer
'Length),
159 lpNumberOfBytesRead
=> Read_Last
'Access,
160 lpOverlapped
=> null);
162 if Success
= Win32
.FALSE then
163 Raise_Error
("read error");
166 Last
:= Last_Index
(Buffer
'First, size_t
(Read_Last
));
175 Rate
: Data_Rate
:= B9600
;
176 Bits
: Data_Bits
:= CS8
;
177 Stop_Bits
: Stop_Bits_Number
:= One
;
178 Parity
: Parity_Check
:= None
;
179 Block
: Boolean := True;
180 Timeout
: Duration := 10.0)
183 Com_Time_Out
: aliased COMMTIMEOUTS
;
184 Com_Settings
: aliased DCB
;
187 if Port
.H
= null then
188 Raise_Error
("set: port not opened", 0);
191 Success
:= GetCommState
(HANDLE
(Port
.H
.all), Com_Settings
'Access);
193 if Success
= Win32
.FALSE then
194 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
196 Raise_Error
("set: cannot get comm state");
199 Com_Settings
.BaudRate
:= DWORD
(Data_Rate_Value
(Rate
));
200 Com_Settings
.fParity
:= 1;
201 Com_Settings
.fBinary
:= Bits1
(System
.Win32
.TRUE);
202 Com_Settings
.fOutxCtsFlow
:= 0;
203 Com_Settings
.fOutxDsrFlow
:= 0;
204 Com_Settings
.fDsrSensitivity
:= 0;
205 Com_Settings
.fDtrControl
:= DTR_CONTROL_DISABLE
;
206 Com_Settings
.fOutX
:= 0;
207 Com_Settings
.fInX
:= 0;
208 Com_Settings
.fRtsControl
:= RTS_CONTROL_DISABLE
;
209 Com_Settings
.fAbortOnError
:= 0;
210 Com_Settings
.ByteSize
:= BYTE
(C_Bits
(Bits
));
211 Com_Settings
.Parity
:= BYTE
(C_Parity
(Parity
));
212 Com_Settings
.StopBits
:= BYTE
(C_Stop_Bits
(Stop_Bits
));
214 Success
:= SetCommState
(HANDLE
(Port
.H
.all), Com_Settings
'Access);
216 if Success
= Win32
.FALSE then
217 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
219 Raise_Error
("cannot set comm state");
222 -- Set the timeout status
225 Com_Time_Out
:= (others => 0);
228 (ReadTotalTimeoutConstant
=> DWORD
(1000 * Timeout
),
234 (hFile
=> HANDLE
(Port
.H
.all),
235 lpCommTimeouts
=> Com_Time_Out
'Access);
237 if Success
= Win32
.FALSE then
238 Raise_Error
("cannot set the timeout");
246 overriding
procedure Write
247 (Port
: in out Serial_Port
;
248 Buffer
: Stream_Element_Array
)
251 Temp_Last
: aliased DWORD
;
254 if Port
.H
= null then
255 Raise_Error
("write: port not opened", 0);
260 (hFile
=> HANDLE
(Port
.H
.all),
261 lpBuffer
=> Buffer
'Address,
262 nNumberOfBytesToWrite
=> DWORD
(Buffer
'Length),
263 lpNumberOfBytesWritten
=> Temp_Last
'Access,
264 lpOverlapped
=> null);
266 if Success
= Win32
.FALSE
267 or else Stream_Element_Offset
(Temp_Last
) /= Buffer
'Length
269 Raise_Error
("failed to write data");
273 end GNAT
.Serial_Communications
;