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-2016, 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 3, 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. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 -- This is the Windows implementation of this package
34 with Ada
.Streams
; use Ada
.Streams
;
35 with Ada
.Unchecked_Deallocation
; use Ada
;
37 with System
; use System
;
38 with System
.Communication
; use System
.Communication
;
39 with System
.CRTL
; use System
.CRTL
;
40 with System
.OS_Constants
;
41 with System
.Win32
; use System
.Win32
;
42 with System
.Win32
.Ext
; use System
.Win32
.Ext
;
46 package body GNAT
.Serial_Communications
is
48 package OSC
renames System
.OS_Constants
;
52 type Port_Data
is new HANDLE
;
54 C_Bits
: constant array (Data_Bits
) of Interfaces
.C
.unsigned
:= (8, 7);
55 C_Parity
: constant array (Parity_Check
) of Interfaces
.C
.unsigned
:=
56 (None
=> NOPARITY
, Odd
=> ODDPARITY
, Even
=> EVENPARITY
);
57 C_Stop_Bits
: constant array (Stop_Bits_Number
) of Interfaces
.C
.unsigned
:=
58 (One
=> ONESTOPBIT
, Two
=> TWOSTOPBITS
);
64 procedure Raise_Error
(Message
: String; Error
: DWORD
:= GetLastError
);
65 pragma No_Return
(Raise_Error
);
71 procedure Close
(Port
: in out Serial_Port
) is
72 procedure Unchecked_Free
is
73 new Unchecked_Deallocation
(Port_Data
, Port_Data_Access
);
78 if Port
.H
/= null then
79 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
80 Unchecked_Free
(Port
.H
);
82 if Success
= Win32
.FALSE then
83 Raise_Error
("error closing the port");
92 function Name
(Number
: Positive) return Port_Name
is
93 N_Img
: constant String := Positive'Image (Number
);
97 Port_Name
("\\.\COM" & N_Img
(N_Img
'First + 1 .. N_Img
'Last));
100 Port_Name
("COM" & N_Img
(N_Img
'First + 1 .. N_Img
'Last) & ':');
109 (Port
: out Serial_Port
;
112 C_Name
: constant String := String (Name
) & ASCII
.NUL
;
114 pragma Unreferenced
(Success
);
117 if Port
.H
= null then
118 Port
.H
:= new Port_Data
;
120 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
123 Port
.H
.all := CreateFileA
124 (lpFileName
=> C_Name
(C_Name
'First)'Address,
125 dwDesiredAccess
=> GENERIC_READ
or GENERIC_WRITE
,
127 lpSecurityAttributes
=> null,
128 dwCreationDisposition
=> OPEN_EXISTING
,
129 dwFlagsAndAttributes
=> 0,
132 if Port
.H
.all = Port_Data
(INVALID_HANDLE_VALUE
) then
133 Raise_Error
("cannot open com port");
141 procedure Raise_Error
(Message
: String; Error
: DWORD
:= GetLastError
) is
143 raise Serial_Error
with Message
145 then " (" & GNAT
.OS_Lib
.Errno_Message
(Err
=> Integer (Error
)) & ')'
153 overriding
procedure Read
154 (Port
: in out Serial_Port
;
155 Buffer
: out Stream_Element_Array
;
156 Last
: out Stream_Element_Offset
)
159 Read_Last
: aliased DWORD
;
162 if Port
.H
= null then
163 Raise_Error
("read: port not opened", 0);
168 (hFile
=> HANDLE
(Port
.H
.all),
169 lpBuffer
=> Buffer
(Buffer
'First)'Address,
170 nNumberOfBytesToRead
=> DWORD
(Buffer
'Length),
171 lpNumberOfBytesRead
=> Read_Last
'Access,
172 lpOverlapped
=> null);
174 if Success
= Win32
.FALSE then
175 Raise_Error
("read error");
178 Last
:= Last_Index
(Buffer
'First, size_t
(Read_Last
));
187 Rate
: Data_Rate
:= B9600
;
188 Bits
: Data_Bits
:= CS8
;
189 Stop_Bits
: Stop_Bits_Number
:= One
;
190 Parity
: Parity_Check
:= None
;
191 Block
: Boolean := True;
192 Local
: Boolean := True;
193 Flow
: Flow_Control
:= None
;
194 Timeout
: Duration := 10.0)
196 pragma Unreferenced
(Local
);
199 Com_Time_Out
: aliased COMMTIMEOUTS
;
200 Com_Settings
: aliased DCB
;
203 if Port
.H
= null then
204 Raise_Error
("set: port not opened", 0);
207 Success
:= GetCommState
(HANDLE
(Port
.H
.all), Com_Settings
'Access);
209 if Success
= Win32
.FALSE then
210 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
212 Raise_Error
("set: cannot get comm state");
215 Com_Settings
.BaudRate
:= DWORD
(Data_Rate_Value
(Rate
));
216 Com_Settings
.fParity
:= 1;
217 Com_Settings
.fBinary
:= Bits1
(System
.Win32
.TRUE);
218 Com_Settings
.fOutxDsrFlow
:= 0;
219 Com_Settings
.fDsrSensitivity
:= 0;
220 Com_Settings
.fDtrControl
:= OSC
.DTR_CONTROL_ENABLE
;
221 Com_Settings
.fInX
:= 0;
222 Com_Settings
.fRtsControl
:= OSC
.RTS_CONTROL_ENABLE
;
226 Com_Settings
.fOutX
:= 0;
227 Com_Settings
.fOutxCtsFlow
:= 0;
230 Com_Settings
.fOutX
:= 0;
231 Com_Settings
.fOutxCtsFlow
:= 1;
234 Com_Settings
.fOutX
:= 1;
235 Com_Settings
.fOutxCtsFlow
:= 0;
238 Com_Settings
.fAbortOnError
:= 0;
239 Com_Settings
.ByteSize
:= BYTE
(C_Bits
(Bits
));
240 Com_Settings
.Parity
:= BYTE
(C_Parity
(Parity
));
241 Com_Settings
.StopBits
:= BYTE
(C_Stop_Bits
(Stop_Bits
));
243 Success
:= SetCommState
(HANDLE
(Port
.H
.all), Com_Settings
'Access);
245 if Success
= Win32
.FALSE then
246 Success
:= CloseHandle
(HANDLE
(Port
.H
.all));
248 Raise_Error
("cannot set comm state");
251 -- Set the timeout status, to honor our spec with respect to read
252 -- timeouts. Always disconnect write timeouts.
254 -- Blocking reads - no timeout at all
257 Com_Time_Out
:= (others => 0);
259 -- Non-blocking reads and null timeout - immediate return with what we
260 -- have - set ReadIntervalTimeout to MAXDWORD.
262 elsif Timeout
= 0.0 then
264 (ReadIntervalTimeout
=> DWORD
'Last,
267 -- Non-blocking reads with timeout - set total read timeout accordingly
271 (ReadTotalTimeoutConstant
=> DWORD
(1000 * Timeout
),
277 (hFile
=> HANDLE
(Port
.H
.all),
278 lpCommTimeouts
=> Com_Time_Out
'Access);
280 if Success
= Win32
.FALSE then
281 Raise_Error
("cannot set the timeout");
289 overriding
procedure Write
290 (Port
: in out Serial_Port
;
291 Buffer
: Stream_Element_Array
)
294 Temp_Last
: aliased DWORD
;
297 if Port
.H
= null then
298 Raise_Error
("write: port not opened", 0);
303 (hFile
=> HANDLE
(Port
.H
.all),
304 lpBuffer
=> Buffer
'Address,
305 nNumberOfBytesToWrite
=> DWORD
(Buffer
'Length),
306 lpNumberOfBytesWritten
=> Temp_Last
'Access,
307 lpOverlapped
=> null);
309 if Success
= Win32
.FALSE
310 or else Stream_Element_Offset
(Temp_Last
) /= Buffer
'Length
312 Raise_Error
("failed to write data");
316 end GNAT
.Serial_Communications
;