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-2017, 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 GNU/Linux implementation of this package
34 with Ada
.Streams
; use Ada
.Streams
;
36 with Ada
.Unchecked_Deallocation
;
38 with System
; use System
;
39 with System
.Communication
; use System
.Communication
;
40 with System
.CRTL
; use System
.CRTL
;
41 with System
.OS_Constants
;
43 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
45 package body GNAT
.Serial_Communications
is
47 package OSC
renames System
.OS_Constants
;
49 use type Interfaces
.C
.unsigned
;
51 type Port_Data
is new int
;
53 subtype unsigned
is Interfaces
.C
.unsigned
;
54 subtype char
is Interfaces
.C
.char
;
55 subtype unsigned_char
is Interfaces
.C
.unsigned_char
;
57 function fcntl
(fd
: int
; cmd
: int
; value
: int
) return int
;
58 pragma Import
(C
, fcntl
, "fcntl");
60 C_Data_Rate
: constant array (Data_Rate
) of unsigned
:=
73 B115200
=> OSC
.B115200
);
75 C_Bits
: constant array (Data_Bits
) of unsigned
:=
76 (CS7
=> OSC
.CS7
, CS8
=> OSC
.CS8
);
78 C_Stop_Bits
: constant array (Stop_Bits_Number
) of unsigned
:=
79 (One
=> 0, Two
=> OSC
.CSTOPB
);
81 C_Parity
: constant array (Parity_Check
) of unsigned
:=
83 Odd
=> OSC
.PARENB
or OSC
.PARODD
,
86 procedure Raise_Error
(Message
: String; Error
: Integer := Errno
);
87 pragma No_Return
(Raise_Error
);
93 function Name
(Number
: Positive) return Port_Name
is
94 N
: constant Natural := Number
- 1;
95 N_Img
: constant String := Natural'Image (N
);
97 return Port_Name
("/dev/ttyS" & N_Img
(N_Img
'First + 1 .. N_Img
'Last));
105 (Port
: out Serial_Port
;
110 C_Name
: constant String := String (Name
) & ASCII
.NUL
;
114 if Port
.H
= null then
115 Port
.H
:= new Port_Data
;
118 Port
.H
.all := Port_Data
(open
119 (C_Name
(C_Name
'First)'Address, int
(O_RDWR
+ O_NOCTTY
+ O_NDELAY
)));
121 if Port
.H
.all = -1 then
122 Raise_Error
("open: open failed");
125 -- By default we are in blocking mode
127 Res
:= fcntl
(int
(Port
.H
.all), F_SETFL
, 0);
130 Raise_Error
("open: fcntl failed");
138 procedure Raise_Error
(Message
: String; Error
: Integer := Errno
) is
140 raise Serial_Error
with Message
142 then " (" & Errno_Message
(Err
=> Error
) & ')'
150 overriding
procedure Read
151 (Port
: in out Serial_Port
;
152 Buffer
: out Stream_Element_Array
;
153 Last
: out Stream_Element_Offset
)
155 Len
: constant size_t
:= Buffer
'Length;
159 if Port
.H
= null then
160 Raise_Error
("read: port not opened", 0);
163 Res
:= read
(Integer (Port
.H
.all), Buffer
'Address, Len
);
166 Raise_Error
("read failed");
169 Last
:= Last_Index
(Buffer
'First, size_t
(Res
));
178 Rate
: Data_Rate
:= B9600
;
179 Bits
: Data_Bits
:= CS8
;
180 Stop_Bits
: Stop_Bits_Number
:= One
;
181 Parity
: Parity_Check
:= None
;
182 Block
: Boolean := True;
183 Local
: Boolean := True;
184 Flow
: Flow_Control
:= None
;
185 Timeout
: Duration := 10.0)
189 type termios
is record
194 c_line
: unsigned_char
;
195 c_cc
: Interfaces
.C
.char_array
(0 .. 31);
199 pragma Convention
(C
, termios
);
201 function tcgetattr
(fd
: int
; termios_p
: Address
) return int
;
202 pragma Import
(C
, tcgetattr
, "tcgetattr");
205 (fd
: int
; action
: int
; termios_p
: Address
) return int
;
206 pragma Import
(C
, tcsetattr
, "tcsetattr");
208 function tcflush
(fd
: int
; queue_selector
: int
) return int
;
209 pragma Import
(C
, tcflush
, "tcflush");
214 pragma Warnings
(Off
, Res
);
215 -- Warnings off, since we don't always test the result
218 if Port
.H
= null then
219 Raise_Error
("set: port not opened", 0);
222 -- Get current port settings
224 Res
:= tcgetattr
(int
(Port
.H
.all), Current
'Address);
226 -- Change settings now
228 Current
.c_cflag
:= C_Data_Rate
(Rate
)
230 or C_Stop_Bits
(Stop_Bits
)
233 Current
.c_iflag
:= 0;
234 Current
.c_lflag
:= 0;
235 Current
.c_oflag
:= 0;
238 Current
.c_cflag
:= Current
.c_cflag
or CLOCAL
;
246 Current
.c_cflag
:= Current
.c_cflag
or CRTSCTS
;
249 Current
.c_iflag
:= Current
.c_iflag
or IXON
;
252 Current
.c_ispeed
:= Data_Rate_Value
(Rate
);
253 Current
.c_ospeed
:= Data_Rate_Value
(Rate
);
254 Current
.c_cc
(VMIN
) := char
'Val (0);
255 Current
.c_cc
(VTIME
) := char
'Val (Natural (Timeout
* 10));
259 Res
:= tcflush
(int
(Port
.H
.all), TCIFLUSH
);
260 Res
:= tcsetattr
(int
(Port
.H
.all), TCSANOW
, Current
'Address);
264 Res
:= fcntl
(int
(Port
.H
.all), F_SETFL
, (if Block
then 0 else FNDELAY
));
267 Raise_Error
("set: fcntl failed");
275 overriding
procedure Write
276 (Port
: in out Serial_Port
;
277 Buffer
: Stream_Element_Array
)
279 Len
: constant size_t
:= Buffer
'Length;
283 if Port
.H
= null then
284 Raise_Error
("write: port not opened", 0);
287 Res
:= write
(int
(Port
.H
.all), Buffer
'Address, Len
);
290 Raise_Error
("write failed");
293 pragma Assert
(size_t
(Res
) = Len
);
300 procedure Close
(Port
: in out Serial_Port
) is
301 procedure Unchecked_Free
is
302 new Unchecked_Deallocation
(Port_Data
, Port_Data_Access
);
305 pragma Unreferenced
(Res
);
308 if Port
.H
/= null then
309 Res
:= close
(int
(Port
.H
.all));
310 Unchecked_Free
(Port
.H
);
314 end GNAT
.Serial_Communications
;